I have three columns in the database that represent a person's first, middle, and last names:
People
|------------------------------------------|
| First_Name | Last_name | Middle_name|
|------------------------------------------|
| John | Hansen | T |
| NULL | Smith | NULL |
| Jacob | NULL | J |
| Michael | Johnson | NULL |
|------------------------------------------|
What is the best way to get null safe Last, First Name + Middle Name. So that from the list above I would get:
Hansen, John T
Smith
Jacob J
Johnson, Michael
So far I've got:
select concat_ws(', ', name_last, concat_ws(' ', name_first, name_middle)) as name from entity;
but it's giving me trailing , where I don't want them.
You can use the fact that CONCAT will return NULL if any of the arguments are NULL:
SELECT COALESCE(CONCAT(last_name, ', ', first_name), last_name, first_name)
FROM People
SQL Fiddle Demo
Or, now that you've edited your question to add a Middle_name column:
SELECT COALESCE(CONCAT(last_name, ', ', COALESCE(CONCAT(first_name, ' ', middle_name),first_name,middle_name)),
last_name,
COALESCE(CONCAT(first_name, ' ', middle_name),first_name,middle_name))
FROM People
SQL Fiddle Demo
The other way around:
You have a fullname column containing "firstname middlename lastname"
and want to display it sorted on lastname
Made this as working, at least it works great on dutch names ("van der Boogert" but also single (artist)names.
This example trims the anmes for extra spaces, then counts the amount of spaces in the fullname so no commas are places when its only a single name (artist name)
SELECT
TRIM(fullname) as originalfullname,
length(trim(fullname)) -length(replace(TRIM(fullname), ' ', '')) AS countedzeros,
SUBSTRING_INDEX(TRIM(fullname), ' ', length(TRIM(fullname)) -length(replace(TRIM(fullname), ' ', ''))) AS first_name,
SUBSTRING_INDEX(TRIM(fullname), ' ', -1) AS last_name,
CONCAT(
SUBSTRING_INDEX(TRIM(fullname), ' ', -1),
IF(length(TRIM(fullname)) -length(replace(TRIM(fullname), ' ', '')),', ',''),
SUBSTRING_INDEX(TRIM(fullname), ' ', length(TRIM(fullname)) -length(replace(TRIM(fullname), ' ', '')))
) as dispayname
FROM catalog
group by fullname
/*
Theo van den Boogaart => Boogaart, Theo van den
Hergé => Hergé
Jhonny Smith => Smith, Johnny
*/
Related
Im trying to write a query that will match partial matches to stored name values.
My database looks as follows
Blockquote
FirstName | Middle Name | Surname
----------------------------------
Joe | James | Bloggs
J | J | Bloggs
Joe | | Bloggs
Jane | | Bloggs
Now if a user enters their name as
J Bloggs
my query should return all 4 rows, as they are all potential matches.
Similarly if a user enters the name
J J Bloggs
all rows should be returned.
If a user enters their name as
Joe Bloggs
only the first three should be returned.
I have tried the following
SELECT *
FROM PERSON
WHERE CONCAT(' ',FirstName,' ',MiddleName,' ', Surname) LIKE '% Joe%'
AND CONCAT(' ',FirstName,' ',MiddleName,' ', Surname, ' ') LIKE '% Bloggs%';
But this doesn't return 'J J Bloggs'.
Any ideas?
If I understand your logic correctly, any of the three input name components is considered to be a match if it either is a substring of a value in the table, or vice-versa. That is, J matches Joe, but also Joe matches to J. Using this logic, we can write the following query:
SELECT *
FROM yourTable
WHERE
(INSTR(FirstName, 'J') > 0 OR INSTR('J', FirstName) > 0) AND
(INSTR(MiddleName, 'J') > 0 OR INSTR('J', MiddleName) > 0 OR MiddleName IS NULL) AND
(INSTR(Surname, 'Bloggs') > 0 OR INSTR('Bloggs', Surname) > 0);
Demo
Note that the middle name has some additional logic. If the middle name be missing in a record (i.e. it is NULL), then we wave the requirement for the middle names to match.
I think you might need OR instead of AND...
SELECT *
FROM PERSON
WHERE CONCAT(' ',FirstName,' ',MiddleName,' ', Surname) LIKE '% Joe%'
OR CONCAT(' ',FirstName,' ',MiddleName,' ', Surname, ' ') LIKE '% Bloggs%';
How to make an SQL query for a table based on the following conditions:
Result is a single column that concatenates all fields delimited by a dash into a single string (ex: FieldA-FieldB-FieldC-FieldD-FieldE)
If a given field is NULL or if the field's value is a string such as "EMPTY" or "NA", do not concatenate that field's value into the result string
Example Table Person (FirstName, LastName, Street, City, State):
Bob | Dylan | 555 Street | Mountain View | California
Ally | M | NULL | Seattle | Washington
Jan | Van | EMPTY | EMPTY | Oregon
Nancy | Finn | EMPTY | EMPTY | NA
Don | William | NULL | EMPTY | Illinois
Result:
Bob-Dylan-555 Street-Mountain View-California
Ally-M-Seattle-Washington
Jan-Van-Oregon
Nancy-Finn
Don-William-Illinois
I know this can be done programatically, but wanted to know if this can be done in SQL and if it would be more efficient to do so in the query itself.
Fully-baked solution for SQL Server 2017 and above:
SELECT *
FROM Person p
OUTER APPLY (
SELECT STRING_AGG(NULLIF(NULLIF(val, 'EMPTY'), 'NA'), '-')
WITHIN GROUP (ORDER BY n) AS val
FROM (VALUES (1, p.FirstName), (2, p.LastName),(3, p.Street),
(4,p.City), (5, p.State)) z(n, val)
)sub;
DBFiddle Demo
MySQL version using CONCAT_WS:
CONCAT_WS() stands for Concatenate With Separator and is a special form of CONCAT(). The first argument is the separator for the rest of the arguments. The separator is added between the strings to be concatenated. The separator can be a string, as can the rest of the arguments. If the separator is NULL, the result is NULL.
CONCAT_WS() does not skip empty strings. However, it does skip any NULL values after the separator argument.
SELECT CONCAT_WS('-',
NULLIF(NULLIF(FirstName, 'EMPTY'), 'NA'),
NULLIF(NULLIF(LastName, 'EMPTY'), 'NA'),
NULLIF(NULLIF(Street, 'EMPTY'), 'NA'),
NULLIF(NULLIF(City, 'EMPTY'), 'NA'),
NULLIF(NULLIF(State, 'EMPTY'), 'NA')) AS r
FROM Person p;
DBFiddle Demo2
first, use CONCAT to concatenate the fields.
then use REPLACE to replace NULL values
SELECT REPLACE( CONCAT( field1, "-", field2 , "-", field3) , "NULL", "EMPTY" )
FROM `table`
Try This
SELECT ISNULL(FirstName,'') + '-' +
ISNULL (LastName,'') + '-' +
ISNULL (City,'') + '-' +
ISNULL (State,'')
FROM Person
OR LIKE THIS
SELECT CASE WHEN ISNULL(FirstName,'') = '' THEN '' ELSE FirstName + '-' +
CASE WHEN ISNULL(LastName,'') = '' THEN '' ELSE LastName + '-' +
CASE WHEN ISNULL(City,'') = '' THEN '' ELSE City + '-' +
CASE WHEN ISNULL(State,'') = '' THEN '' ELSE State + '-' END AS
ColumnName
FROM Person
Your select should be something like this:
select isnull(FieldA,'')+ '-' + isnull (FieldB,'') + '-' + isnull (FieldC,'') ....
and so on ..
This will work on MS SQL server if you don't want '-' if previous field is null than you should use case statement.
If you want to replace also 'Empty' or 'NULL' strings than you should use:
select replace(replace( isnull(FieldA+'-','') , 'Empty' , ''),'Null', '')
I have modified isnull() by Nitin_g3 observation.
Within a table like this:
ID| ph_number
-----------
1 | 51231234
2 | 5123 1234
3 | 51231234; 61231234
4 | 5123 1234; 61231234
5 | 5123 1934; 6123 1234
6 | 5123 1234; 6123 1234
7 | aargh; 5123 1234; 6123 1234
, user needs to find a phone number (ex 51231234) not knowing where the spaces are, or if there are many numbers per field. I can find the numbers without spaces with query like this:
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE REPLACE('51231234', ' ', '')
that returns IDs 1 and 2, or
SELECT ID, ph_number FROM test WHERE ph_number LIKE '%51231234%'
that returns IDs 1 and 3. But Needed are IDs 1,2,3,4, 6 and 7. I'm not able to combine the two queries. Have tried:
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE ('%' + REPLACE('51231234', ' ', '') + '%') // returns 1 & 2
SELECT ID, ph_number FROM test WHERE REPLACE(ph_number, ' ', '') LIKE '%' + REPLACE('51231234', ' ', '') + '%' // returns ERROR
How could I achieve this? I wouldn't want to tell users that they can't have multiple numbers on the field.
In MySQL "+" is exclusively an arithmetic operator. Use the CONCAT() function to concatenate strings:
....WHERE REPLACE(ph_number, ' ', '') LIKE CONCAT('%', REPLACE('51231234', ' ', ''), '%')
I have a field name with the following rows:
`name`
------
John Smith
George Washington
Ash Ketchum
Bill O'Reilly
I would like to reformat the rows on output:
`name`
------
SMITH, JOHN
WASHINGTON, GEORGE
KETCHUM, ASH
O'REILLY BILL
I know I can use upper( x.name ) for casing, but how can I reformat the names?
Assuming your rdbms is mySql, answer will need to be tailored to differenct dialects of sql.
SELECT concat( substring(name, locate(name, ' ')), ', ', substring(name, 0, locate(name, ' ') - 1)) FROM NAMES;
The real problem here however is data integrity. You need to have seperate columns for each peice of the name so that formating in the database is ensured to be consitent. Ideally you would want to be doing this --
Select concat(last_name, ', ', first_name) FROM NAMES;
Allowing
'name'
-------------------
John Smith
Smith, John
J Smith
Smith J
John q Smith
Jhon 'the smithmeister' Smith
All in the same column of a table is a bad thing for a number of reasons so this should be explictly prevented.
Try this:
SELECT SUBSTRING_INDEX( `name` , ' ', -1 ) + ', ' + SUBSTRING_INDEX( `name` , ' ', 1 )
FROM MyTable
#Ben, makes a good point about names with multiple spaces in them. I doubt this would give you the output you want in those cases, but it should get you started.
try this
SELECT Concat(SUBSTRING_INDEX( `name` , ' ', -1 ) , ', ' , SUBSTRING_INDEX( `name` , ' ', 1 )) as name
FROM your_Table
How create json format with group-concat mysql?
(I use MySQL)
Example1:
table1:
email | name | phone
-------------------------------------
my1#gmail.com | Ben | 6555333
my2#gmail.com | Tom | 2322452
my2#gmail.com | Dan | 8768768
my1#gmail.com | Joi | 3434356
like syntax code that not give me the format:
select email, group-concat(name,phone) as list from table1
group by email
output that I need:
email | list
------------------------------------------------
my1#gmail.com | {name:"Ben",phone:"6555333"},{name:"Joi",phone:"3434356"}
my2#gmail.com | {name:"Tom",phone:"2322452"},{name:"Dan",phone:"8768768"}
Thanks
With the newer versions of MySQL, you can use JSON_OBJECT function to achieve the desired result, like so:
GROUP_CONCAT(
JSON_OBJECT(
'name', name,
'phone', phone
)
) AS list
To get the SQL response ready to be parsed as an array:
CONCAT(
'[',
GROUP_CONCAT(
JSON_OBJECT(
'name', name,
'phone', phone
)
),
']'
) AS list
This will give you a string like: [{name: 'ABC', phone: '111'}, {name: 'DEF', phone: '222'}] which can be JSON parsed.
Try this query -
SELECT
email,
GROUP_CONCAT(CONCAT('{name:"', name, '", phone:"',phone,'"}')) list
FROM
table1
GROUP BY
email;
JSON format result -
+---------------+-------------------------------------------------------------+
| email | list |
+---------------+-------------------------------------------------------------+
| my1#gmail.com | {name:"Ben", phone:"6555333"},{name:"Joi", phone:"3434356"} |
| my2#gmail.com | {name:"Tom", phone:"2322452"},{name:"Dan", phone:"8768768"} |
+---------------+-------------------------------------------------------------+
For Mysql 5.7.22+
SELECT
email,
JSON_ARRAYAGG(
JSON_OBJECT(
'name', name,
'phone', phone
)
) AS list
FROM table1
GROUP BY email;
Result:
+---------------+-------------------------------------------------------------------+
| email | list |
+---------------+-------------------------------------------------------------------+
| my1#gmail.com | [{"name":"Ben", "phone":6555333},{"name":"Joi", "phone":3434356}] |
| my2#gmail.com | [{"name":"Tom", "phone":2322452},{"name":"Dan", "phone":8768768}] |
+---------------+-------------------------------------------------------------------+
The only difference is that column list is now Json-valid, so you can parse directly as Json
I hope this finds the right eyes.
You can use:
For arrays (documentation):
JSON_ARRAYAGG(col_or_expr) as ...
For objects (documentation):
JSON_OBJECTAGG(key, value) as ...
Devart's answer above is great, but K2xL's question is valid. The answer I found was to hexadecimal-encode the name column using HEX(), which ensures that it will create valid JSON. Then in the application, convert the hexadecimal back into the string.
(Sorry for the self-promotion, but) I wrote a little blog post about this with a little more detail:
http://www.alexkorn.com/blog/2015/05/hand-rolling-valid-json-in-mysql-using-group_concat/
[Edit for Oriol] Here's an example:
SELECT email,
CONCAT(
'[',
COALESCE(
GROUP_CONCAT(
CONCAT(
'{',
'\"name\": \"', HEX(name), '\", ',
'\"phone\": \"', HEX(phone), '\"',
'}')
ORDER BY name ASC
SEPARATOR ','),
''),
']') AS bData
FROM table
GROUP BY email
Also note I've added a COALESCE in case there are no items for that email.
Similar to Madacol's answer above, but slightly different. Instead of JSONARRAYAGG, you could also CAST AS JSON:
SELECT
email,
CAST( CONCAT(
'[',
GROUP_CONCAT(
JSON_OBJECT(
'name', name,
'phone', phone
)
),']') AS JSON )
FROM table1
GROUP BY email;
Result:
+---------------+-------------------------------------------------------------------+
| email | list |
+---------------+-------------------------------------------------------------------+
| my1#gmail.com | [{"name":"Ben", "phone":6555333},{"name":"Joi", "phone":3434356}] |
| my2#gmail.com | [{"name":"Tom", "phone":2322452},{"name":"Dan", "phone":8768768}] |
+---------------+-------------------------------------------------------------------+
Going off of #Devart's answer... if the field contains linebreaks or double quotation marks, the result will not be valid JSON.
So, if we know the "phone" field occasionally contains double-quotes and linebreaks, our SQL would look like:
SELECT
email,
CONCAT(
'[',
GROUP_CONCAT(CONCAT(
'{name:"',
name,
'", phone:"',
REPLACE(REPLACE(phone, '"', '\\\\"'),'\n','\\\\n'),
'"}'
)),
']'
) AS list
FROM table1 GROUP BY email;
If Ben phone has a quote in the middle of it, and Joi's has a newline, the SQL would give (valid JSON) results like:
[{name:"Ben", phone:"655\"5333"},{name:"Joi", phone:"343\n4356"}]
Use like this
SELECT email,concat('{name:"',ur_name_column,'",phone:"',ur_phone_column,'"}') as list FROM table1 GROUP BY email;
Cheers