【问题标题】:Removing duplicates from SQL query从 SQL 查询中删除重复项
【发布时间】:2014-07-03 04:04:08
【问题描述】:

我正在尝试创建一个不会返回具有相同 ID 的行的 SQL 查询。我还想指定一个主行,以便在两行具有相同 ID 的情况下,将返回主行。如果没有指定主行,我想返回第一行。

这是我要查询的数据库示例。

+----+---------+-------+
| id | primary | label |
+----+---------+-------+
| 1  |    Y    |   A   |
| 1  |         |   B   |  
| 2  |         |   C   |
| 2  |         |   D   |
| 3  |         |   E   |
+----+---------+-------+

这是我想要达到的结果的示例

+----+---------+-------+
| id | primary | label |
+----+---------+-------+
| 1  |    Y    |   A   |
| 2  |         |   C   |
| 3  |         |   E   |
+----+---------+-------+

我一直在尝试使用 select distinct,但我非常不确定解决这个问题的方向。任何帮助是极大的赞赏。谢谢!

【问题讨论】:

  • “第一行”是什么意思?第一个根据标签的字母顺序?如果是这样,标签是否总是不同的?
  • 我的意思是第一行,因为它存在于数据库中。标签只是区分行的一种方式,因此可以更容易地注意到具有相似 id 的行在结果中只出现一次。
  • 如果不按“数据库中存在的第一行”进行排序,则取决于索引/缓存等,它是伪随机的。它不会自行跟踪插入顺序。
  • 不应考虑“存在于数据库中”的行顺序,因为这可能会根据数据库版本等而改变。简而言之 - 这是不稳定的解决方案:) 更好地按标签排序。跨度>
  • 在我的情况下,如果他们有重复的 id 并且没有指定主要的,我选择哪一个并不重要,但我一定会在未来牢记这一点。感谢您的反馈!

标签: mysql sql


【解决方案1】:

在您的情况下,子查询比 DISTINCT 更合适。

试试下面的。以下是它获得所需结果的演示:http://sqlfiddle.com/#!2/97fdd3/1/0

顺便说一句,当 ID 没有“主要”时,这将选择该 ID 的最低标签值。正如其他人所说,这比“数据库中的顺序”更可靠。

select *
  from tbl t
 where t.label = (select x.label
                    from tbl x
                   where x.primary = 'Y'
                     and x.id = t.id)
    or (not exists
        (select 1
           from tbl x
          where x.primary = 'Y'
            and x.id = t.id) and
        t.label = (select min(x.label) from tbl x where x.id = t.id))

【讨论】:

    【解决方案2】:

    我可以看到你已经得到了答案,但你也可以使用普通的LEFT JOIN

    SELECT * FROM mytable a 
    LEFT JOIN mytable b
      ON a.id = b.id AND (
                a.label>b.label AND a.primary IS NULL AND b.primary IS NULL OR 
                                    a.primary IS NULL AND b.primary='Y')
    WHERE b.id IS NULL
    

    An SQLfiddle to test with.

    【讨论】:

    • 感谢您的回复!看到完成任务的多种方法对我的 SQL 学习有好处
    【解决方案3】:
    SELECT a.id, 
           IFNULL(primaries.primary, '') AS primary, 
           IFNULL(primaries.label, secondary.label) AS label
    FROM yourTable AS a
    LEFT JOIN (SELECT *
               FROM yourTable
               WHERE primary = 'Y') AS primaries
    ON a.id = primaries.id AND a.label = primaries.label
    LEFT JOIN (SELECT id, MIN(label) AS label
               FROM yourTable
               WHERE primary != 'Y'
               GROUP BY id) AS secondary
    ON a.id = secondary.id AND a.label = secondary.label
    

    【讨论】:

      【解决方案4】:

      也许这样的东西可以工作(未经测试):

      SELECT DISTINCT
            t1.id
           ,t2.primary
           ,t2.label
      FROM table t1
          LEFT JOIN (
              SELECT id, primary, label
              FROM table
              GROUP BY id
              ORDER BY primary DESC, label ASC
              LIMIT 1
          ) t2 ON t2.id=t1.id
      

      【讨论】:

      • 您的子查询只返回一行,而不是每个 id 的一行。
      猜你喜欢
      • 1970-01-01
      • 2019-12-11
      • 1970-01-01
      • 2020-12-25
      • 2015-08-12
      • 2023-03-17
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多