SQLite:如何在使用 CASE 语句时避免使用两个 CTE?
SQLite: How to avoid using two CTE when using CASE statement?
我有一个 table trx
具有以下架构:
| id | p_id |
| 1 | 1 |
| 2 | 1 |
| 3 | 4 |
...
| 1000 | 2 |
其中 id
是交易 ID,p_id
是交易者的 ID。
我需要查询 trx
所以我得到一个 table 允许我绘制交易频率的直方图,这意味着我想知道有多少 p_id
只有 1 笔交易,有多少人做了 2 笔交易,依此类推。我必须在 +10
bin 中汇总 11 笔或更多笔交易:
| n_trx | bin_size |
| 1 | 10 |
| 2 | 18 |
| 3 | 7 |
...
| +10 | 26 |
我知道 +10
需要 CASE
语句,我使用两个 CTE
:
来完成任务
WITH new_trx_history
AS (WITH trx_history
AS (SELECT p_id,
Count(DISTINCT id) AS n_trx
FROM trx
GROUP BY p_id)
SELECT CASE
WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END AS n_trx,
Count(*) AS bin_size
FROM trx_history
GROUP BY n_trx)
SELECT n_trx,
Sum(bin_size)
FROM new_trx_history
GROUP BY n_trx;
我想知道是否有一种比我实际的(working)查询更直接的方法。
这里是SQLFiddle
您可以在 GROUP BY
中使用 CASE
WITH trx_history
AS (SELECT p_id,
Count(DISTINCT id) AS n_trx
FROM trx
GROUP BY p_id)
SELECT CASE
WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END AS n_trx,
Count(*) AS bin_size
FROM trx_history
GROUP BY CASE
WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END
;
如果你使用 COUNT()
window 函数,你可以在没有任何 CTE 的情况下做到这一点:
SELECT DISTINCT
CASE WHEN COUNT(*) >= 10 THEN '+10' ELSE COUNT(*) END AS n_trx,
COUNT(*) OVER (PARTITION BY CASE WHEN COUNT(*) >= 10 THEN '+10' ELSE COUNT(*) END) AS bin_size
FROM trx
GROUP BY p_id
参见demo。
结果:
n_trx | bin_size
----- | --------
3 | 1
6 | 1
+10 | 3
我建议这样写查询:
WITH p as (
SELECT p_id,
Count(*) AS n_trx
FROM trx
GROUP BY p_id
)
SELECT (CASE WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END) AS trx_grp,
Count(*) AS bin_size
FROM p
GROUP BY trx_grp
ORDER BY MIN(n_trx);
备注:
- 您似乎不需要
COUNT(DISTINCT)
CTE。 id
在事务中看起来是独一无二的 table 并且 COUNT(DISTINCT)
会产生额外的开销。
- 您可以在 SQLite 中通过列别名进行聚合。但是,如果它与
FROM
子句中的任何列具有不同的名称会更好。
- 您可以使用聚合功能轻松订购。
- SQLite 允许您在
CASE
表达式中混合类型。这是由于它对类型的神秘处理。任何其他 SQL 方言都会将 '+10'
转换为数字 10
.
我有一个 table trx
具有以下架构:
| id | p_id |
| 1 | 1 |
| 2 | 1 |
| 3 | 4 |
...
| 1000 | 2 |
其中 id
是交易 ID,p_id
是交易者的 ID。
我需要查询 trx
所以我得到一个 table 允许我绘制交易频率的直方图,这意味着我想知道有多少 p_id
只有 1 笔交易,有多少人做了 2 笔交易,依此类推。我必须在 +10
bin 中汇总 11 笔或更多笔交易:
| n_trx | bin_size |
| 1 | 10 |
| 2 | 18 |
| 3 | 7 |
...
| +10 | 26 |
我知道 +10
需要 CASE
语句,我使用两个 CTE
:
WITH new_trx_history
AS (WITH trx_history
AS (SELECT p_id,
Count(DISTINCT id) AS n_trx
FROM trx
GROUP BY p_id)
SELECT CASE
WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END AS n_trx,
Count(*) AS bin_size
FROM trx_history
GROUP BY n_trx)
SELECT n_trx,
Sum(bin_size)
FROM new_trx_history
GROUP BY n_trx;
我想知道是否有一种比我实际的(working)查询更直接的方法。
这里是SQLFiddle
您可以在 GROUP BY
CASE
WITH trx_history
AS (SELECT p_id,
Count(DISTINCT id) AS n_trx
FROM trx
GROUP BY p_id)
SELECT CASE
WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END AS n_trx,
Count(*) AS bin_size
FROM trx_history
GROUP BY CASE
WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END
;
如果你使用 COUNT()
window 函数,你可以在没有任何 CTE 的情况下做到这一点:
SELECT DISTINCT
CASE WHEN COUNT(*) >= 10 THEN '+10' ELSE COUNT(*) END AS n_trx,
COUNT(*) OVER (PARTITION BY CASE WHEN COUNT(*) >= 10 THEN '+10' ELSE COUNT(*) END) AS bin_size
FROM trx
GROUP BY p_id
参见demo。
结果:
n_trx | bin_size
----- | --------
3 | 1
6 | 1
+10 | 3
我建议这样写查询:
WITH p as (
SELECT p_id,
Count(*) AS n_trx
FROM trx
GROUP BY p_id
)
SELECT (CASE WHEN n_trx < 11 THEN n_trx
ELSE '+10'
END) AS trx_grp,
Count(*) AS bin_size
FROM p
GROUP BY trx_grp
ORDER BY MIN(n_trx);
备注:
- 您似乎不需要
COUNT(DISTINCT)
CTE。id
在事务中看起来是独一无二的 table 并且COUNT(DISTINCT)
会产生额外的开销。 - 您可以在 SQLite 中通过列别名进行聚合。但是,如果它与
FROM
子句中的任何列具有不同的名称会更好。 - 您可以使用聚合功能轻松订购。
- SQLite 允许您在
CASE
表达式中混合类型。这是由于它对类型的神秘处理。任何其他 SQL 方言都会将'+10'
转换为数字10
.