【问题标题】:Select rows where there is a one-to-one match between two columns in same table SQL选择同一表 SQL 中两列之间存在一对一匹配的行
【发布时间】:2019-01-23 16:43:18
【问题描述】:

我有一个包含两种类型 ID 列的 SQL 表。例如

ID_1    Name          Date     ID_2
 487     Joe    09/06/2004      332
 731    Mike    06/01/2004      116
 487     Joe    09/06/2004      354
 777    Rich    01/01/2002      455
 745    Mike    06/01/2004      116

有时 ID_1 有多个行,ID_2 具有不同的值。反之亦然,有时 ID_2 有多个行,ID_1 的值不同。

我想保留 ID_1 和 ID_2 之间存在一对一匹配的所有行。理想情况下,我还会用剩余的行制作另一个表格,这样我以后可以轻松查看它们。所以上面的例子中,只有一行(第 4 行)ID_1 和 ID_2 是一对一匹配的:

ID_1    Name          Date     ID_2
 777    Rich    01/01/2002      455

所有其他行都有其中一个 ID 重复的行。所以它基本上是删除任何一个 ID 列重复的行。

我曾尝试使用 DISTINCT,但这会保留其中一个重复的行,而我希望将它们全部删除。

附言这不是关于连接表的问题 - 示例是单个表。

【问题讨论】:

  • 查找 SQL Server JOIN 语句
  • “一对一”匹配是什么意思?期望的结果会有所帮助。
  • 您是否在寻找名称只出现一次的行?因为我在您的数据中看不到 id_1 和 id_2 之间的任何相关性。
  • 我正在使用 sql-server - 我已经添加了这个标签。

标签: sql sql-server distinct


【解决方案1】:
create table #one_to_one
(id_1 int, name varchar(20), dt date, id_2 int)

insert into #one_to_one values( 487,   'Joe',    '09/06/2004'  ,    332)
insert into #one_to_one values( 731,   'Mike',    '06/01/2004' ,     116)
insert into #one_to_one values(487,   'Joe',    '09/06/2004'  ,    354)
insert into #one_to_one values( 777,    'Rich',    '01/01/2002',      455)
insert into #one_to_one values( 745,    'Mike',    '06/01/2004',      116)


select id_1, name, dt, id_2
from (select *, count(*) over(partition by id_1) as id_1_count,
               count(*) over(partition by id_2) as id_2_count
      from #one_to_one) res
where id_1_count = 1 and id_2_count = 1;

【讨论】:

    【解决方案2】:

    你可以使用窗口化的COUNT:

    CREATE TABLE only_one_to_one
    AS
    SELECT ID_1, Name, Date, ID_2
    FROM (SELECT *,COUNT(*) OVER(PARTITION BY ID_1) AS ID1_cnt,
                   COUNT(*) OVER(PARTITION BY ID_2) AS ID2_cnt
          FROM tab) sub
    WHERE ID1_cnt = 1 AND ID2_cnt = 1;
    

    db<>fiddle demo

    【讨论】:

      【解决方案3】:

      只有一对一

      SELECT *
        FROM Table A
       WHERE (SELECT Count(1)
                FROM Table B
               WHERE A.ID_1 = B.ID_1) = 1
         AND (SELECT Count(1)
                FROM Table B
               WHERE A.ID_2 = B.ID_2) = 1
      

      不止一个

      SELECT *
        FROM Table A
       WHERE (SELECT Count(1)
                FROM Table B
               WHERE A.ID_1 = B.ID_1) > 1
          OR (SELECT Count(1)
                FROM Table B
               WHERE A.ID_2 = B.ID_2) > 1
      

      【讨论】:

      • 非常直观的软件!性能怎么样,这可能是大表的问题
      • 这种情况可以用查询“Exists”来实现,我不记得查询是否有更好的性能。 @Siyon.D.P
      【解决方案4】:

      这段代码可以帮到你

      create table #temp (ID_1 int,name varchar(255),[Date] date,ID_2 int)
      insert into #temp values (487  ,  'Joe','09/06/2004', 332)
      insert into #temp values (731  , 'Mike' ,  '06/01/2004'  ,    116   )
      insert into #temp values (487  , ' Joe' ,  '09/06/2004'  ,    354   )
      insert into #temp values (777  , 'Rich' ,  '01/01/2002'  ,    455   )
      insert into #temp values (745  , 'Mike' ,  '06/01/2004'  ,    116   )
      
      
      Select * from (
      Select ROW_NUMBER() OVER(ORDER BY id_1 DESC)  AS Row#,ID_1,Name,Date,ID_2 
      FROM #temp
      
      ) as T 
      
      Where Row# = 4
      Drop table #temp
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-16
        • 1970-01-01
        • 1970-01-01
        • 2022-09-23
        • 2015-04-14
        • 2017-01-08
        • 2021-02-22
        • 2022-11-28
        相关资源
        最近更新 更多