TSQL: Displaying multiple rows of results as 1 row - sql-server

All,
Not quite sure how to do the following. Teaching myself SQL, working with SQL Server 2008 R2. Note that while I can perform all the select queries I like, I do not have the permissions to create drop tables in the database.
In my database, there's a table called "messages." Each message is a three letter code (e.g., 'AAA', 'AAB', etc.). Each primary key can have an arbitrary number of messages. So, for purposes of this exercise, say the table looks like this:
1 AAA
1 AAB
1 AAC
2 AAA
2 CCC
etc,
The output I would like to get is to convert this horizontal data to vertical data so I can get this:
1 AAA AAB AAC
2 AAA CCC
If relevant, the database also contains a list of all the possible message codes on a different table.
I suspect the correct answer involves PIVOT, but I am not quite sure how to get there. The closest I found is this: How to pivot table with T-SQL? However, (a) I wasn't sure how to adapt it to my situation and (b) it appears to require creating a table.
Thank you in advance.

Since your question has been edited, including both queries:
Query for expected result in Original question:
;WITH CTE AS (
SELECT T2.ID, STUFF(
(SELECT ' '+ T1.Code
FROM TableName T1
WHERE T1.ID = T2.ID
FOR XML PATH('')),1,1,'') AS CSV
FROM TableName AS T2
GROUP BY T2.ID)
SELECT TOP 1 STUFF(
(SELECT ' ' + s.Temp
FROM (SELECT CONVERT(varchar(10),ID)+' '+CSV as Temp
FROM CTE) s
FOR XML PATH('')),1,1,'') AS Result
Result:
RESULT
1 AAA AAB AAC 2 AAA CCC
See result in SQL Fiddle.
Query for expected result in Edited question:
SELECT T2.ID, STUFF(
(SELECT ' '+ T1.Code
FROM TableName T1
WHERE T1.ID = T2.ID
FOR XML PATH('')),1,1,'') AS Codes
FROM TableName AS T2
GROUP BY T2.ID
Result:
ID CODES
1 AAA AAB AAC
2 AAA CCC
See result in SQL Fiddle.

