在SQL Server中相交

Niz*_*zam 5 sql sql-server intersect

有没有办法使用交叉而不选择不同的值?有点像INTERSECT ALL.

例如,考虑表A和B.

A --> 1, 1, 1, 2, 3, 4

B --> 1, 1, 2
Run Code Online (Sandbox Code Playgroud)

会导致

Result --> 1, 1, 2
Run Code Online (Sandbox Code Playgroud)

编辑

我认为这个链接很好地解释了我想要的东西.这个其他链接也有助于理解这个问题.或者这个其他链接更好地解释事件.

编辑2

假设表格:

表A.

?????????????????????????????
?   A    ? B  ? C ? D  ? E  ?
?????????????????????????????
? Car    ? 10 ? 1 ? OK ? -1 ?
? Car    ? 10 ? 1 ? OK ? -1 ?
? Car    ? 10 ? 1 ? OK ? -1 ?
? House  ? 10 ? 1 ? NO ? -5 ?
? Monkey ? 15 ? 1 ? OK ? -1 ?
? Dog    ?  3 ? 1 ? OK ? -1 ?
?????????????????????????????
Run Code Online (Sandbox Code Playgroud)

表B.

??????????????????????????
?  A  ? B  ? C ? D  ? E  ?
??????????????????????????
? Car ? 10 ? 1 ? OK ? -1 ?
? Car ? 10 ? 1 ? OK ? -1 ?
? Car ? 15 ? 1 ? OK ? -1 ?
? Dog ?  3 ? 1 ? OK ? -1 ?
??????????????????????????
Run Code Online (Sandbox Code Playgroud)

intersect(select * from A INTERSECT select * from B)的答案是:

??????????????????????????
?  A  ? B  ? C ? D  ? E  ?
??????????????????????????
? Car ? 10 ? 1 ? OK ? -1 ?
? Dog ?  3 ? 1 ? OK ? -1 ?
??????????????????????????
Run Code Online (Sandbox Code Playgroud)

因为它只需要不同的值.我想要的是采用常见的行,就像:

??????????????????????????
?  A  ? B  ? C ? D  ? E  ?
??????????????????????????
? Car ? 10 ? 1 ? OK ? -1 ?
? Car ? 10 ? 1 ? OK ? -1 ?
? Dog ?  3 ? 1 ? OK ? -1 ?
??????????????????????????
Run Code Online (Sandbox Code Playgroud)

观察我不需要知道我有什么链接(连接是位置的,就像INTERSECT).ID将是使用所有列构建的(表之间的链接是所有列,基于它们的位置).

And*_*y M 5

在SQL Server中,INTERSECT仅适用于不同的行.如果您希望区分重复的行,则需要使行不同.我能想到的唯一方法是添加另一个列并使用每个副本的唯一值填充它,但这样的结果是所得到的行可以跨不同的表进行匹配.

然而,问题是到目前为止还没有通用的语法.例如,您可以使用ROW_NUMBER()来枚举每个副本,但是您必须为每个案例单独写出它的PARTITION BY子句:没有PARTITION BY *,至少在SQL Server中没有.

无论如何,为了说明,这里是ROW_NUMBER方法的样子:

SELECT
  A, B, C, D, E,
  ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1))
FROM
  dbo.A

INTERSECT

SELECT
  A, B, C, D, E,
  ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1))
FROM
  dbo.B
;
Run Code Online (Sandbox Code Playgroud)

如上所述,查询还将在输出中返回一个额外的列,即行号列.如果要禁止它,则需要使查询更复杂:

SELECT
  A, B, C, D, E
FROM
  (
    SELECT
      A, B, C, D, E,
      rn = ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1))
    FROM
      dbo.A

    INTERSECT

    SELECT
      A, B, C, D, E,
      rn = ROW_NUMBER() OVER (PARTITION BY A, B, C, D, E ORDER BY (SELECT 1))
    FROM
      dbo.B
  ) AS s
;
Run Code Online (Sandbox Code Playgroud)

只是为了澄清一下,当我上面说的没有通用语法时,我的意思是你不能不借助动态SQL就能做到这一点.使用动态SQL,很多东西都是可能的,但是这样的解决方案会复杂得多,而且在我看来,可维护性要低得多.

再次,为了说明这一点,这是一个如何使用动态SQL解决它的示例:

DECLARE
  @table1 sysname,
  @table2 sysname,
  @columns nvarchar(max),
  @sql nvarchar(max)
;

SET @table1 = 'dbo.A';
SET @table2 = 'dbo.B';

-- collecting the columns from one table only,
-- assuming the structures of both tables are identical
-- if the structures differ, declare and populate
-- @columns1 and @columns2 separately
SET @columns = STUFF(
  (
    SELECT
      N', ' + QUOTENAME(name)
    FROM
      sys.columns
    WHERE
      object_id = OBJECT_ID(@table1)
    FOR XML
      PATH (''), TYPE
  ).value('text()[1]', 'nvarchar(max)'),
  1,
  2,
  ''
);

SET @sql =
N'SELECT ' + @columns + N'
FROM
  (
    SELECT
      ' + @columns + N',
      ROW_NUMBER() OVER (PARTITION BY ' + @columns + N' ORDER BY (SELECT 1))
    FROM
      ' + @table1 + N'

    INTERSECT

    SELECT
      ' + @columns + N',
      ROW_NUMBER() OVER (PARTITION BY ' + @columns + N' ORDER BY (SELECT 1))
    FROM
      ' + @table2 + N'
  ) AS s
';

EXECUTE sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)

你现在可能至少可以看到"更为复杂"的含义.