SQL Query Distinct Column Concatenate Other Column - sql

I have a MS SQL query that joins multiple tables and an example of the results are:
EmailAddress Column2
--------------------- ----------------
sean#abc.com Value1
sean#abc.com Value2
test#abc.com Value5
What I really want to achieve are the following results:
EmailAddress Column2
--------------------- ------------------
sean#abc.com Value1, Value2
test#abc.com Value5
There are other columns that are identical for each row with the same email address. Can anyone help me with the SQL to return distinct email addresses and concatenate the column2 information?
Thanks for any feedback.

Try the answer to this question

In SQL Server 2005+:
WITH q AS
(
SELECT 'sean#abc.com' AS address, 'Value1' AS value
UNION ALL
SELECT 'sean#abc.com', 'Value2'
UNION ALL
SELECT 'test#abc.com', 'Value5'
)
SELECT (
SELECT CASE WHEN ROW_NUMBER() OVER (ORDER BY value) > 1 THEN ', ' ELSE '' END + value
FROM q qi
WHERE qi.address = qo.address
FOR XML PATH('')
)
FROM (
SELECT DISTINCT address
FROM q
) qo

Same answer from Jeremy, but I would use the other answer with XML PATH trick

Related

SQL Server Convert Particular Column Values into comma separated String

I have a table in Database as below :
Id Name
1 Item1
1 Item2
2 Item3
1 Item4
3 Item5
I need output as below(3rd column is count):
1 Item1,Item2,Item4 3
2 Item3 1
3 Item5 1
How it can achieved by SQL Query ?
SQL Server has STUFF() function which could able to help you.
SELECT t.Id,
Name = STUFF( (SELECT DISTINCT ','+Name
FROM table
WHERE Id = t.Id
FOR XML PATH('')
), 1, 1, ''
)
FROM table t
GROUP BY t.Id;
SQL Server 2017 has introduced a much easier way to achieve this using STRING_AGG(expression, separator).
Here's an example:
SELECT STRING_AGG(T.Name, ', ') FROM MyTable T where MyColumnID = 78
You could even play around with formatting in other ways like this one:
SELECT STRING_AGG(CONCAT(T.MyColumnID,' - ',T.Name), ', ') FROM MyTable T where MyColumnID = 78
More info in this blog I found about it: https://database.guide/the-sql-server-equivalent-to-group_concat/
select id, group_concat(name) csv,
from Table
group by id

SQL query to get column names if it has specific value

I have a situation here, I have a table with a flag assigned to the column names(like 'Y' or 'N'). I have to select the column names of a row, if it have a specific value.
My Table:
Name|sub-1|sub-2|sub-3|sub-4|sub-5|sub-6|
-----------------------------------------
Tom | Y | | Y | Y | | Y |
Jim | Y | Y | | | Y | Y |
Ram | | Y | | Y | Y | |
So I need to get, what are all the subs are have 'Y' flag for a particular Name.
For Example:
If I select Tom I need to get the list of 'Y' column name in query output.
Subs
____
sub-1
sub-3
sub-4
sub-6
Your help is much appreciated.
The problem is that your database model is not normalized. If it was properly normalized the query would be easy. So the workaround is to normalize the model "on-the-fly" to be able to make the query:
select col_name
from (
select name, sub_1 as val, 'sub_1' as col_name
from the_table
union all
select name, sub_2, 'sub_2'
from the_table
union all
select name, sub_3, 'sub_3'
from the_table
union all
select name, sub_4, 'sub_4'
from the_table
union all
select name, sub_5, 'sub_5'
from the_table
union all
select name, sub_6, 'sub_6'
from the_table
) t
where name = 'Tom'
and val = 'Y'
The above is standard SQL and should work on any (relational) DBMS.
Below code works for me.
select t.Subs from (select name, u.subs,u.val
from TableName s
unpivot
(
val
for subs in (sub-1, sub-2, sub-3,sub-4,sub-5,sub-6,sub-7)
) u where u.val='Y') T
where t.name='Tom'
Somehow I am near to the solution. I can get for all rows. (I just used 2 columns)
select col from ( select col, case s.col when 'sub-1' then sub-1 when 'sub-2' then sub-2 end AS val from mytable cross join ( select 'sub-1' AS col union all select 'sub-2' ) s ) s where val ='Y'
It gives the columns for all row. I need the same data for a single row. Like if I select "Tom", I need the column names for 'Y' value.
I'm answering this under a few assumptions here. The first is that you KNOW the names of the columns of the table in question. Second, that this is SQL Server. Oracle and MySql have ways of performing this, but I don't know the syntax for that.
Anyways, what I'd do is perform an 'UNPIVOT' on the data.
There's a lot of parans there, so to explain. The actual 'unpivot' statement (aliased as UNPVT) takes the data and twists the columns into rows, and the SELECT associated with it provides the data that is being returned. Here's I used the 'Name', and placed the column names under the 'Subs' column and the corresponding value into the 'Val' column. To be precise, I'm talking about this aspect of the above code:
SELECT [Name], [Subs], [Val]
FROM
(SELECT [Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6]
FROM pvt) p
UNPIVOT
(Orders FOR [Name] IN
([Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6])
)AS unpvt
My next step was to make that a 'sub-select' where I could find the specific name and val that was being hunted for. That would leave you with a SQL Statement that looks something along these lines
SELECT [Name], [Subs], [Val]
FROM (
SELECT [Name], [Subs], [Val]
FROM
(SELECT [Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6]
FROM pvt) p
UNPIVOT
(Orders FOR [Name] IN
([Name], [Sub-1], [Sub-2], [Sub-3], [Sub-4], [Sub-5], [Sub-6])
)AS unpvt
) AS pp
WHERE 1 = 1
AND pp.[Val] = 'Y'
AND pp.[Name] = 'Tom'
select col from (
select col,
case s.col
when 'sub-1' then sub-1
when 'sub-2' then sub-2
when 'sub-3' then sub-3
when 'sub-4' then sub-4
when 'sub-5' then sub-5
when 'sub-6' then sub-6
end AS val
from mytable
cross join
(
select 'sub-1' AS col union all
select 'sub-2' union all
select 'sub-3' union all
select 'sub-4' union all
select 'sub-5' union all
select 'sub-6'
) s on name="Tom"
) s
where val ='Y'
included the join condition as
on name="Tom"

