Reformat table data sql - mysql

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

Related

How to convert row data into columns in mysql?

I need help to convert the data in a following format from 2 columns (ID & description ) to 6 further columns shown below . Will appreciate the suggestions provided.
Id Description
------ ------------------------------------------------------------------------------------------
1 Company : RAFIQ BRAZING WORK
1 Factory Address : Plot No. 2, 87/B/12, Shop No. 1 , Nr. Lalit
1 Factory Address : Engineering, G.I.D.C., Umber, Dist, Valsad - 7482
,
1 Factory Address : ITHDH
1 Contact Name : Mr. Adam Noor / Mr. Noor,
1 Mobile : 8888761 9323
1 Product : MS Steel,
1 Product : Copper
2 Company : ComapSAPNA STEEL
2 Factory Address: Plot No. 1909, Ill Phase, GIDC, Umbergoan,
2 Factory Address : Dist. Valsad 5er 5334, Arat
2 Mobile : 0260-32517320 Fax: 0260-2562133
2 Contact Name: Mr. Farukh Abdulla Mobile: 6667027032
2 Email: farbdulla# gmail.com
2 Office address: Gala no. 3, B.T. Compound, malad west, Mumbai - 407777
2 Contact Name: Mr. Hamsa Abdulla Mobile:093333732768
2 Product: Specialist in Profile Cutting, Traders of M.S.Plate,
2 Product : Angels Channels, etc.
ID Company contactperson mobilenumber products factoryaddress
1 RAFIQ BRAZING WORK Mr. Adam Noor/ Mr. Noor +8888761 9323 MS Steel, Copper Plot No. X, 19/B/12, Shop No. 1 , Nr. Lalit Engineering, G.I.D.C., Umber, Dist, Valsad - 7482 ,ITHDH
That’s a poor data model. Each attribute should be stored as a column rather than buried in a string.
For your setup, assuming that ' : ' consistently separates the attribute name from its value, you could use string functions and conditional aggregation like this:
select id,
group_concat(case when attr = 'Company' then val end) as company,
group_concat(case when attr = 'Factory Address' then val end) as factory_address,
...
from (
select t.*,
left(description, locate(' : ', description) - 1) as attr,
substring(description, locate(' : ', description) + 3) as val
from mytable t
) t
group by id
The subquery parses the string as an attribute/value pair, then the outer query aggregates.
Unlike some other RDBMS MySQL doesn't have native support for pivoting operations of this sort by design (the developers feel it's more suited to the presentation, rather than database, layer of your application).
If you absolutely must perfom such manipulations within MySQL, building a prepared statement is the way to go—although rather than messing around with CASE, I'd probably just use MySQL's GROUP_CONCAT() function:
SELECT CONCAT(
'SELECT `table`.id', GROUP_CONCAT('
, `t_', REPLACE(name, '`', '``'), '`.value
AS `', REPLACE(name, '`', '``'), '`'
SEPARATOR ''),
' FROM `table` ', GROUP_CONCAT('
LEFT JOIN `table` AS `t_', REPLACE(name, '`', '``'), '`
ON `table`.id = `t_', REPLACE(name, '`', '``'), '`.id
AND `t_', REPLACE(name, '`', '``'), '`.name = ', QUOTE(name)
SEPARATOR ''),
' GROUP BY `table`.id'
) INTO #qry FROM (SELECT DISTINCT name FROM `table`) t;
PREPARE stmt FROM #qry;
EXECUTE stmt;
Note that the result of GROUP_CONCAT() is limited by the group_concat_max_len variable (default of 1024 bytes: unlikely to be relevant here unless you have some extremely long name values).

Partial/Abbreviated Name Matching

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%';

Is there a way for switch 2 words in MySQL row field

I would want to switch 2 words (firstName lastName) in a mysql row's fields
example :
I have a column 'persons' with a field :
Jonh Smith
I would want to switch to : Smith Jonh
I searched a lot for a MySQL function or snippet but found no way.
Try this update if the field has only two words
UPDATE tablename
SET persons = CONCAT(SUBSTRING_INDEX(SUBSTRING_INDEX(persons, ' ', 2), ' ', -1),' ',
SUBSTRING_INDEX(SUBSTRING_INDEX(persons, ' ', 1), ' ', -1))

Splitting a single column (name) into two (forename, surname) in SQL

Currently I'm working on a database redesign project. A large bulk of this project is pulling data from the old database and importing it into the new one.
One of the columns in a table from the old database is called 'name'. It contains a forename and a surname all in one field (ugh). The new table has two columns; forenames and surname. I need to come up with a clean, efficient way to split this single column into two.
For now I'd like to do everything in the same table and then I can easily transfer it across.
3 columns:
Name (the forename and surname)
Forename (currently empty, first half of name should go here)
Surname (currently empty, second half of name should go here)
What I need to do: Split name in half and place into forename and surname
If anyone could shed some light on how to do this kind of thing I would really appreciate it as I haven't done anything like this in SQL before.
Database engine: MySQL
Storage engine: InnoDB
A quick solution is to use SUBSTRING_INDEX to get everything at the left of the first space, and everything past the first space:
UPDATE tablename
SET
Forename = SUBSTRING_INDEX(Name, ' ', 1),
Surname = SUBSTRING_INDEX(Name, ' ', -1)
Please see fiddle here. It is not perfect, as a name could have multiple spaces, but it can be a good query to start with and it works for most names.
Try this:
insert into new_table (forename, lastName, ...)
select
substring_index(name, ' ', 1),
substring(name from instr(name, ' ') + 1),
...
from old_table
This assumes the first word is the forename, and the rest the is lastname, which correctly handles multi-word last names like "John De Lacey"
For the people who wants to handle fullname: John -> firstname: John, lastname: null
SELECT
if( INSTR(`name`, ' ')=0,
TRIM(SUBSTRING(`name`, INSTR(`name`, ' ')+1)),
TRIM(SUBSTRING(`name`, 1, INSTR(`name`, ' ')-1)) ) first_name,
if( INSTR(`name`, ' ')=0,
null,
TRIM(SUBSTRING(`name`, INSTR(`name`, ' ')+1)) ) last_name
It works fine with John Doe. However if user just fill in John with no last name, SUBSTRING(name, INSTR(name, ' ')+1)) as lastname will return John instead of null and firstname will be null with SUBSTRING(name, 1, INSTR(name, ' ')-1).
In my case I added if condition check to correctly determine lastname and trim to prevent multiple spaces between them.
This improves upon the answer given, consider entry like this "Jack Smith Smithson", if you need just first and last name, and you want first name to be "Jack Smith" and last name "Smithson", then you need query like this:
-- MySQL
SELECT
SUBSTR(full_name, 1, length(full_name) - length(SUBSTRING_INDEX(full_name, ' ', -1)) - 1) as first_name,
SUBSTRING_INDEX(full_name, ' ', -1) as last_name
FROM yourtable
Just wanted to share my solution. It also works with middle names. The middle name will be added to the first name.
SELECT
TRIM(SUBSTRING(name,1, LENGTH(name)- LENGTH(SUBSTRING_INDEX(name, ' ', -1)))) AS firstname,
SUBSTRING_INDEX(name, ' ', -1) AS lastname
I had a similar problem but with Names containing multiple names, eg. "FirstName MiddleNames LastName" and it should be "MiddleNames" and not "MiddleName".
So I used a combo of substring() and reverse() to solve my problem:
select
SystemUser.Email,
SystemUser.Name,
Substring(SystemUser.Name, 1, instr(SystemUser.Name, ' ')) as 'First Name',
reverse(Substring(reverse(SystemUser.Name), 1, instr(reverse(SystemUser.Name), ' '))) as 'Last Name',
I do not need the "MiddleNames" part and maybe this is not the most efficient way to solve it, but it works for me.
Got here from google, and came up with a slightly different solution that does handle names with more than two parts (up to 5 name parts, as would be created by space character). This sets the last_name column to everything to the right of the 'first name' (first space), it also sets full_name to the first name part. Perhaps backup your DB before running this :-) but here it is it worked for me:
UPDATE users SET
name_last =
CASE
WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 1)) = LENGTH(full_name) THEN ''
WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 2)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -1)
WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 3)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -2)
WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 4)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -3)
WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 5)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -4)
WHEN LENGTH(SUBSTRING_INDEX(full_name, ' ', 6)) = LENGTH(full_name) THEN SUBSTRING_INDEX(del_name, ' ', -5)
ELSE ''
END,
full_name = SUBSTRING_INDEX(full_name, ' ', 1)
WHERE LENGTH(name_last) = 0 or LENGTH(name_last) is null or name_last = ''
SUBSTRING_INDEX didn't work for me in SQL 2018, so I used this:
declare #fullName varchar(50) = 'First Last1 Last2'
declare #first varchar(50)
declare #last varchar(50)
select #last = right(#fullName, len(#fullName)-charindex(' ',#fullName, 1)), #first = left(#fullName, (charindex(' ', #fullName, 1))-1);
Yields #first = 'First', #last = 'Last1 Last2'

sql last name comma first null checks

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
*/