【问题标题】:How to select unique records by SQL如何通过 SQL 选择唯一记录
【发布时间】:2010-12-11 03:12:50
【问题描述】:

当我执行SELECT * FROM table 时,我得到如下结果:

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

如您所见,column2 中有重复记录(item1 已重复)。那么我怎么能得到这样的结果:

1 item1 data1
2 item2 data3
3 item3 data4

只有一条记录从重复中返回,以及其余的唯一记录。

【问题讨论】:

  • 第 1 项在技术上没有重复。如图所示,第 1 行和第 2 行是独特的观察结果。如果您想保留第 2 行而不是第 1 行怎么办?

标签: sql database


【解决方案1】:

使用带有单列名称和多列名称的 distinct 关键字,您可以获得不同的记录:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;

【讨论】:

  • 会不会是答案真的错了? DISTINCT 应​​用于所有选定的列(至少在 DB2 上),它仍然会在各个列中返回重复值。
  • 是的,DISTINCT 不会给出所需的结果(至少在 Postgres 上),因为它应用于所有选择列,而不仅仅是此答案中指定的 column1
  • 这在 Bigquery 中不起作用
【解决方案2】:

如果您只需要删除重复项,请使用DISTINCTGROUP BY 应该用于将聚合运算符应用于每个组

GROUP BY v DISTINCT