How to group 3 columns into a single one in SQL

I have a table that has three columns: myColumn, myColumn2 and myColumn3. The three columns can have a different value but they are all the same type.
I need to do a join such that I merge all the items in the three columns and then group by
If I had a single column, it would be done like this:
select distinct (myColumn), COUNT(myColumn) as 'TotalF'
from FormularioCorto
where idEvento = #idEvento and myColumn <> ''
group by myColumn
The question is:
How do I do a TSQL statement that will allow for me to join the three columns and then group by?
Edit: here is the sample data
I have a table that has 3 columns with the same type
columna columnb columnc
a a b
b a b
c c d
I need to run a tsql that will merge the 3 columns and group by, to get a result like
newcolumn count
a 3
b 3
c 2
d 1
Any ideas?
Thanks in advance
It is hard to tell without some sample data and desired output but a guess would be something like:
SELECT MyCol as MyColumn, Count(*) as 'TotalF'
FROM
(
SELECT myColumn MyCol from FormularioCorto
WHERE idEvento = #idEvento AND myColumn <> ''
UNION ALL
SELECT myColumn2 MyCol from FormularioCorto
WHERE idEvento = #idEvento AND myColumn2 <> ''
UNION ALL
SELECT myColumn3 MyCol from FormularioCorto
WHERE idEvento = #idEvento) AND myColumn3 <> ''
) A
GROUP BY MyCol;
Or for just the example data and result:
SELECT NewColumn, Count(*) as Count FROM
(
SELECT columna as NewColumn FROM SomeTable
UNION ALL
SELECT columnb as NewColumn FROM SomeTable
UNION ALL
SELECT columnc as NewColumn FROM SomeTable
) A
Group by NewColumn
I think you mean concatenate rather than JOIN. JOIN has a very specific meaning with SQL. Use the + operator to concatenate string fields.
CONCAT(`myColumn`, `myColumn2`, `myColumn3`) as joinedField
The CONCAT() function concatenates fields and strings.
Info:
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat
Note: You should reconsider your structure though, as this will prove to be painfully slow as you add more records.
select cast(myColumn as nvarchar) + CAST(COUNT(myColumn)as nvarchar) as 'TotalF'
from FormularioCorto
where idEvento = #idEvento and myColumn <> ''
group by myColumn
If I am understanding your question right, then you simply want 2 columns (one identifying the id you are counting and one giving the count for the identifier. If this is correct, simply use your existing query for each column and union the results.
For example;
SELECT myColumn AS Id, COUNT(myColumn) AS IdCount
FROM FormularioCorto
where idEvento = #idEvento and myColumn <> ''
GROUP BY myColumn
UNION
SELECT myColumn2 AS Id, COUNT(myColumn2) AS IdCount
FROM FormularioCorto
where idEvento = #idEvento and myColumn2 <> ''
GROUP BY myColumn2
etc etc.
Try this:
SELECT myColumn1 + myColumn2 + myColumn3 AS AllThreeFields
FROM FormularioCorto
WHERE 1=1
GROUP BY myColumn1 + myColumn2 + myColumn3
It won't be fast but it should work. If you need to delimit the data in the columns with other characters you can try this:
SELECT myColumn1 + ' ' + myColumn2 + ' ' + myColumn3 AS AllThreeFields
FROM FormularioCorto
WHERE 1=1
GROUP BY myColumn1 + myColumn2 + myColumn3
If the column types are not the same (you said they were), you will need to cast them to a similar type.

how to combine two numeric fields?

How to combine two int columns into one.
My table1 is as follows:
name adress1 adress2
hhh 1 2
www 2 3
I want result as follows:
name columnz
hhh 12
www 23
In the upcoming SQL-server you can do:
SELECT name, concat(address1,address2) as columnz
FROM table1
However SQL-server does not allow concat yet, so you'll have the use the '+' operator and a cast.
SELECT
name
,CAST(address1 AS char)+CAST(address2 AS char) as columnz
FROM table1
SQL is not that troublesome about the difference between strings and numbers.
Another option is:
SELECT name, (address1*10+address2) as columnz
FROM table1
SELECT name, CAST(ADRESS1 AS VARCHAR(20)) + CAST(ADRESS2 AS VARCHAR(20)) AS columnz from table1
Try this:
SELECT name, Concat(adress1, adress2) AS columnz FROM table1;
select name, convert(varchar, adress1) + convert(varchar, adress2) as columnz from table1;

SQL 2005 Merge / concatenate multiple rows to one column

We have a bit of a SQL quandry. Say I have a results that look like this...
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | A
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | B
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | C
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | D
7ce953ca-a55b-4c55-a52c-9d6f012ea903 | E
7ce953ca-a55b-4c55-a52c-9d6f012ea903 | F
is there a way I can group these results within SQL to return as
61E77D90-D53D-4E2E-A09E-9D6F012EB59C | A B C D
7ce953ca-a55b-4c55-a52c-9d6f012ea903 | E F
Any ideas people?
Many thanks
Dave
try this:
set nocount on;
declare #t table (id char(36), x char(1))
insert into #t (id, x)
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'A' union
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'B' union
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'C' union
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'D' union
select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'E' union
select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'F'
set nocount off
SELECT p1.id,
stuff(
(SELECT
' ' + x
FROM #t p2
WHERE p2.id=p1.id
ORDER BY id, x
FOR XML PATH('')
)
,1,1, ''
) AS YourValues
FROM #t p1
GROUP BY id
OUTPUT:
id YourValues
------------------------------------ --------------
61E77D90-D53D-4E2E-A09E-9D6F012EB59C A B C D
7ce953ca-a55b-4c55-a52c-9d6f012ea903 E F
(2 row(s) affected)
EDIT
based on OP's comment about this needing to run for an existing query, try this:
;WITH YourBugQuery AS
(
--replace this with your own query
select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' AS ColID , 'A' AS ColX
union select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'B'
union select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'C'
union select '61E77D90-D53D-4E2E-A09E-9D6F012EB59C' , 'D'
union select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'E'
union select '7ce953ca-a55b-4c55-a52c-9d6f012ea903' , 'F'
)
SELECT p1.ColID,
stuff(
(SELECT
' ' + ColX
FROM YourBugQuery p2
WHERE p2.ColID=p1.ColID
ORDER BY ColID, ColX
FOR XML PATH('')
)
,1,1, ''
) AS YourValues
FROM YourBugQuery p1
GROUP BY ColID
this has the same results set as displayed above.
I prefer to define a custom user-defined aggregate. Here's an example of a UDA which will accomplish something very close to what you're asking.
Why use a user-defined aggregate instead of a nested SELECT? It's all about performance, and what you are willing to put up with. For a small amount of elements, you can most certainly get away with a nested SELECT, but for large "n", you'll notice that the query plan essentially runs the nested SELECT once for every row in the output list. This can be the kiss of death if you're talking about a large number of rows. With a UDA, it's possible to aggregate these values in a single pass.
The tradeoff, of course, is that the UDA requires you to use the CLR to deploy it, and that's something not a lot of people do often. In Oracle, this particular situation is a bit nicer as you can use PL/SQL directly to create your user-defined aggregate, but I digress...
Another way of doing it is to use the FOR XML PATH option
SELECT
[ID],
(
SELECT
[Value] + ' '
FROM
[YourTable] [YourTable2]
WHERE
[YourTable2].[ID] = [YourTable].[ID]
ORDER BY
[Value]
FOR XML PATH('')
) [Values]
FROM
[YourTable]
GROUP BY
[YourTable].[ID]