sql (oracle) 在同一个 select/where 查询中计数和求和

sql (oracle) count and sum within the same select/where query

参考以下正确回答的问题:

在 oracle sql 数据库中给出以下 table 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 以及所有 idstop 值的总和具有相同的 name,即:

+----+------+-------+------+-----------+------------+
| 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 错误?

你应该可以用 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

应该这样做:

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 行)。您可能希望排除与自身匹配的行。