How can I use SQL to break comma-separeted values into new rows - sql

I have the following dataset example:
Name:
Qualities:
Adam
Authentic,Cool,Young
Bob
Serious,Old,Authentic
Carl
Cool,Athletic,Hardworker
And I need to use SQL to turn this dataset into the following:
Name:
Qualities:
Adam
Authentic
Adam
Cool
Adam
Young
Bob
Serious
Bob
Old
Bob
Authentic
Carl
Cool
Carl
Athletic
Carl
Hardworker
Can someone give me a hand on that? I have no clue how can I get this done.
Hope to find it out soon!
Cheers!

SELECT Name, value AS Quality FROM <dataset>
CROSS APPLY STRING_SPLIT(Qualities, ',')

You can used STRING_SPLIT for string values.
Please see more informaton.
https://www.sqlservertutorial.net/sql-server-string-functions/sql-server-string_split-function/
SELECT
Name,
value Quality
FROM
<TABLE NAME>
CROSS APPLY STRING_SPLIT(Qualities, ',');

Related

How to merge crosstab info down in Access?

Not sure if this is possible but I'm hoping it is. I am using MS Access for Estate Planning for work. I've gotten to the point where I've got the data to look like this:
File_Name
Executor_1
Executor_2
Beneficiary_1
Beneficiary_2
Hill, Hank
Peggy Hill
Peggy Hill
Hill, Hank
Bobby Hill
Bobby Hill
Gribble, Dale
Nancy Gribble
Gribble, Dale
Joseph Gribble
Joseph Gribble
Gribble, Dale
John Redcorn
But I need it to look like this:
File_Name
Executor_1
Executor_2
Beneficiary_1
Beneficiary_2
Hill, Hank
Peggy Hill
Bobby Hill
Peggy Hill
Bobby Hill
Gribble, Dale
Nancy Gribble
Joseph Gribble
Joseph Gribble
John Redcorn
I need it in the latter format so I can use MailMerge in word and create the Will. Can anyone provide any guidance? We don't currently use any software for Est. Planning so anything beats having to go into Word manually and retype everything. Please let me know if more information is needed.
Edit:
This is what the SQL looks like:
TRANSFORM Last(File_Roles.File_Name) AS LastOfFile_Name
SELECT File_Roles.Executor_1,
File_Roles.Executor_2,
File_Roles.Beneficiary_1,
File_Roles.Beneficiary_2,
File_Roles.Trustee_1,
File_Roles.Trustee_2,
File_Roles.Guardian_1,
File_Roles.Guardian_2,
File_Roles.ATTY_IF_1, File_Roles.ATTY_IF_2,
File_Roles.HCATTY_IF_1,
File_Roles.HCATTY_IF_2
FROM File_Roles
GROUP BY File_Roles.Executor_1,
File_Roles.Executor_2,
File_Roles.Beneficiary_1,
File_Roles.Beneficiary_2,
File_Roles.Trustee_1,
File_Roles.Trustee_2,
File_Roles.Guardian_1,
File_Roles.Guardian_2,
File_Roles.ATTY_IF_1,
File_Roles.ATTY_IF_2,
File_Roles.HCATTY_IF_1,
File_Roles.HCATTY_IF_2
PIVOT File_Roles.File_Name;
You can use GROUP BY and MAX()
SELECT
t.File_Name,
MAX(t.Executor_1) As Executor_1,
MAX(t,Executor_2) As Executor_2,
MAX(t.Beneficiary_1) As Beneficiary_1,
MAX(t.Beneficiary_2) As Beneficiary_2
FROM table_or_query t
GROUP BY File_Name
But maybe you can fix your original crosstab query to do this right away. Probably you are doing the grouping wrong. You must group by File_Name in the crosstab query and apply Max to the total row of the value (so it is difficult to say without seeing this query).
GROUP BY File_Name means that one row is created for each distinct value of File_Name.
Since this will merge several rows into one, you must specify an aggregate function for every column in the SELECT list not listed in the GROUP BY clause. This can be e.g. SUM(), AVG(), MIN() or MAX(). See SQL Aggregate Functions for a complete list. Since any Null value is considered to be less than any other value, MAX() will take this non-Null value from the merged rows.

