sql (oracle) count и sum в одном запросе select / where - PullRequest
0 голосов
/ 28 сентября 2018

Со ссылкой на следующий и правильно отвеченный вопрос:
sql (oracle) подсчитывает количество перекрывающихся интервалов

Учитывая следующую таблицу test в базе данных oracle sql:

+----+------+-------+------+
| 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   |
+----+------+-------+------+

Теперь я хотел бы найти количество перекрывающихся интервалов (включая конечные точки) [start, stop] n_overlap, а также сумму значений stop для всех id, имеющихто же самое 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 ошибку?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

Это должно сделать это:

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).Возможно, вы захотите исключить строку, соответствующую самому себе.

0 голосов
/ 28 сентября 2018

Вы должны иметь возможность делать то, что вы хотите с JOIN и GROUP 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
...