【问题标题】:Selecting unique rows in a set of two possibilities在一组两种可能性中选择唯一行
【发布时间】:2010-09-14 02:48:39
【问题描述】:

问题本身很简单,但我想不出在一个查询中解决问题的解决方案,这是我对问题的“抽象”,以便进行更简单的解释:

我会保留我原来的解释,但这里有一组示例数据和我期望的结果:

好的,这里有一些示例数据,我用空行分隔对

-------------
| Key |  Col | (Together they from a Unique Pair)
--------------
|  1     Foo |
|  1     Bar |
|            |
|  2     Foo |
|            |
|  3     Bar |
|            |
|  4     Foo |
|  4     Bar |
--------------

我期望的结果是,运行一次查询后,它需要能够在一个查询中选择这个结果集:

1 - Foo
2 - Foo
3 - Bar
4 - Foo

原文解释:

我有一张表,称之为TABLE,其中我有两列IDNAME,它们共同构成了表的主键。现在我想选择ID=1 的位置,然后首先检查它是否可以找到NAME 具有值“John”的行,如果“John”不存在,它应该查找NAME 为“ Bruce” - 但仅在“Bruce”和“John”都存在或当然只有“John”存在时才返回“John”。

还要注意,它应该能够为每个查询返回几行匹配上述条件但当然具有不同的 ID/名称组合,并且上述解释只是对实际问题的简化。

我可能完全被自己的代码和思路所蒙蔽,但我就是想不通。

【问题讨论】:

  • 您能举个例子澄清一下这个问题吗?即提供最少的数据集以及您希望从中获得的解决方案?
  • 您要求答案的跨平台程度如何?我可以想出一些可以在 SQL Server 中工作,但在 MySQL 中不行的东西......
  • Georgi:我用一些示例数据阐明了这个例子,我在一次查询后期望得到的结果 AviewAnew:任何事情都有帮助

标签: sql mysql sql-server database postgresql


【解决方案1】:

不需要太复杂,你可以使用MAX()group by ...

select id, max(col) from foo group by id