Columns into JSON array

I have the following table:
Name
Pets
John
Bird
John
Cow
John
Dog
Nina
Cow
Nina
Fish
Nina
Cat
I would like to output it like so:
Name
Pets
John
["Bird","Cow","Dog"]
Nina
["Cow","Fish","Cat"]
I have this starting point, that converts a single column to JSON.
SELECT JSON_ARRAY(GROUP_CONCAT(column_name SEPARATOR ',')) AS names
FROM table_name;
I'm new to working with arrays and JSON in SQL. Is this possible? What is the best solution?
This approach is already a proper solution for this current case, just need to add GROUP BY expression, and exchange the aliases such as
SELECT name, JSON_ARRAY(GROUP_CONCAT(pets)) AS pets
FROM t
GROUP BY name
where , is the default seperator, then adding that is redundant
Demo
P.S. seems your DB is MySQL (version at least 5.7+) or its extension which's so called MariaDB or SQLite. It's expected to tag the DBMS, and its version, which you're using.

SQL Group By with Text Transformation

I'm trying to do some transformations on a large data set that I'm working on and was hoping for a bit of assistance on a particular grouping. I have a series of records that follow a pattern similar to below:
Language Full Name Customer ID
--------------------------------------
English John Smith 12222
French John Smith 12222
Spanish John Smith 12222
English Karen Wong 55999
Cantonese Karen Wong 55999
I need the data such that the Full Name and Customer ID are not repeated so simply using DISTINCT for that. However, one oddity in the requirement is that all the different languages need to be preserved and squashed into the resulting output so the resulting data needs to look like this:
Languages Spoken Full Name Customer ID
----------------------------------------------------
English, French, Spanish John Smith 12222
English, Cantonese Karen Wong 55999
Sounded like a simple thing but I guess I'm not a big SQL guru and keep getting funny results. Any help would be much appreciated :)
If you're using SQL Server 2017 or Azure SQL than you can just use STRING_AGG
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-2017
For everything else (covers solutions from SQL Server 2005 and on):
Simulating group_concat MySQL function in Microsoft SQL Server 2005?

Returning a substring within given HTML tags in a Row in SQL Server

I've below 3 rows in a table -
1. <p><strong>By Dr. Mercola</strong></p> <blockquote> <p>In an interview with ElectromagneticHealth.org
2. <p><strong>By Barbara Loe Fisher</strong></p> <blockquote> <p>Here we are in the winter of 2015, and
3. <p><strong>By Gary Ruskin<br> Co-Founder and Executive Director, U.S. Right to Know</strong></p> <blockquote> <p>U.S. Right to Know
From the above rows i want to fetch a substring and want a result as below -
Dr. Mercola
Barbara Loe Fisher
Gary Ruskin
For this i have written below query-
CASE WHEN CHARINDEX('<p><strong>By', FormattedBody, -1)=1 THEN LTRIM(REPLACE(LEFT(CAST(FormattedBody as nvarchar(max)),CHARINDEX('</strong>', FormattedBody)-1),'<p><strong>By',''))
ELSE 'Dr.Mercola' END as Name
The above query returns the expected output for the first 2 rows, but not for the third row. It returns Gary Ruskin<br> Co-Founder and Executive Director, U.S. Right to Know
Please let me know what additional changes should be made to the query to get expected results. Thanks in advance.!!
Your pattern matching is looking for </strong> to end the name.
However, the examples suggest that < is sufficient for this purpose. It is hard to imagine a person's name with this character, so it seems safe to use that.
So, you can try:
(CASE WHEN CHARINDEX('<p><strong>By', FormattedBody, -1) = 1
THEN LTRIM(REPLACE(LEFT(CAST(FormattedBody as nvarchar(max)), CHARINDEX('<', FormattedBody) - 1, 12), '<p><strong>By', ''))
ELSE 'Dr.Mercola'
END) as Name
SELECT SUBSTRING(REPLACE(col,'<p><strong>By ',''),0,CHARINDEX('<',REPLACE(col,'<p><strong>By ','')))
FROM (VALUES
('<p><strong>By Dr. Mercola</strong></p> <blockquote> <p>In an interview with ElectromagneticHealth.org'),
('<p><strong>By Barbara Loe Fisher</strong></p> <blockquote> <p>Here we are in the winter of 2015, and '),
('<p><strong>By Gary Ruskin<br> Co-Founder and Executive Director, U.S. Right to Know</strong></p> <blockquote> <p>U.S. Right to Know')
) as t (col)
Will give you:
Dr. Mercola
Barbara Loe Fisher
Gary Ruskin
Used below query and working properly for each case-
CASE WHEN CHARINDEX('<p><strong>By', FormattedBody, -1)=1 THEN LTRIM(SUBSTRING(REPLACE(CAST(FormattedBody as varchar(max)),'<p><strong>By ',''),0,CHARINDEX('<',REPLACE(cast(FormattedBody as varchar(max)),'<p><strong>By ',''))))
ELSE 'Dr.Mercola' END as Name

