PostgreSQL ILIKE on concatinated columns not working - postgresql

I'm trying to query using ILIKE on a user's name in PostgreSQL. There are columns for first_name and last_name, and I'd like the search term to match against the two concatenated, with a space between, so that a user may search for either, or a full name using one input. "John" "Doe" or "John Doe".
This always returns no results:
SELECT * FROM user_profiles WHERE first_name || ' ' || last_name ILIKE '%ryan%'
This always returns the one result I am expecting:
SELECT * FROM user_profiles WHERE first_name ILIKE '%ryan%'
Based on everything I've read, the first query should work as I am expecting, but it doesn't. No results and no errors. What am I missing here?

The first query would return no results if last_name were NULL (and similarly if first_name were NULL).
So, try this instead:
WHERE first_name || ' ' || COALESCE(last_name, '') ILIKE '%ryan%'
or:
WHERE CONCAT_WS(' ', first_name, last_name) ILIKE '%ryan%'
The concat_ws() function ignores arguments that are not NULL (except for the first argument).

Related

Postgres query for IN(NULL, 'test') does not work

When I wan't to match a column that has some certain string values or is null, I assumed I can do something like this:
SELECT * FROM table_name WHERE column_name IN (NULL, 'someTest', 'someOtherTest');
But it does not return the columns where column_name set set to NULL. Is this anywhere documented? Why does it not work?
You can't compare NULL values using = (which is what IN is doing).
Quote from the manual
Ordinary comparison operators yield null (signifying “unknown”), not true or false, when either input is null. For example, 7 = NULL yields null, as does 7 <> NULL
You need to add a check for NULL explicitly:
SELECT *
FROM table_name
WHERE (column_name IN ('someTest', 'someOtherTest') OR column_name IS NULL);
NULL and empty string (i.e ' ') both are considered different in Postgres, unlike Oracle.
The query can be modified as:
SELECT *
FROM table_name
WHERE (column_name IN ('someTest', 'someOtherTest', '', ' ') OR
column_name IS NULL);

Postgres: how to use LIKE on every word of user input, AND-ing the results

In postgresql (9.6), given a variable length user input of the type 'alice chaplin' or 'alice' or 'alice chaplin meyer' but also 'lic chapl', I would like to search for records that contain 'alice' in column firstname OR column lastname (AND contain 'chaplin' in firstname OR lastname (AND contain 'meyer' in firstname OR lastname)), etc.
I had decided to use ILIKE %searchterm% for the matching, so the query would presumably be along the lines of:
... where
((lastname ILIKE '%' || SEARCHTERM1 || '%') OR (firstname ILIKE '%' || SEARCHTERM1 || '%'))
AND ((lastname ILIKE '%' || SEARCHTERM2 || '%') OR (firstname ILIKE '%' || SEARCHTERM2 || '%'))
AND etc.
After lots of attempts and searching, nothing comes up that resolves this... As a last resort I'll write a very procedural pgplsql function that loops over a split search string, intersecting the ILIKE results, but there has to be some more idiomatic SQL way of resolving such a run of the mill problem.
You can use string_to_array to convert an input string into an array of words. You can then use unnest to convert the array into a (virtual) table, and operate on the words to add '%' before and after. And finally, you can use the ALL comparison using ILIKE ALL (SELECT ...). This ALL will actually be AND-ing the results, as desired.
WITH q AS
(
SELECT 'Alice Chaplin Meyer'::text AS q
)
, words AS
(
SELECT
'%' || word || '%' AS wordish
FROM
q
JOIN LATERAL unnest(string_to_array(q, ' ')) AS a(word) ON true
)
SELECT
*
FROM
t
WHERE
concat_ws(' ', first_name, last_name) ILIKE ALL(SELECT wordish FROM words)
You can check it all at http://rextester.com/LNB38296
References:
string_to_array and unnest
Using ALL
NOTE: This can probably be simplified, but I've prefered a step-by-step approach.

ERROR: subquery must return only one column

