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
以及所有 id
的 stop
值的总和具有相同的 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
错误?
你应该可以用 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
应该这样做:
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 行)。您可能希望排除与自身匹配的行。
参考以下正确回答的问题:
在 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
以及所有 id
的 stop
值的总和具有相同的 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
错误?
你应该可以用 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
应该这样做:
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 行)。您可能希望排除与自身匹配的行。