Please see the following SQL code.
Declare #LookUp table (id int,val varchar(12))
insert into #LookUp values (1,'A'),(1,'D'),(1,'X'),(2,'B'),(2,'F')
Declare #summary table (id int,val varchar(2000))
------------------------------
Declare #value varchar(30)
Declare #start int = 1, #end int = (Select count(Distinct id) from #LookUp)
While #start <= #end
Begin
Set #value = ''
Select #value = #value + '|' + val From #LookUp Where id = #start
Insert into #summary
Select #start,Right(#value,Len(#value)-1)
Set #start = #start + 1
End
Select * From #summary
With the following query, I am grouping based on Id, and making the values with in a group, as comma-separated values.
Input:
Output:
I have done this using a loop, which is not performing very well when it comes to large amount of data.
Can we do this avoiding a loop?
Note: Assume that #lookup.id is continuous.
INSERT #summary(id, val)
SELECT
t.id,
STUFF((
select '|' + [val]
from #LookUp t1
where t1.id = t.id
for xml path(''), type
).value('.', 'varchar(max)'), 1, 1, '') [values]
FROM #LookUp t
GROUP BY t.id
Try this..
Declare #LookUp table (id int,val varchar(12))
insert into #LookUp values (1,'A'),(1,'D'),(1,'X'),(2,'B'),(2,'F')
select
id,
val =
stuff((
select
'| ' + t2.val
from #LookUp t2
where
t2.id = t1.id
group by t2.val
for xml path(''), type).value('.', 'varchar(max)'
), 1, 2, '')
from #LookUp t1
GROUP BY t1.id
Declare #LookUp table (id int,val varchar(12))
insert into #LookUp values (1,'A'),(1,'D'),(1,'X'),(2,'B'),(2,'F');
WITH A AS
(
SELECT DISTINCT id
FROM #LookUp
)
SELECT
A.id,
STUFF
(
(
SELECT ',' + val
FROM #LookUp B
WHERE B.id = A.id
FOR XML PATH('')
),
1, 1, ''
) AS val
FROM A
Declare #LookUp table (id int,val varchar(12))
insert into #LookUp values (1,'A'),(1,'D'),(1,'X'),(2,'B'),(2,'F')
SELECT DISTINCT a.id, stuff((select '|' + val
from #LookUp c
where c.id = a.id
for xml path('')),1,1,'') as vall
FROM #LookUp a
I'll add a solution based on a recursive common table expression. With small modifications it should work in DB2 too (you have to change the row_number() function to rownumber() and how the concatenation works in the second list (use || instead of the concat function).
DECLARE #LookUp TABLE (id int, val varchar(12))
INSERT INTO #LookUp VALUES (1,'A'),(1,'D'),(1,'X'),(2,'B'),(2,'F')
;WITH
list1(rn, id, val) AS
(
SELECT row_number() OVER (PARTITION BY id ORDER BY id), id, val
FROM #LookUp
),
list2 (id, val, idx) AS
(
SELECT id, val, 1
FROM list1
WHERE rn = 1
UNION ALL
SELECT
list2.id,
CAST(CONCAT(list2.val, ' | ', list1.val) AS varchar(12)),
list2.idx + 1
FROM list2
JOIN list1 ON list2.id = list1.id
WHERE list2.idx + 1 = list1.rn
)
SELECT l2.id, l2.val
FROM list2 l2
JOIN (SELECT id, MAX(rn) maxid FROM list1 GROUP BY id) a
ON l2.id = a.id AND l2.idx = a.maxid
ORDER BY l2.id
This outputs:
id val
1 A | D | X
2 B | F
Related
Using SQL-Server 2012
I have the following Table:
Id Description
6192 Salzburg
6193 Salzburg
6194 Salzburg
6196 Innsbruck
6197 Innsbruck
6198 Innsbruck
6199 Innsbruck
6201 Bregenz
6202 Bregenz
6203 Bregenz
I want to Select each Distinct "Description" with all the Id's together in one string:
Description Ids
Salzburg '6192,6193,6194'
Innsbruck '6196,6197,6198'
I saw some similar code on this site [How to concatenate text from multiple rows into a single text string in SQL server?, but I couldn't figure it out yet for my purpose (don't want to use XML Path!). Here is what I have tried so far:
DECLARE #ids AS Nvarchar(MAX)
SELECT #ids = COALESCE(#ids + ',', '') + CAST(t.Id AS nvarchar(5))
FROM (SELECT tmp.Id FROM (SELECT id, [Description] FROM tblMasterPropValues WHERE IdCategory = 253 AND IsActive = 1) as tmp
WHERE [Description] = tmp.[Description]) AS t
SELECT #ids
--SELECT DISTINCT [Description], #ids AS IDs FROM tblMasterPropValues WHERE IdCategory = 253 AND IsActive = 1 AND Id IN (#ids)
I can't really get my head around it, and would appreciate any help on it.
You can try using STUFF() function
SELECT description, Ids = STUFF(
(SELECT ',' + Id
FROM tblMasterPropValues t1
WHERE t1.description = t2.description
FOR XML PATH (''))
, 1, 1, '') from tblMasterPropValues t2
group by description;
For that FOR XML PATH() is the right clause so, you can do :
SELECT DISTINCT v.description, STUFF(v1.ids, 1, 1, '''') + ''''
FROM tblMasterPropValues v CROSS APPLY
(SELECT ', '+ CAST(v1.Id AS VARCHAR(255))
FROM tblMasterPropValues v1
WHERE v1.description = v.description
FOR XML PATH('')
) v1(ids);
You can also make it by using recursive CTE
DECLARE #tblMasterPropValues TABLE (Id INT, Description VARCHAR(20))
INSERT INTO #tblMasterPropValues VALUES
(6192 , 'Salzburg'),
(6193 , 'Salzburg'),
(6194 , 'Salzburg'),
(6196 , 'Innsbruck'),
(6197 , 'Innsbruck'),
(6198 , 'Innsbruck'),
(6199 , 'Innsbruck'),
(6201 , 'Bregenz'),
(6202 , 'Bregenz'),
(6203 , 'Bregenz')
;WITH Tbl AS
(
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY Description ORDER BY Id) AS RN,
COUNT(*) OVER(PARTITION BY Description) AS CNT
FROM #tblMasterPropValues
)
, Rcr AS (
SELECT *, CAST(Id AS varchar(max)) Ids
FROM Tbl WHERE RN = 1
UNION ALL
SELECT T.*, Rcr.Ids + ',' + CAST(T.Id AS VARCHAR(10)) Ids
FROM Rcr
INNER JOIN Tbl T ON T.RN = Rcr.RN + 1 and Rcr.Description = T.Description
)
SELECT RN, Description, Ids FROM Rcr
WHERE RN = CNT
Result:
Description Ids
-------------------- -----------------------
Salzburg 6192,6193,6194
Innsbruck 6196,6197,6198,6199
Bregenz 6201,6202,6203
Try this:
DECLARE #Table TABLE(ID INT, Description VARCHAR(25))
INSERT INTO #Table
VALUES (6192,'Salzburg' )
,(6193,'Salzburg' )
,(6194,'Salzburg' )
,(6196,'Innsbruck')
,(6197,'Innsbruck')
,(6198,'Innsbruck')
,(6199,'Innsbruck')
,(6201,'Bregenz' )
,(6202,'Bregenz' )
,(6203,'Bregenz' )
Query:
SELECT DISTINCT T2.Description,
SUBSTRING(
(
SELECT ','+CAST(T1.ID AS VARCHAR) AS [text()]
FROM #Table T1
WHERE T1.Description = T2.Description
ORDER BY T1.Description
FOR XML PATH ('')
), 2, 1000) [Ids]
FROM #Table T2
Result:
Description Ids
Bregenz 6201,6202,6203
Innsbruck 6196,6197,6198,6199
Salzburg 6192,6193,6194
How to create one row from two columns?
Example:
id description
------------------
1 one
2 two
3 three
In result:
1: one, 2: two, 3: three
I use follow statment:
select Id,
stuff((SELECT distinct ', ' + cast(Description as varchar(10))
FROM dbo.tbl t2
where t2.Id = t1.Id
FOR XML PATH('')),1,1,'')
from dbo.tbl t1
group by Id
But in result I have two columns. I need one such as string
You can try this query.
CREATE TABLE T (
id int,
description varchar(50)
);
INSERT INTO T VALUES (1,'one');
INSERT INTO T VALUES (2,'two');
INSERT INTO T VALUES (3,'three');
Query 1:
select
stuff((SELECT ', ' + CAST(t2.ID AS VARCHAR(5)) + ':'+ t2.description
FROM t t2
FOR XML PATH('')),1,1,'')
Results:
| |
|------------------------|
| 1:one, 2:two, 3:three |
i think you are asking for this
select stuff((SELECT ', ' + CAST(tbl.id AS varchar) + ':' + tbl.description
FROM tablename tbl FOR XML PATH('')), 1, 1, '') as Columnname
You were close..
declare #T TABLE (
id int,
description varchar(50)
);
INSERT INTO #T VALUES (1,'one');
INSERT INTO #T VALUES (2,'two');
INSERT INTO #T VALUES (3,'three');
select Id,
stuff((SELECT distinct ', ' + +cast(id as nvarchar) +':'+description
FROM #T t2
where t2.Id = t1.Id
FOR XML PATH('')),1,1,'')
from #T t1
group by Id
OR If you want all the ids in a sing row use the below query
select stuff((select ',' +cast(id as nvarchar) +':'+description
from #T for xml path('')),1,1,'')
select statement is like a for loop or an iterator and you you need a space to save you data and it's not possible with select only because in the moment select statement only access to a row not previous row and not next row so
please use a scaler-value function
create function test()
return
nvarchar(max)
as
begin
declare #s nvarchar(max)
select #s = concate(#s, id, description)
from yourTable
return #s
end
How to find the number of distinct character used in the field having multiple rows.
For example, if there are two rows having data like abcd and eaafg* then distinct character used are abcdefg*.
Try this one -
INSERT INTO #temp (txt)
VALUES ('abcd3'), ('abcdefg*')
SELECT disword = (
SELECT DISTINCT dt.ch
FROM (
SELECT ch = SUBSTRING(t.mtxt, n.number + 1, 1)
FROM [master].dbo.spt_values n
CROSS JOIN (
SELECT mtxt = (
SELECT txt
FROM #temp
FOR XML PATH(N''), TYPE, ROOT).value(N'root[1]', N'NVARCHAR(MAX)'
)
) t
WHERE [type] = N'p'
AND number <= LEN(mtxt) - 1
) dt
FOR XML PATH(N''), TYPE, ROOT).value(N'root[1]', N'NVARCHAR(MAX)'
)
Example (edited):
SET NOCOUNT ON;
DECLARE #temp TABLE (txt VARCHAR(8000))
INSERT INTO #temp (txt)
VALUES ('abcd'), ('abcdefg*'), (REPLICATE('-', 8000)), (REPLICATE('+', 8000))
DECLARE #t TABLE (i BIGINT)
DECLARE
#i BIGINT = 1
, #l BIGINT = (
SELECT SUM(LEN(txt))
FROM #temp
)
WHILE (#i <= #l) BEGIN
INSERT INTO #t (i)
VALUES (#i), (#i+1), (#i+2), (#i+3), (#i+4), (#i+5), (#i+6), (#i+7), (#i+8), (#i+9)
SELECT #i += 10
END
SELECT disword = (
SELECT DISTINCT dt.ch
FROM (
SELECT ch = SUBSTRING(t.mtxt, n.i, 1)
FROM #t n
CROSS JOIN (
SELECT mtxt = (
SELECT txt
FROM #temp
FOR XML PATH(N''), TYPE, ROOT).value(N'root[1]', N'NVARCHAR(MAX)'
)
) t
) dt
FOR XML PATH(N''), TYPE, ROOT).value(N'root[1]', N'NVARCHAR(MAX)'
)
Have a look a t this solution -
SELECT
dt.ch
, cnt = COUNT(1)
FROM (
SELECT ch = SUBSTRING(t.mtxt, n.i, 1)
FROM #t n
CROSS JOIN (
SELECT mtxt = (
SELECT txt
FROM #temp
FOR XML PATH(N''), TYPE, ROOT).value(N'root[1]', N'NVARCHAR(MAX)')
) t
) dt
WHERE dt.ch != ''
GROUP BY dt.ch
ORDER BY cnt DESC
Here are questions that may refer to what you are asking:
How do I get distinct characters of string column in mssql?
and
SQL: how to get all the distinct characters in a column, across all rows
With tallys:
DECLARE #t TABLE (s NVARCHAR(MAX))
INSERT INTO #t
VALUES ('abcd'), ('abcdefg*')
;WITH tally AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) i
FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t1(n)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t2(n))
SELECT
( SELECT DISTINCT sb
FROM tally
CROSS APPLY ( SELECT SUBSTRING(s, i, 1) sb FROM #t ) ca
WHERE sb <> ''
FOR XML PATH(N'') , TYPE , ROOT).value(N'root[1]', N'NVARCHAR(MAX)')
I have two lists and I want to see what the two lists DON'T have in common. For example:
List1:
'a','b','c','123'
List2:
'd','e','f','a','asd','c'
I want output to be:
'b','123','d','e','f','asd'
Something like this?
select * from ('a','b','c','123')
join ('d','e','f','a','asd','c')
on ???
Is there a pure SQL Server solution for this without using tables?
If you have control over the lists, I would just make them table variables:
DECLARE #a TABLE (str varchar(100))
INSERT INTO #a
VALUES
('a'),
('b')...
DECLARE #b table (str varchar(100))
INSERT INTO #b
VALUES
...
(SELECT str FROM #a
EXCEPT
SELECT str FROM #b)
UNION
(SELECT str FROM #b
EXCEPT
SELECT str FROM #a)
Given this function:
CREATE FUNCTION dbo.SplitStrings ( #List NVARCHAR(MAX) )
RETURNS TABLE
AS
RETURN ( SELECT Item FROM (
SELECT Item = x.i.value('(./text())[1]', 'nvarchar(max)')
FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(#List,',', '</i><i>')
+ '</i>').query('.')) AS a CROSS APPLY [XML].nodes('i') AS x(i)
) AS y WHERE Item IS NOT NULL);
GO
You can do it with a full outer join:
DECLARE
#list1 NVARCHAR(MAX) = N'a,b,c,123',
#list2 NVARCHAR(MAX) = N'd,e,f,a,asd,c',
#output NVARCHAR(MAX) = N'';
SELECT #output += N',' + COALESCE(l1.Item, l2.Item)
FROM dbo.SplitStrings(#list1) AS l1
FULL OUTER JOIN dbo.SplitStrings(#list2) AS l2
ON l1.Item = l2.Item
WHERE l1.Item IS NULL OR l2.Item IS NULL;
SELECT STUFF(#output, 1, 1, N'');
Or similar to #JNK's:
DECLARE
#list1 NVARCHAR(MAX) = N'a,b,c,123',
#list2 NVARCHAR(MAX) = N'd,e,f,a,asd,c',
#output NVARCHAR(MAX) = N'';
;WITH l1 AS (SELECT Item FROM dbo.SplitStrings(#list1)),
l2 AS (SELECT Item FROM dbo.SplitStrings(#list2))
SELECT #output += N',' + Item
FROM ( (SELECT Item FROM l1 EXCEPT SELECT Item FROM l2)
UNION
(SELECT Item FROM l2 EXCEPT SELECT Item FROM l1)) AS x;
SELECT STUFF(#output, 1, 1, N'');
And probably a variety of other ways too. If order matters, it's going to be a little more complex, but still possible.
There is no easy way to accomplish this. To filter the values from a list you need to have them as rows. So you would end up with something like:
SELECT col FROM (
SELECT 'a' as col
UNION
SELECT 'b'
UNION
SELECT 'c') t
WHERE col NOT IN ('a', 'b')
How about:
with
list1(j) as (select 'a' union select 'b'),
list2(j) as (select 'b' union select 'c')
select coalesce(list1.j, list2.j)
from list1 full join list2
on list1.j = list2.j
where (list1.j is null or list2.j is null)
I think you'll have to insert the values into 2 variable tables.
DECLARE #Table1 TABLE (Value VARCHAR(1))
DECLARE #Table2 TABLE (Value VARCHAR(1))
INSERT INTO #Table1 (Value) VALUES ('a')
INSERT INTO #Table1 (Value) VALUES ('b')
INSERT INTO #Table2 (Value) VALUES ('b')
INSERT INTO #Table2 (Value) VALUES ('c')
Then perform some set operations on the 2 tables.
DECLARE #TableUnion TABLE (Value VARCHAR(1))
DECLARE #TableIntersection TABLE (Value VARCHAR(1))
DECLARE #TableExcept TABLE (Value VARCHAR(1))
INSERT INTO #TableUnion
SELECT * FROM
((SELECT * FROM #Table1)
UNION
(SELECT * FROM #Table2)) U
INSERT INTO #TableIntersection
SELECT * FROM
((SELECT * FROM #Table1)
INTERSECT
(SELECT * FROM #Table2)) I
INSERT INTO #TableExcept
SELECT * FROM
((SELECT * FROM #TableUnion)
EXCEPT
(SELECT * FROM #TableIntersection)) E
The result set of the final select statement will contain 'a' and 'c'. Which can be concatenated into a single string as follows.
DECLARE #ExceptString VARCHAR(3)
SELECT #ExceptString =
CASE
WHEN #ExceptString IS NULL THEN Value
ELSE #ExceptString + ',' + Value
END
FROM #TableExcept
Based on below 2 tables
declare #t1 table
(
Id int,
Title varchar(100),
RelatedId int
)
insert into #t1 values(1,'A',2)
insert into #t1 values(1,'A',3)
declare #t2 table
(
Id int,
Title varchar(100)
)
insert into #t2 values
(2,'B'),
(3,'C')
I am trying to get the below output
Id Title RelatedItems
---------------------------------
1 A 2 (B), 3 (C)
I tried the following:
select t1.Id,t1.Title, cast(t2.Id as varchar) + ' (' + t2.Title + ')' from #t1 as t1
left outer join #t2 as t2
on t1.RelatedId=t2.Id
But that gives 2 different rows. I want just one row with the data combined in the third column (as shown above). Pls. suggest.
Use:
SELECT DISTINCT
b.id,
b.title,
STUFF((SELECT ','+ CAST(t2.id AS VARCHAR(100)) + ' ('+ t2.title +')'
FROM t2
JOIN t1 a ON a.relatedid = t2.id
WHERE a.id = b.id
FOR XML PATH('')), 1, 1, '')
FROM t1 b