I am trying to execute the following query:
INSERT
INTO rooms(
id,
name,
body,
parents,
tags,
createtime,
creator,
deletetime,
meta,
params,
terms,
updater,
updatetime,
counts,
identities)
SELECT *
FROM dblink ('dbname=oldsb',
'SELECT '
'(SELECT newid FROM id_map WHERE oldid = entities.id) AS id, '
'id AS name, '
'description AS body, '
'NULL AS parents, '
'NULL AS tags, '
'ROUND(EXTRACT(EPOCH FROM current_timestamp)*1000) AS createtime, '
'NULL AS creator, '
'ROUND(EXTRACT(EPOCH FROM deletetime)*1000) AS deletetime, '
'json_build_object(''picture'', picture) AS meta, '
'jsonb_object_agg(
(SELECT * '
'FROM jsonb_each(params) '
'AS fields (name, value) '
'WHERE name <> ''places'')) AS params, '
'terms AS terms, '
'NULL AS updater, '
'EXTRACT(EPOCH FROM lAStseentime)*1000 AS updatetime, '
'NULL AS counts, '
'NULL AS identities '
'FROM entities WHERE type=''room''')
AS t(
id uuid,
name text,
body text,
parents uuid[],
tags smallint[],
createtime bigint,
creator text,
deletetime bigint,
meta jsonb,
params jsonb,
terms tsvector,
updater text,
updatetime bigint,
counts jsonb,
identities text[]);
and I am getting the following error:
Executing Rooms migration query
ERROR: subquery must return only one column
CONTEXT: Error occurred on dblink connection named "unnamed": could not execute query.
table for updating identities in rooms.
I am not able to understand where I am going wrong with the query.
One of Yours subqueries returns multiple results. Probobly this one.
SELECT newid FROM id_map WHERE oldid = entities.id
Add LIMIT 1 to the end and try again. In fact You can add LIMIT 1 to every subquery and see if it helps.
Is it possible that jsonb_each(params) has more than one column?
jsonb_object_agg(
(SELECT * '
'FROM jsonb_each(params) '
'AS fields (name, value) '
'WHERE name <> ''places'')) AS params,
I don't know what jsonb_object_agg() does but I don't think it's designed to handle an input that is a table. Usually, aggregate functions combine one or more rows of results into a single value.
Yes it is. Check this documentation for json_each function. json_each AND jsonb_each work the same way.

Oracle Select Query

How can I perform a select operation on two fields and view them as a single field?
ex:
I have a customer table that holds the customers data, I want to select both last_name and first_name (two different fields) and want to view them like this, "last_name, first_name"
using the oracle command not using any language.
SELECT last_name || ', ' || first_name full_name
FROM tbl
Try this -
SELECT '"' || last_name || ',' || first_name || '"' from table

Convert multiple rows into one with comma as separator [duplicate]

This question already has answers here:
How to concatenate text from multiple rows into a single text string in SQL Server
(47 answers)
Closed 7 years ago.
If I issue SELECT username FROM Users I get this result:
username
--------
Paul
John
Mary
but what I really need is one row with all the values separated by comma, like this:
Paul, John, Mary
How do I do this?
select
distinct
stuff((
select ',' + u.username
from users u
where u.username = username
order by u.username
for xml path('')
),1,1,'') as userlist
from users
group by username
had a typo before, the above works
This should work for you. Tested all the way back to SQL 2000.
create table #user (username varchar(25))
insert into #user (username) values ('Paul')
insert into #user (username) values ('John')
insert into #user (username) values ('Mary')
declare #tmp varchar(250)
SET #tmp = ''
select #tmp = #tmp + username + ', ' from #user
select SUBSTRING(#tmp, 0, LEN(#tmp))
good review of several approaches:
http://blogs.msmvps.com/robfarley/2007/04/07/coalesce-is-not-the-answer-to-string-concatentation-in-t-sql/
Article copy -
Coalesce is not the answer to string concatentation in T-SQL I've seen many posts over the years about using the COALESCE function to get string concatenation working in T-SQL. This is one of the examples here (borrowed from Readifarian Marc Ridey).
DECLARE #categories varchar(200)
SET #categories = NULL
SELECT #categories = COALESCE(#categories + ',','') + Name
FROM Production.ProductCategory
SELECT #categories
This query can be quite effective, but care needs to be taken, and the use of COALESCE should be properly understood. COALESCE is the version of ISNULL which can take more than two parameters. It returns the first thing in the list of parameters which is not null. So really it has nothing to do with concatenation, and the following piece of code is exactly the same - without using COALESCE:
DECLARE #categories varchar(200)
SET #categories = ''
SELECT #categories = #categories + ',' + Name
FROM Production.ProductCategory
SELECT #categories
But the unordered nature of databases makes this unreliable. The whole reason why T-SQL doesn't (yet) have a concatenate function is that this is an aggregate for which the order of elements is important. Using this variable-assignment method of string concatenation, you may actually find that the answer that gets returned doesn't have all the values in it, particularly if you want the substrings put in a particular order. Consider the following, which on my machine only returns ',Accessories', when I wanted it to return ',Bikes,Clothing,Components,Accessories':
DECLARE #categories varchar(200)
SET #categories = NULL
SELECT #categories = COALESCE(#categories + ',','') + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
SELECT #categories
Far better is to use a method which does take order into consideration, and which has been included in SQL2005 specifically for the purpose of string concatenation - FOR XML PATH('')
SELECT ',' + Name
FROM Production.ProductCategory
ORDER BY LEN(Name)
FOR XML PATH('')
In the post I made recently comparing GROUP BY and DISTINCT when using subqueries, I demonstrated the use of FOR XML PATH(''). Have a look at this and you'll see how it works in a subquery. The 'STUFF' function is only there to remove the leading comma.
USE tempdb;
GO
CREATE TABLE t1 (id INT, NAME VARCHAR(MAX));
INSERT t1 values (1,'Jamie');
INSERT t1 values (1,'Joe');
INSERT t1 values (1,'John');
INSERT t1 values (2,'Sai');
INSERT t1 values (2,'Sam');
GO
select
id,
stuff((
select ',' + t.[name]
from t1 t
where t.id = t1.id
order by t.[name]
for xml path('')
),1,1,'') as name_csv
from t1
group by id
;
FOR XML PATH is one of the only situations in which you can use ORDER BY in a subquery. The other is TOP. And when you use an unnamed column and FOR XML PATH(''), you will get a straight concatenation, with no XML tags. This does mean that the strings will be HTML Encoded, so if you're concatenating strings which may have the < character (etc), then you should maybe fix that up afterwards, but either way, this is still the best way of concatenating strings in SQL Server 2005.
building on mwigdahls answer. if you also need to do grouping here is how to get it to look like
group, csv
'group1', 'paul, john'
'group2', 'mary'
--drop table #user
create table #user (groupName varchar(25), username varchar(25))
insert into #user (groupname, username) values ('apostles', 'Paul')
insert into #user (groupname, username) values ('apostles', 'John')
insert into #user (groupname, username) values ('family','Mary')
select
g1.groupname
, stuff((
select ', ' + g.username
from #user g
where g.groupName = g1.groupname
order by g.username
for xml path('')
),1,2,'') as name_csv
from #user g1
group by g1.groupname
You can use this query to do the above task:
DECLARE #test NVARCHAR(max)
SELECT #test = COALESCE(#test + ',', '') + field2 FROM #test
SELECT field2 = #test
For detail and step by step explanation visit the following link
http://oops-solution.blogspot.com/2011/11/sql-server-convert-table-column-data.html
DECLARE #EmployeeList varchar(100)
SELECT #EmployeeList = COALESCE(#EmployeeList + ', ', '') +
CAST(Emp_UniqueID AS varchar(5))
FROM SalesCallsEmployees
WHERE SalCal_UniqueID = 1
SELECT #EmployeeList
source:
http://www.sqlteam.com/article/using-coalesce-to-build-comma-delimited-string
In SQLite this is simpler. I think there are similar implementations for MySQL, MSSql and Orable
CREATE TABLE Beatles (id integer, name string );
INSERT INTO Beatles VALUES (1, "Paul");
INSERT INTO Beatles VALUES (2, "John");
INSERT INTO Beatles VALUES (3, "Ringo");
INSERT INTO Beatles VALUES (4, "George");
SELECT GROUP_CONCAT(name, ',') FROM Beatles;
you can use stuff() to convert rows as comma separated values
select
EmployeeID,
stuff((
SELECT ',' + FPProjectMaster.GroupName
FROM FPProjectInfo AS t INNER JOIN
FPProjectMaster ON t.ProjectID = FPProjectMaster.ProjectID
WHERE (t.EmployeeID = FPProjectInfo.EmployeeID)
And t.STatusID = 1
ORDER BY t.ProjectID
for xml path('')
),1,1,'') as name_csv
from FPProjectInfo
group by EmployeeID;
Thanks #AlexKuznetsov for the reference to get this answer.
A clean and flexible solution in MS SQL Server 2005/2008 is to create a CLR Agregate function.
You'll find quite a few articles (with code) on google.
It looks like this article walks you through the whole process using C#.
If you're executing this through PHP, what about this?
$hQuery = mysql_query("SELECT * FROM users");
while($hRow = mysql_fetch_array($hQuery)) {
$hOut .= $hRow['username'] . ", ";
}
$hOut = substr($hOut, 0, strlen($hOut) - 1);
echo $hOut;