Another transpose rows to columns question- SQL Server 2005

Sorry I know similar question have been asked many times before but like most I haven't been able to find one that fits what I need or gives me enough information to be able to expand towards the solution.
I suspect I could use the PIVOT or UNPIVOT commands of T-SQL but I can't follow the MSDN explanation and there don't seem to be any "idiots" type guides out there!
Onto my problem - I need to convert a wide table consisting of many columns to a row based result set for a report. No aggregation needed and I'm trying to avoid a repeated UNION based select if possible.
The table result set is formatted as such (there are actually many more person columns! :s ):
Person1 | Person2 | Person3 | Person4 | Person5 | Person6 | Person7 | Person8
-----------------------------------------------------------------------------
Bob Sam Tom Alex Paul Ann Jill Jane
What I really need is to be able to produce the following:
Person
--------------------
Bob
Sam
Tom
Alex
Paul
Ann
Jill
Jane
A bonus would be able to create a result set such as:
Column Person
--------------------
Person1 Bob
Person2 Sam
Person3 Tom
Person4 Alex
Person5 Paul
Person6 Ann
Person7 Jill
Person8 Jane
How can this be achieved using T-SQL in SQL Server 2005?
Thanks for any help,
Paul.
--Edit--
Thanks to Martin I've learnt something new this morning and I've managed to get exactly what I needed. In the end I had to modify the example slightly to get what I needed but that's because my original example left out some detail that I hadn't realised would be important!
My final piece of code looked like this for anyone else that has such a problem:
WITH Query_CTE([Person1 Title],[Person2 Title],[Person3 Title])
AS
--CTE Expression and column list
(
SELECT
--Converted to create a common data type.
CONVERT(NVARCHAR(MAX),Person1Title) AS 'Person1 Title',
CONVERT(NVARCHAR(MAX),Person2Title) AS 'Person2 Title',
CONVERT(NVARCHAR(MAX),Person3Title) AS 'Person3 Title'
FROM Table_Name
WHERE KeyId = 'XXX'
)
SELECT *
FROM Query_CTE
UNPIVOT
(Person FOR [Column] IN
(
[Person1 Title],
[Person2 Title],
[Person3 Title]
)
)AS unpvt;
WITH T(Person1,Person2 /* etc....*/) AS
(
SELECT 'Bob','Sam' /* etc....*/
)
SELECT *
FROM T
UNPIVOT
(Person FOR [Column] IN
(Person1,Person2 /* etc....*/)
)AS unpvt;
To easily transpose columns into rows with its names you should use XML. In my blog I was described this with example: http://sql-tricks.blogspot.com/2011/04/sql-server-rows-transpose.html