【问题标题】:sql (oracle) count and sum within the same select/where querysql (oracle) 在同一个 select/where 查询中计数和求和
【发布时间】:2019-03-04 12:22:15
【问题描述】:

参考以下并正确回答的问题:
sql (oracle) counting number of overlapping intervals

给定oracle sql数据库中的下表test

+----+------+-------+------+
| id | name | start | stop |
+----+------+-------+------+
| 1  |   A  |   1   |  5   |
+----+------+-------+------+
| 2  |   A  |   2   |  6   |
+----+------+-------+------+
| 3  |   A  |   5   |  8   |
+----+------+-------+------+
| 4  |   A  |   9   |  10  |
+----+------+-------+------+
| 5  |   B  |   3   |  6   |
+----+------+-------+------+
| 6  |   B  |   4   |  8   |
+----+------+-------+------+
| 7  |   B  |   1   |  2   |
+----+------+-------+------+

我现在想找出重叠间隔的数量(包括端点)[开始,停止]n_overlap 以及所有id 具有相同namestop 值的总和,即:

+----+------+-------+------+-----------+------------+
| id | name | start | stop | n_overlap | sum_stops  |
+----+------+-------+------+-----------+------------+
| 1  |   A  |   1   |  5   |     3     |    19      |
+----+------+-------+------+-----------+------------+
| 2  |   A  |   2   |  6   |     3     |    19      |
+----+------+-------+------+-----------+------------+
| 3  |   A  |   4   |  8   |     3     |    19      |
+----+------+-------+------+-----------+------------+
| 4  |   A  |   9   |  10  |     1     |    10      |
+----+------+-------+------+-----------+------------+
| 5  |   B  |   3   |  6   |     2     |    14      |
+----+------+-------+------+-----------+------------+
| 6  |   B  |   4   |  8   |     2     |    14      |
+----+------+-------+------+-----------+------------+
| 7  |   B  |   1   |  2   |     1     |     2      |
+----+------+-------+------+-----------+------------+

我尝试了这个解决方案,它有效:

select t.*,
   (select count(*)
    from test t2
    where t2.name = t.name and
          t2.start <= t.stop and
          t2.stop >= t.start
   ) as n_overlap,
   (select sum(stop)
    from test t2
    where t2.name = t.name and
          t2.start <= t.stop and
          t2.stop >= t.start
   ) as sum_stops 
from test t;

但是,有没有办法压缩两个 select/where 查询,使用例如:

select t.*,
   (select count(*) as n_overlap, sum(stop) as sum_stops
    from test t2
    where t2.name = t.name and
          t2.start <= t.stop and
          t2.stop >= t.start
   ) 
from test t;

会引发too many values 错误?

【问题讨论】:

    标签: sql oracle select count where


    【解决方案1】:

    你应该可以用JOINGROUP BY 做你想做的事:

    SELECT t.id, t.name, t.start, t.stop, COUNT(t2.name) AS n_overlap, SUM(t2.stop) AS sum_stops
    FROM test t
    LEFT JOIN test t2 ON t2.name = t.name AND t2.start <= t.stop AND t2.stop >= t.start
    GROUP BY t.id, t.name, t.start, t.stop
    

    输出:

    id  name    start   stop    n_overlap   sum_stops
    1   A       1       5       3           19
    2   A       2       6       3           19
    3   A       5       8       3           19
    4   A       9       10      1           10
    5   B       3       6       2           14
    6   B       4       8       2           14
    7   B       1       2       1           2
    

    【讨论】:

    • 谢谢@Nick。它给出了一个错误not a GROUP BY expression,但如果我从SELECT 中删除t.* 就可以了
    • 对不起,习惯了 MySQL 松懈的GROUP BY 规则。如果您想要所有 t.* 值(不仅仅是 id),您应该能够将它们全部放在 GROUP BY 例如GROUP BY t.id, t.name, t.start, t.stop
    • 谢谢@Nick。如果我明确列出SELECTGROUP BY 中的所有列/值,它会起作用,但如果我只是使用SELECT t.*, COUNT(t2.name) AS...GROUP BY t.*,它不会,当有很多列/值时,这可能是一个问题.
    • @MarcoC 我已经编辑了我的答案以反映这一点。正如您所说,当有很多列和值时,这很痛苦。解决这个问题的唯一方法是使用 Salman 在他的回答中提出的子查询。您可能想接受这一点。
    【解决方案2】:

    应该这样做:

    SELECT test.*, n_overlap, sum_stops
    FROM test
    LEFT JOIN (
        SELECT m.id, COUNT(o.id) AS n_overlap, SUM(o.stop) AS sum_stops
        FROM test AS m
        INNER JOIN test AS o ON
            /* m.id <> o.id AND */
            m.name = o.name AND
            m.stop >= o.start AND
            o.stop >= m.start
        GROUP BY m.id
    ) AS sq ON test.id = sq.id
    

    我可能会补充一点,您的预期输出会考虑任何给定的行与其自身重叠(参见第 4 行)。您可能希望排除匹配自身的行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-09
      • 2021-07-17
      • 1970-01-01
      • 2017-09-24
      相关资源
      最近更新 更多