【问题标题】:SQL Select any other records if exist and select default if no othersSQL 如果存在则选择任何其他记录,如果没有其他记录则选择默认值
【发布时间】:2016-11-30 10:52:18
【问题描述】:

如果存在任何其他多条记录(不包括值 9999),我希望选择它 - 如果除了值为 9999 的一条记录之外不存在其他记录,则只需返回该一条记录。

换句话说,想象一下:

  | FIELD1 | FIELD2 | FIELD3 |
1.|  AAA   | BBB    | 1234   |
2.|  AAA   | BCB    | 1234   |
3.|  AAA   | ABB    | 1234   |
4.|  AAA   | BDB    | 9999   |
5.|  AAA   | SDD    | 1234   |

所以,我只想要第 1、2、3 和 5 行,其中 FIELD1 = 'AAA' 而不是第 4 行。如果在 FIELD1 = 'AAA' 和 FIELD3 = '9999' 的地方不存在其他行,那么它应该只返回那个一个。

【问题讨论】:

  • 标签sql 不够用。请用实际的 RDBMS(产品和版本)标记

标签: sql oracle


【解决方案1】:

如果我猜对了:

SELECT * 
FROM TestTable as T
WHERE 
(
  (Field3 <>9999) 
  OR
  ( 
    (Field3 = 9999) 
    AND 
    NOT EXISTS (SELECT * FROM TestTable 
                 WHERE Field1 = T.Field1 AND Field3 <>9999)
   ) 
 );

对于表:

AAA BBB 1234
AAA BCB 1234
AAA ABB 1234
AAA BDB 9999
AAA SDD 1234
BBB BDB 9999
CCC BBB 1234
CCC BCB 1234
CCC ABB 1234
CCC BDB 9999
CCC SDD 1234

输出将是:

AAA BBB 1234
AAA BCB 1234
AAA ABB 1234
AAA SDD 1234
BBB BDB 9999
CCC BBB 1234
CCC BCB 1234
CCC ABB 1234
CCC SDD 1234

【讨论】:

  • 工作如梦!
  • 非常感谢!
  • @valex 您可以删除该存在子句;这有点毫无意义,因为如果您有一行带有 field3 != 9999 那么您会自动知道该 field1 的表中存在一行带有 field3 != 9999 的行!这会将对表的调用次数减少到 2 次,而不是 3 次。
【解决方案2】:

您可以使用 UNIONNOT EXISTS() 来做到这一点:

SELECT * FROM YourTable t
WHERE t.field3 <> 9999
UNION ALL
SELECT * FROM YourTable s
WHERE s.field3 = 9999
  AND NOT EXISTS(SELECT 1 FROM YourTable p
                 WHERE p.field1 = s.field1
                   AND s.field2 <> 9999)

【讨论】:

    【解决方案3】:
    CREATE TABLE #Table( FIELD1 VARCHAR(100), FIELD2 VARCHAR(100) ,FIELD3 INT)
    INSERT INTO #Table( FIELD1 , FIELD2  ,FIELD3)
    SELECT 'AAA','BBB',1234 UNION ALL
    SELECT 'AAA','BCB',1234 UNION ALL
    SELECT 'AAA','ABB',1234 UNION ALL
    SELECT 'AAA','BDB',9999 UNION ALL
    SELECT 'AAA','SDD',1234   
    
    SELECT * FROM #Table T1
    WHERE FIELD3 = (SELECT FIELD3 FROM #Table T2 GROUP BY FIELD3 HAVING COUNT(*)     
    > 1)
    

    【讨论】:

    • 只有9999条记录不返回结果
    【解决方案4】:

    如果您使用的是 SQL SERVER,那么您可以使用 IF ELSE 来实现这一点,我将您的表命名为 TAB,请相应更改。

    IF EXISTS (SELECT FIELD3 FROM TAB WHERE FIELD3=9999)
    BEGIN
    SELECT * FROM TAB WHERE FIELD3=9999
    END
    ELSE
    BEGIN
    SELECT * FROM TAB
    END
    

    【讨论】:

    • 即使OP使用SQL Server,这点目前还不清楚,在可以使用SQL的地方使用T-SQL也是有问题的路径
    【解决方案5】:

    最简单的答案。


    选项 1

    select      *
    
    from        t
    
    where       field3 <> 9999
             or not exists (select null from t t2 where t2.field1 = t.field1 and field3 <> 9999)
    ;
    

    选项 2

    select      *
    
    from       (select      *
                           ,min (case when field3 <> 9999 then 1 end) over 
                                    (partition by field1)    as field3_no_9999_flag
    
                from        t
                )
    
    where       field3              <> 9999
            or  field3_no_9999_flag is null            
    ;       
    

    【讨论】:

      【解决方案6】:

      这是一个只访问表一次,但使用解析函数的解决方案:

      WITH testtable AS (SELECT 'AAA' field1, 'BBB' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'AAA' field1, 'BCB' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'AAA' field1, 'ABB' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'AAA' field1, 'BDB' field2, 9999 field3 FROM dual UNION ALL
                         SELECT 'AAA' field1, 'SDD' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'BBB' field1, 'BDB' field2, 9999 field3 FROM dual UNION ALL
                         SELECT 'CCC' field1, 'BBB' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'CCC' field1, 'BCB' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'CCC' field1, 'ABB' field2, 1234 field3 FROM dual UNION ALL
                         SELECT 'CCC' field1, 'SDD' field2, 1234 field3 FROM dual)
      SELECT field1,
             field2,
             field3
      FROM   (SELECT field1,
                     field2,
                     field3,
                     COUNT(CASE WHEN field3 != 9999 THEN field3 END) OVER (PARTITION BY field1) cnt_non_default
              FROM   testtable)
      WHERE  field3 != 9999
      OR     cnt_non_default = 0;
      
      FIELD1 FIELD2     FIELD3
      ------ ------ ----------
      AAA    BBB          1234
      AAA    BCB          1234
      AAA    ABB          1234
      AAA    SDD          1234
      BBB    BDB          9999
      CCC    BBB          1234
      CCC    BCB          1234
      CCC    ABB          1234
      CCC    SDD          1234
      

      这可能会或可能不会比访问该表两次或更多次的其他建议答案更有效 - 您需要针对您的表和(适当数量的)数据进行测试,看看哪个最适合您。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-29
        • 2020-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多