Reputation: 60851
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?
Upvotes: 1
Views: 101
Reputation: 4218
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
Upvotes: 0
Reputation: 280520
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.
Upvotes: 3
Reputation: 1304
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)
Upvotes: 1
Reputation: 65197
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)
Upvotes: 5
Reputation: 11623
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')
Upvotes: 1