Test Data
DECLARE #TABLE TABLE(MessageID INT, Body VARCHAR(100))
INSERT INTO #TABLE VALUES
(1, 'AAA'),
(1, 'AAB'),
(1, 'AAC'),
(2, 'AAA'),
(2, 'CCC')
Query
SELECT t.MessageID,
STUFF((SELECT ' ' + Body
FROM #TABLE
WHERE MessageID = t.MessageID
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'')
AS FullMessage
FROM #TABLE t
GROUP BY t.MessageID
Result Set
╔═══════════╦═════════════╗
║ MessageID ║ FullMessage ║
╠═══════════╬═════════════╣
║ 1 ║ AAA AAB AAC ║
║ 2 ║ AAA CCC ║
╚═══════════╩═════════════╝

Related

SQL Server Syntax - Using in or like with comma delimited columns

I have two tables where I want to check if a value exists in the second table.
The problem is that in the second table the group field could either be a individual value or a comma delimited value. I need a query to check if the group value exists in table 2 either as a single value or in a comma delimited value
Table 1
Id
Group
1
Group1
2
Group2
3
Group3
5
Group4
6
Group4
7
Group2
Table 2
Group
Group1, Group2
Group3
The results of the select query would be.
Table 1 Filtered Results
Id
Group
1
Group1
2
Group2
3
Group3
7
Group2
Ideally, you should not store multiple pieces of information in a single column.
But you can solve this in set-based fashion, using STRING_SPLIT in a subquery.
SELECT *
FROM t1
WHERE t1.[group] IN (
SELECT TRIM(s.value)
FROM t2
CROSS APPLY STRING_SPLIT(t2.[group], ',') s
);
db<>fiddle
Maybe this is what you want:
select * from Table1 t1 where exists (
select * from Table2 t2 where t2.[Group] like '%'+t1.[Group]+'%'
)
But be careful!!! "Group" is a keyword in SQL, you should not name a field like that.
UPDATE on Larnu comment:
To avoid Group1 and Group10 match, we can do that:
select * from Table1 t1 where exists (
select * from Table2 t2 where (t2.[Group] like '%'+t1.[Group] or t2.[Group] like '%'+t1.[Group]+',%')
)
Try joining the two tables with a LIKE clause, like this:
DECLARE #t1 TABLE (id INT, [group] VARCHAR(255))
DECLARE #t2 TABLE ([group] VARCHAR(255))
INSERT INTO #t1 VALUES (1,'g1'),(2,'g2'),(3,'g3'),(5,'g4'),(6,'g4'),(7,'g2')
INSERT INTO #t2 VALUES ('g1,g2'),('g3')
SELECT DISTINCT t1.*
FROM #t1 t1 INNER JOIN #t2 t2
ON t2.[group] LIKE '%' + t1.[group] OR t2.[group] LIKE '%' + t1.[group] + ',%'
Result:
id
group
1
g1
2
g2
3
g3
7
g2
UPDATED to accommodate Larnu's comment to Carlos's post

SQL Server: How to select top rows of a group based on value of the column of that group?

I have two tables like below.
table 1
id rem
1 2
2 1
table 2
id value
1 abc
1 xyz
1 mno
2 mnk
2 mjd
EDIT:
#output
id value
1 abc
1 xyz
2 mnk
What i want to do is select top 2 rows of table2 with id one as rem value is 2 for id 1 and top 1 row with id 2 as its rem value is 1 and so on. I am using MS sqlserver 2012 My whole scenario is more complex than this. Please help.
Thank you.
EDIT : I know that i should have given what i have done and how i am doing it but for this particular part i don't have idea for starting. I could do this by using while loop for each unique id but i want to do it in one go if possible.
First, SQL tables represent unordered sets. There is no specification of which values you get, unless you include an order by.
For this purpose, I would go with row_number():
select t2.*
from table1 t1 join
(select t2.*,
row_number() over (partition by id order by id) as seqnum
from table2 t2
) t2
on t1.id = t2.id and t2.seqnum <= t1.rem;
Note: The order by id in the windows clause should be based on which rows you want. If you don't care which rows, then order by id or order by (select null) is fine.
Try This:
DECLARE #tbl1 TABLE (id INT, rem INT)
INSERT INTO #tbl1 VALUES (1, 2), (2, 1)
DECLARE #tbl2 TABLE (id INT, value VARCHAR(10))
INSERT INTO #tbl2 VALUES (1, 'abc'), (1, 'xyz'),
(1, 'mno'), (2, 'mnk'), (2, 'mjd')
SELECT * FROM #tbl1 -- your table 1
SELECT * FROM #tbl2 -- your table 2
SELECT id,value,rem FROM ( SELECT ROW_NUMBER() OVER (PARTITION BY T.ID ORDER BY T.ID) rowid,
T.id,T.value,F.rem FROM #tbl2 T LEFT JOIN #tbl1 F ON T.id = F.id ) A WHERE rowid = 1
-- your required output
Hope it helps.

sql query to display the duplicates as per the requested output

I have a sample input table as show below
╔═══════════╗
║ name id ║
╠═══════════╣
║ anil 3 ║
║ ashok 2 ║
╚═══════════╝
I want to get output for this table as
╔════════════╗
║ name id ║
╠════════════╣
║ anil 3 ║
║ anil 3 ║
║ anil 3 ║
║ ashok 2 ║
║ ashok 2 ║
╚════════════╝
how to achieve this using sql query?
This seems like a job for a Recursive CTE:
create table #input (name varchar(10), id int)
insert into #input values ('anil',3),('ashok',2)
;with cte as
( select a.name, a.id, a.id as countdown
from #input a
union all
select a.name, a.id, a.countdown-1
from cte a
where a.countdown-1 > 0
)
select name,id,countdown from cte
order by 1,2,3 desc
Output
name id countdown
====================
anil 3 3
anil 3 2
anil 3 1
ashok 2 2
ashok 2 1
It's tempting to go for a recursive query but this can be done simply with a tally table.
Something like this:
SET nocount ON;
IF Object_id('dbo.Tally') IS NOT NULL
DROP TABLE dbo.tally
-- Define how many rows you want in Tally table.
-- I am inserting only 100 rows
SET ROWCOUNT 100
SELECT IDENTITY(int, 1, 1) ID
INTO dbo.tally
FROM master.sys.all_columns c
CROSS JOIN master.sys.all_columns c1
-- you may use one more cross join if tally table required hundreds of million rows
SET ROWCOUNT 0
-- ADD (unique) clustered index
CREATE UNIQUE CLUSTERED INDEX pkc_tally
ON dbo.tally (id)
SELECT T2.*
FROM dbo.tally T1
CROSS JOIN table1 T2
WHERE T1.id <= T2.id
You can take a look and play around with an example on SQL Fiddle

Grouping data in comma separated format

I have a table called SampleData which looks like this:
col1 col2
1 a
1 b
1 c
2 d
2 e
3 f
I need the data in the below format:
col1 col2
1 a,b,c
2 d,e
3 f
Is there a way of doing this using CTE as well?
you can use STUFF if you are using SQL Server 2005 and above.
SELECT
[col1],
STUFF(
(SELECT ',' + [col2]
FROM Table1
WHERE [col1] = a.[col1]
FOR XML PATH ('')) , 1, 1, '') AS col2
FROM Table1 AS a
GROUP BY [col1]
SQLFiddle Demo
I think this is also useful to you.
Comma Seprate Value

Join two different columns from two different tables and merge duplicates

i have two temporary table
Table 1
ID1 Name ID2 Single
----------------------------------------------------
1 ABC 1 100
2 DEF 1 200
Table 2
ID1 Name ID2 Monthly
----------------------------------------------------
3 PQR 2 500
4 LMN 2 600
1 ABC 2 700
2 DEF 2 800
I want Output
ID1 Name ID2 Single Monthly
--------------------------------------------------------
1 ABC 1 100 700
2 DEF 1 200 800
3 PQR 2 NULL 500
4 LMN 2 NULL 600
I used all Joins , Union ALL , Union nothing working
thanks in advance
Try this:
select coalesce(T1.ID1, T2.ID1) as ID1,
coalesce(T1.Name, T2.Name) as ID1,
coalesce(T1.ID2, T2.ID2) as ID2,
T1.Single,
T2.Monthly
from Table1 as T1
full outer join Table2 as T2
on T1.ID1 = T2.ID1
https://data.stackexchange.com/stackoverflow/q/121659/
If you know that all rows always will be present in Table2 you can use a right outer join instead of full join.
Hope you are using Sql Server 2008(other wise the insert statement in my query won't work). Try this one.
From the required out put, i guess you need all the values from table2 and there corresponding Single(Column name in table 1) value.
DECLARE #tempTable1 TABLE (ID1 INT,Name VARCHAR(10),ID2 INT,Single INT)
DECLARE #tempTable2 TABLE (ID1 INT,Name VARCHAR(10),ID2 INT,Monthly INT)
INSERT INTO #tempTable1 VALUES
(1 ,'ABC' ,1 ,100),
(2 ,'DEF' ,1 ,200)
INSERT INTO #tempTable2 VALUES
(3 ,'PQR' ,2 ,500 ),
(4 ,'LMN' ,2 ,600 ),
(1 ,'ABC' ,2 ,700 ),
(2 ,'DEF' ,2 ,800 );
SELECT
T2.ID1
,T2.Name
,T2.ID2
,T1.Single
,T2.Monthly
FROM #tempTable2 T2
LEFT OUTER JOIN #tempTable1 T1
ON T2.ID1 = T1.ID1
ORDER BY T2.ID1

Resources