【问题标题】:Select all rows, with specific characteristics, with same subdata by grouping them through a same row value in oracle通过在 oracle 中通过相同的行值对它们进行分组来选择具有特定特征和相同子数据的所有行
【发布时间】:2016-04-25 07:42:22
【问题描述】:

我有一个具有下一个结构的表:

Data structure: 
| CONTRACT | CONNECTION | STATE |
|    1     |    AAA     |   Y   |
|    2     |    AAA     |   Y   |
|    3     |    BBB     |   N   |
|    4     |    BBB     |   N   |
|    5     |    BBB     |   N   |
|    6     |    BBB     |   N   |
|    7     |    AAA     |   Y   |
|    8     |    CCC     |   Y   |
|    9     |    CCC     |   N   |
|    10    |    AAA     |   Y   |
|    11    |    CCC     |   N   |

我想选择所有行/数据,考虑到由 CONNECTION 列定义为组 AAA、BBB 和 CCC 的组,查询必须仅选择具有状态的 所有 行的组值为“N”的列,但始终考虑该组的所有数据。 所以桌子上的结果是:

Result needed: 
| CONTRACT | CONNECTION | STATE |
|    3     |    BBB     |   N   |
|    4     |    BBB     |   N   |
|    5     |    BBB     |   N   |
|    6     |    BBB     |   N   |

我一直在寻找解码、存在等功能,但只是不知道如何解决这个问题。

知道如何为此目的编写查询吗?

【问题讨论】:

  • 非常感谢大家。我试过 Felix Pamittan 答案,效果很好。
  • 所有 3 种解决方案都应该工作,但 Giorgos Betsos' Answer 只会扫描表/索引一次,而使用 INNOT EXISTS 并且相关的子查询将扫描子中的表/索引查询和外部查询,可能会做更多的 IO。如果您查看两个查询的解释计划,您可以自己计算表(或索引)扫描的数量,并可以查看每个解决方案的不同 IO 量。

标签: sql oracle group-by subquery


【解决方案1】:

试试这个:

SELECT CONTRACT, CONNECTION, STATE
FROM (
  SELECT CONTRACT, CONNECTION, STATE,
         COUNT(CASE WHEN STATE <> 'N' THEN 1 END) OVER (PARTITION BY CONNECTION) AS cnt
  FROM mytable) t
WHERE t.cnt  = 0

【讨论】:

    【解决方案2】:

    您可以使用SUMHAVING

    ONLINE DEMO

    SELECT *
    FROM tbl t
    WHERE
        CONNECTION IN(
            SELECT CONNECTION
            FROM tbl
            GROUP BY CONNECTION
            HAVING
                SUM(CASE WHEN STATE = 'N' THEN 1 ELSE 0 END) > 0
                AND SUM(CASE WHEN STATE <> 'N' THEN 1 ELSE 0 END) = 0
        )
    

    HAVING 子句中的第一个条件确保CONNECTION 至少有一个STATE = 'N'。第二个确保CONNECTION 除了'N' 之外没有其他STATEs。

    【讨论】:

    • SUM(CASE WHEN STATE = 'N' THEN 1 ELSE 0 END) &gt; 0 是多余的,因为必须至少存在一行作为分组依据,并且您已经使用 SUM(CASE WHEN STATE &lt;&gt; 'N' THEN 1 ELSE 0 END) = 0 过滤器排除了所有其他状态。
    【解决方案3】:

    你可以使用窗口化的COUNT:

    WITH cte AS (
      SELECT *
       ,COUNT(CASE WHEN STATE = 'N' THEN 1 END) OVER(PARTITION BY CONNECTION) AS num_of_n
       ,COUNT(CASE WHEN STATE <> 'N' OR STATE IS NULL THEN 1 END) 
              OVER(PARTITION BY CONNECTION) AS num_of_non_n
      FROM mytable
    )
    SELECT CONTRACT, CONNECTION, STATE
    FROM cte
    WHERE num_of_n > 0 AND num_of_non_n = 0;
    

    LiveDemo


    或相关子查询:

    SELECT *
    FROM mytable m1
    WHERE STATE = 'N'
      AND NOT EXISTS (SELECT 1
                      FROM mytable m2
                      WHERE m1.CONNECTION = m2.CONNECTION
                        AND (STATE <> 'N' OR STATE IS NULL));
    

    LiveDemo 2

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-25
      • 1970-01-01
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多