【问题标题】:matching groups of rows in two databases匹配两个数据库中的行组
【发布时间】:2017-02-23 16:55:12
【问题描述】:

我在两个数据库中有以下(简化的)情况:

    ID       Prog      T         Qt   
|---------|--------|---------|---------|  
|   a     |    1   |   N     |   100   |  
|   b     |    1   |   Y     |   10    |  
|   b     |    2   |   N     |   90    |  
|   c     |    1   |   N     |   25    |  
|   c     |    2   |   Y     |   25    |  
|   c     |    3   |   Y     |   25    |  
|   c     |    4   |   Y     |   25    |  
|---------|--------|---------|---------|  

    ID       Prog      T         Qt   
|---------|--------|---------|---------|  
|   1     |    1   |   Y     |   10    |  
|   1     |    2   |   N     |   90    |  
|   2     |    1   |   Y     |   100   |  
|   3     |    1   |   Y     |   100   |  
|   4     |    1   |   Y     |    50   |  
|   4     |    2   |   Y     |    25   |  
|   4     |    3   |   Y     |    25   |      
|---------|--------|---------|---------|  

我需要比较行组(主键是 ID 和 Prog),以找出哪些行组代表相同的因素组合(不考虑 ID)。

在上面的示例中,第一个表中的 ID“b”和第二个表中的 ID“1”具有相同的 Prog、T 和 Qt 值组合,而其他任何一个都不能被认为是完全相同的 2 dbs(虽然第二个表中的 ID "2" 和 "3" 相等,但我不想在同一个 db 中进行比较)。

我希望我解释了一切。

【问题讨论】:

  • @iamdave 我的 SQL 命令不如尝试几条 SELECT 语句应有的好。我认为我应该使用函数或存储过程来获取第一个表中所有 ID 的可能结果,而不是求助于一系列 SELECT * FROM ... JOIN ... ON ... WHERE 。 .. 事实是,我已经在这个网站和其他地方搜索了一些东西,但似乎没有人分享关于这个主题的任何内容。有 2 几十个值要匹配,所以我正在寻找简洁优雅的东西

标签: sql sql-server sql-server-2014


【解决方案1】:

连接和聚合应该用于此目的:

select t1.id, t2.id
from (select t1.*, count(*) over (partition by id) as cnt
      from t1
     ) t1 join
     (select t2.*, count(*) over (partition by id) as cnt
      from t2
     ) t2
     on t1.prog = t2.prog and t1.T = t2.T and t1.Qt = t2.Qt and t1.cnt = t2.cnt
group by t1.id, t2.id, t1.cnt
having count(*) = t1.cnt;

这有点棘手。子查询计算每个表中每个 id 的行数。 on 子句获取三列之间的匹配项——并检查 id 是否具有相同的计数。 group byhaving 然后获取匹配行数为总行数的行。

【讨论】:

  • 感谢 Gordon,你是对的:我很确定对于第一个表的每个组合,我应该只检查那些具有相同行数的组合。我会看看它。当我写信给 Wes H 时,我很想找到比加入 2 个几十个值更优雅的东西,但如果 SQL 没有更好的选择,我会选择其中一个!
  • @MaZe 。 . .在其他数据库中,您可以使用 listagg()group_concat() 或类似的东西。尽管您可以在 SQL Server 中执行此操作,但它可能比此解决方案更不优雅。
【解决方案2】:

根据您要匹配的条件连接两个表。结果将是它们之间匹配的值。

CREATE TABLE a (ID CHAR(1), Prog INT, T CHAR(1), Qt INT);
CREATE TABLE b (ID int, Prog INT, T CHAR(1), Qt INT);

    INSERT INTO dbo.a
            ( ID ,Prog ,T ,Qt)
    VALUES  ('a',1,'N',100), ('b',1,'Y',10), ('b',2,'N',90),('c',1,'N',25),('c',2,'Y',25),('c',3,'Y',25),('c',4,'Y',25)
    INSERT INTO dbo.b
            ( ID ,Prog ,T ,Qt)
    VALUES  (1,1,'Y',10),(1,2,'N',90),(2,1,'Y',100),(3,1,'Y',100),(4,1,'Y',50),(4,2,'Y',25),(4,3,'Y',25)

WITH CTEa
AS (SELECT  ID,
            Prog,
            T,
            Qt,
            Cnt = COUNT(ID) OVER (PARTITION BY ID)
    FROM    dbo.a
   ),
     CTEb
AS (SELECT  ID,
            Prog,
            T,
            Qt,
            Cnt = COUNT(ID) OVER (PARTITION BY ID)
    FROM    dbo.b
   )
SELECT  ID_A = a.ID,
        ID_B = b.ID,
        b.Prog,
        b.T,
        b.Qt,
        b.Cnt
FROM    CTEa AS a
  INNER JOIN CTEb AS b
    ON a.Prog = b.Prog
       AND  a.T = b.T
       AND  a.Qt = b.Qt
       AND  a.Cnt = b.Cnt;

结果:

ID_A    ID_B    Prog    T   Qt  Cnt
b       1       1       Y   10  2
b       1       2       N   90  2

【讨论】:

  • 这很有用,我怀疑加入 2 个几十个值可能需要做很多工作,但如果没有其他更好的方法,我会选择这个或 Gordon Linoff 解决方案。谢谢!
  • @MaZe 我认为c4 不应该匹配。
  • @SqlZim 你是完全正确的。我没有检查完整的结果表,只有“b”和“1”是一样的。事实上,现在我明白了,使 Gordon 解决方案更好的原因正是他检查了相同数量的行。谢谢你让我看到!
  • @MaZe 我已更新查询以修复我忽略的条件。
  • @SqlZim 很好。我错过了 c 和 4 不应该是它的一部分。我已经更新了查询来解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2021-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多