【讨论】:

    【解决方案2】:

    您可以使用这样的 OUTER JOIN 将初始表连接到自身:

    create table #mytest
       (
       id           int,
       Name         varchar(20)
       );
    go
    
    insert into #mytest values (1,'Foo');
    insert into #mytest values (1,'Bar');
    insert into #mytest values (2,'Foo');
    insert into #mytest values (3,'Bar');
    insert into #mytest values (4,'Foo');
    insert into #mytest values (4,'Bar');
    go
    
    select distinct
       sc.id,
       isnull(fc.Name, sc.Name) sel_name
    from
       #mytest sc
    
       LEFT OUTER JOIN #mytest fc
          on (fc.id = sc.id
              and fc.Name = 'Foo')
    

    这样。

    【讨论】:

    • 我在 mysql 中尝试此操作时似乎出现错误,仅限 postgre?
    • 我在 SQL Server 2005 中测试过。
    【解决方案3】:

    这是一个适用于 SQL Server 2005 及更高版本的示例。这是一个有用的模式,您希望根据自定义排序选择顶行(或前 n 行)。这将使您不仅可以在具有自定义优先级的两个值中进行选择,还可以选择任何数字。您可以使用 ROW_NUMBER() 函数和 CASE 表达式:

    CREATE TABLE T (id int, col varchar(10));
    
    INSERT T VALUES (1, 'Foo')
    INSERT T VALUES (1, 'Bar')
    INSERT T VALUES (2, 'Foo')
    INSERT T VALUES (3, 'Bar')
    INSERT T VALUES (4, 'Foo')
    INSERT T VALUES (4, 'Bar')
    
    SELECT id,col
    FROM 
    (SELECT id, col,
        ROW_NUMBER() OVER (
        PARTITION BY id 
        ORDER BY 
        CASE col 
        WHEN 'Foo' THEN 1
        WHEN 'Bar' THEN 2 
        ELSE 3 END
        ) AS RowNum 
        FROM T
    ) AS X
    WHERE RowNum = 1
    ORDER BY id
    

    【讨论】:

      【解决方案4】:

      您可以使用连接而不是存在,这可能会在优化器不够智能的情况下改进查询计划:

      SELECT f1.id
        ,f1.col
      FROM foo f1 
      LEFT JOIN foo f2
        ON f1.id = f2.id
        AND f2.col = 'Foo'
      WHERE f1.col = 'Foo' 
        OR ( f1.col = 'Bar' AND f2.id IS NULL )
      

      【讨论】:

        【解决方案5】:

        这与您编写的内容非常相似,但应该相当快,因为​​在这种情况下,NOT EXISTS 比 NOT IN... 更有效。

        mysql> select * from foo;
        +----+-----+
        | id | col |
        +----+-----+
        |  1 | Bar | 
        |  1 | Foo | 
        |  2 | Foo | 
        |  3 | Bar | 
        |  4 | Bar | 
        |  4 | Foo | 
        +----+-----+
        
        SELECT id
             , col
          FROM foo f1 
         WHERE col = 'Foo' 
          OR ( col = 'Bar' AND NOT EXISTS( SELECT * 
                                             FROM foo f2
                                            WHERE f1.id  = f2.id 
                                              AND f2.col = 'Foo' 
                                         ) 
             ); 
        
        +----+-----+
        | id | col |
        +----+-----+
        |  1 | Foo | 
        |  2 | Foo | 
        |  3 | Bar | 
        |  4 | Foo | 
        +----+-----+
        

        【讨论】:

          【解决方案6】:

          在 PostgreSQL 中,我相信会是这样的:

          SELECT DISTINCT ON (id) id, name
          FROM mytable
          ORDER BY id, name = 'John' DESC;
          

          更新 - 在真之前的错误排序 - 我最初是倒退的。请注意,DISTINCT ON 是 PostgreSQL 功能,而不是标准 SQL 的一部分。这里发生的是它只向您显示它遇到的任何给定 id 的第一行。由于我们按天气排序,名称为 John,因此将选择名为 John 的行而不是所有其他名称。

          你的第二个例子是:

          SELECT DISTINCT ON (key) key, col
          FROM mytable
          ORDER BY key, col = 'Foo' DESC;
          

          这会给你:

          1 - Foo
          2 - Foo
          3 - Bar
          4 - Foo
          

          【讨论】:

            【解决方案7】:

            好的,这里有一些示例数据,我用空行分隔对

            -------------
            | Key |  Col | (Together they from a Unique Pair)
            --------------
            |  1     Foo |
            |  1     Bar |
            |            |
            |  2     Foo |
            |            |
            |  3     Bar |
            |            |
            |  4     Foo |
            |  4     Bar |
            --------------
            

            我期望的结果:

            1 - Foo
            2 - Foo
            3 - Bar
            4 - Foo
            

            我确实在上面解决了这个问题,但是对于较大的表,该查询的效率非常低,还有其他方式吗?

            【讨论】:

              【解决方案8】:

              我自己想出了一个解决方案,但它有点复杂和缓慢 - 它也不能很好地扩展到更高级的查询:

              SELECT *
              FROM users
              WHERE name = "bruce"
              OR (
                  name = "john"
                  AND NOT id
                  IN (
                      SELECT id
                      FROM posts
                      WHERE name = "bruce"
                  )
              )
              

              没有重连接等没有替代方案?

              【讨论】:

                【解决方案9】:

                试试这个:

                select top 1 * from (
                SELECT 1 as num, * FROM TABLE WHERE ID = 1 AND NAME = 'John'
                union 
                SELECT 2 as num, * FROM TABLE WHERE ID = 1 AND NAME = 'Bruce'
                ) t
                order by num 
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-05-18
                  • 1970-01-01
                  • 2017-02-23
                  相关资源
                  最近更新 更多