Как выполнить объединение в SQL Server без использования таблиц - PullRequest
1 голос
/ 10 февраля 2012

У меня есть два списка, и я хочу посмотреть, что общего между этими двумя списками НЕ имеет.Например:

List1:
'a','b','c','123'

List2:
'd','e','f','a','asd','c'

Я хочу, чтобы вывод был:

'b','123','d','e','f','asd'

Как-то так?

select * from ('a','b','c','123')
join ('d','e','f','a','asd','c')
on ???

Есть ли для этого решение на чистом SQL Server безиспользуя таблицы?

Ответы [ 5 ]

5 голосов
/ 10 февраля 2012

Если у вас есть контроль над списками, я бы просто сделал их табличными переменными:

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)
3 голосов
/ 10 февраля 2012

С учетом этой функции:

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

Вы можете сделать это с полным внешним объединением:

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'');

или аналогично @ 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'');

И, возможно, множество других способов тоже.Если порядок важен, он будет немного сложнее, но все же возможен.

1 голос
/ 10 февраля 2012

Как насчет:

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)
1 голос
/ 10 февраля 2012

Нет простого способа сделать это.Чтобы отфильтровать значения из списка, вы должны иметь их в виде строк.Таким образом, вы получите что-то вроде:

SELECT col FROM (
SELECT 'a' as col
UNION
SELECT 'b'
UNION
SELECT 'c') t

WHERE col NOT IN ('a', 'b')
0 голосов
/ 10 февраля 2012

Я думаю, вам придется вставить значения в 2 таблицы переменных.

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')

Затем выполните несколько операций над множествами таблиц.

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

Результирующий набор последнего оператора выбора будет содержать «a» и «c». Который может быть объединен в одну строку следующим образом.

DECLARE @ExceptString VARCHAR(3)

SELECT @ExceptString = 
    CASE 
        WHEN @ExceptString IS NULL THEN Value
        ELSE @ExceptString + ',' + Value
    END
FROM @TableExcept
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...