【讨论】:

    【解决方案3】:

    这取决于您要为每个独特的项目返回哪个行。您的数据似乎表明了 SQL Server 实例中的最小数据值。

    SELECT item, min(data)
    FROM  table
    GROUP BY item
    

    【讨论】:

      【解决方案4】:

      我发现如果我因任何原因不能使用 DISTINCT,那么 GROUP BY 将起作用。

      【讨论】:

        【解决方案5】:

        要获得结果中的所有列,您需要放置以下内容:

        SELECT distinct a, Table.* FROM Table
        

        它将 a 作为第一列,其余列将按照与您的定义相同的顺序排列。也就是说,列 a 将被重复。

        【讨论】:

        • 你确定吗?我在 w3schools 上尝试过,它返回的结果与 SELECT * 相同,除了 a 是第一列
        • @Freakishly 是的,这正是我的回答中所说的:/
        • 这行不通,你不能像这样在 distinct 之后选择 *(你会得到一个 1064 错误 - 你的 SQL 语法错误)
        • @Mohsinkhan 好吧,我忘了放置你需要写表名的地方。不知何故,当我写这个的时候,它工作了,但我现在才测试,它并没有在 * 之前没有表名
        • 这个和select distinct * from ...一模一样
        【解决方案6】:

        选择 Eff_st 从 ( 选择 EFF_ST,ROW_NUMBER() over(PARTITION BY eff_st) XYZ - 来自 ABC.CODE_DIM

        ) 其中 XYZ= 1 按 EFF_ST 排序,仅获取前 5 行

        【讨论】:

          【解决方案7】:

          只使用内连接,因为 group by 不能用于表示不包含在任一聚合函数中的多个列。

          SELECT a.*
          FROM yourtable a
          INNER JOIN 
            (SELECT yourcolumn,
              MIN(id) as id
            FROM yourtable 
            GROUP BY yourcolumn
          ) AS b
            ON a.yourcolumn= b.yourcolumn
            AND a.id = b.id;
          

          【讨论】:

          • 这是另一个问题的答案,可能应该用greatest-n-per-group标记
          • 这和 Dave Baker 的解决方案是 SO 问题的正确解决方案。此解决方案的优点是它允许选择仅具有某些指定不同列的行,并且必须定义一列 MIN(id) AS id 才能仅选择多个指定列中的一个。
          【解决方案8】:

          您可以使用 4 种方法:

          1. 不同
          2. 分组依据
          3. 子查询
          4. 带有 ROW_NUMBER() 的公用表表达式 (CTE)

          考虑以下带有测试数据的示例TABLE

          /** Create test table */
          CREATE TEMPORARY TABLE dupes(word text, num int, id int);
          
          /** Add test data with duplicates */
          INSERT INTO dupes(word, num, id)
          VALUES ('aaa', 100, 1)
                ,('bbb', 200, 2)
                ,('ccc', 300, 3)
                ,('bbb', 400, 4)
                ,('bbb', 200, 5)     -- duplicate
                ,('ccc', 300, 6)     -- duplicate
                ,('ddd', 400, 7)
                ,('bbb', 400, 8)     -- duplicate
                ,('aaa', 100, 9)     -- duplicate
                ,('ccc', 300, 10);   -- duplicate
          

          选项 1:选择 DISTINCT

          这是最简单直接,但也是最有限的方式:

          SELECT DISTINCT word, num 
          FROM    dupes
          ORDER BY word, num;
          
          /*
          word|num|
          ----|---|
          aaa |100|
          bbb |200|
          bbb |400|
          ccc |300|
          ddd |400|
          */
          

          选项 2:分组方式

          分组允许您添加聚合数据,例如min(id)max(id)count(*) 等:

          SELECT  word, num, min(id), max(id), count(*)
          FROM    dupes
          GROUP BY word, num
          ORDER BY word, num;
          
          /*
          word|num|min|max|count|
          ----|---|---|---|-----|
          aaa |100|  1|  9|    2|
          bbb |200|  2|  5|    2|
          bbb |400|  4|  8|    2|
          ccc |300|  3| 10|    3|
          ddd |400|  7|  7|    1|
          */
          

          选项 3:子查询

          使用子查询,您可以首先识别要忽略的重复行,然后在外部查询中使用WHERE NOT IN (subquery) 构造将它们过滤掉:

          /** Find the higher id values of duplicates, distinct only added for clarity */
              SELECT  distinct d2.id
              FROM    dupes d1
                  INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
              WHERE d2.id > d1.id
          
          /*
          id|
          --|
           5|
           6|
           8|
           9|
          10|
          */
          
          /** Use the previous query in a subquery to exclude the dupliates with higher id values */
          SELECT  *
          FROM    dupes
          WHERE   id NOT IN (
              SELECT  d2.id
              FROM    dupes d1
                  INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
              WHERE d2.id > d1.id
          )
          ORDER BY word, num;
          
          /*
          word|num|id|
          ----|---|--|
          aaa |100| 1|
          bbb |200| 2|
          bbb |400| 4|
          ccc |300| 3|
          ddd |400| 7|
          */
          

          选项 4:使用 ROW_NUMBER() 的公用表表达式

          在公用表表达式 (CTE) 中,选择 ROW_NUMBER(),按组列分区并按所需顺序排序。然后只选择有ROW_NUMBER() = 1的记录:

          WITH CTE AS (
              SELECT  *
                     ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
              FROM    dupes
          )
          SELECT  word, num, id 
          FROM    cte
          WHERE   row_num = 1
          ORDER BY word, num;
          
          /*
          word|num|id|
          ----|---|--|
          aaa |100| 1|
          bbb |200| 2|
          bbb |400| 4|
          ccc |300| 3|
          ddd |400| 7|
          */
          

          【讨论】:

            【解决方案9】:

            我不确定接受的答案是否有效。它至少不适用于postgres 12DISTINCT 关键字应该应用于select 查询中的所有列,而不仅仅是写入DISTINCT 关键字旁边的列。因此,基本上,这意味着结果中返回的每一行在select 查询列的组合方面都是唯一的。在 OP 的问题中,以下两个结果行已经不同,因为它们的 column1 和 column 3 具有不同的值。

            1 item1 data1
            2 item1 data2
            

            现在,回答这个问题,至少在postgres 中有一个DISTINCT ON 关键字。这将达到 OP 的要求。

            select DISTINCT ON(column2) column1, column3 from Table1;

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-01-21
              • 1970-01-01
              • 2021-02-14
              • 2023-01-18
              • 2018-09-13
              • 1970-01-01
              • 1970-01-01
              • 2021-07-21
              相关资源
              最近更新 更多