SQL从generate_series中选择,按用户_id筛选删除序列?
在postgresql 9.2.4中,我有一个复杂的SQL查询,使用generate_系列和多个联接。我需要从练习表中计算某一天所有练习的重复次数,并确保这些练习属于当前用户完成的训练。最后,我需要将该表连接到一个序列以显示缺失的日期(使用generate_series) 我的想法是在from子句中选择序列,然后将序列左键连接到一个子查询,该子查询的结果在练习和训练表之间进行内部连接。例如,我有以下查询:SQL从generate_series中选择,按用户_id筛选删除序列?,sql,join,aggregate-functions,postgresql-9.2,generate-series,Sql,Join,Aggregate Functions,Postgresql 9.2,Generate Series,在postgresql 9.2.4中,我有一个复杂的SQL查询,使用generate_系列和多个联接。我需要从练习表中计算某一天所有练习的重复次数,并确保这些练习属于当前用户完成的训练。最后,我需要将该表连接到一个序列以显示缺失的日期(使用generate_series) 我的想法是在from子句中选择序列,然后将序列左键连接到一个子查询,该子查询的结果在练习和训练表之间进行内部连接。例如,我有以下查询: SELECT DISTINCT date_trunc('day', series
SELECT
DISTINCT date_trunc('day', series.date)::date as date,
sum(COALESCE(reps, 0)) OVER WIN,
array_agg(workout_id) OVER WIN as ids
FROM (
select generate_series(-22, 0) + current_date as date
) series
LEFT JOIN (
exercises INNER JOIN workouts
ON exercises.workout_id = workouts.id
)
ON series.date = exercises.created_at::date
WINDOW
WIN AS (PARTITION BY date_trunc('day', series.date)::date)
ORDER BY date ASC;
这将提供以下输出:
date | sum | ids
------------+-----+---------------------------------------------------------
2013-04-27 | 0 | {NULL}
2013-04-28 | 432 | {49,48,47,46,45,44,43,42,41,38,37,36,36,36,36,35,34,33}
2013-04-29 | 0 | {NULL}
2013-04-30 | 20 | {50}
2013-05-01 | 0 | {NULL}
2013-05-02 | 0 | {NULL}
2013-05-03 | 0 | {NULL}
2013-05-04 | 0 | {NULL}
2013-05-05 | 0 | {NULL}
2013-05-06 | 0 | {NULL}
2013-05-07 | 40 | {51,51}
2013-05-08 | 0 | {NULL}
2013-05-09 | 0 | {NULL}
2013-05-10 | 0 | {NULL}
2013-05-11 | 0 | {NULL}
2013-05-12 | 0 | {NULL}
2013-05-13 | 0 | {NULL}
2013-05-14 | 0 | {NULL}
2013-05-15 | 0 | {NULL}
2013-05-16 | 20 | {52}
2013-05-17 | 0 | {NULL}
2013-05-18 | 0 | {NULL}
2013-05-19 | 0 | {NULL}
(23 rows)
但是,我想按某些条件进行过滤:
WHERE workouts.user_id = 5
比如说
但是,如果我在上面的查询中加入WHERE子句并使用该条件,则输出如下:
date | sum | ids
------------+-----+---------------------------------------------------------
2013-04-28 | 432 | {49,48,47,46,45,44,43,42,41,38,37,36,36,36,36,35,34,33}
2013-04-30 | 20 | {50}
2013-05-07 | 40 | {51,51}
2013-05-16 | 20 | {52}
(4 rows)
这部连续剧结束了
如何按用户id筛选并保留序列?如果有任何帮助,我们将不胜感激。您不必从训练表中获取所有数据,也可以将此条件作为参考-
SELECT
DISTINCT date_trunc('day', series.date)::date as date,
sum(COALESCE(reps, 0)) OVER WIN,
array_agg(workout_id) OVER WIN as ids
FROM (
select generate_series(-22, 0) + current_date as date
) series
LEFT JOIN (
exercises INNER JOIN (select * from workouts where user_id = 5) workout
ON exercises.workout_id = workouts.id
)
ON series.date = exercises.created_at::date
WINDOW
WIN AS (PARTITION BY date_trunc('day', series.date)::date)
ORDER BY date ASC;
我认为这应该给你你想要的输出。你可以把这个条件也放在那里,而不是从训练表中获取所有数据-
SELECT
DISTINCT date_trunc('day', series.date)::date as date,
sum(COALESCE(reps, 0)) OVER WIN,
array_agg(workout_id) OVER WIN as ids
FROM (
select generate_series(-22, 0) + current_date as date
) series
LEFT JOIN (
exercises INNER JOIN (select * from workouts where user_id = 5) workout
ON exercises.workout_id = workouts.id
)
ON series.date = exercises.created_at::date
WINDOW
WIN AS (PARTITION BY date_trunc('day', series.date)::date)
ORDER BY date ASC;
我认为这应该给你你想要的输出
我有一个复杂的SQL查询
的确,你知道。但是它不必是那样的:
SELECT s.day
,COALESCE(sum(w.reps), 0) AS sum_reps -- assuming reps comes from workouts
,array_agg(e.workout_id) AS ids
FROM exercises e
JOIN workouts w ON w.id = e.workout_id AND w.user_id = 5
RIGHT JOIN (
SELECT now()::date + generate_series(-22, 0) AS day
) s ON s.day = e.created_at::date
GROUP BY 1
ORDER BY 1;
要点:
- 是左连接的反向孪晶。由于联接是从左到右应用的,因此不需要以这种方式使用括号
- 切勿将基本类型和函数名
用作标识符。我用date
代替天
- 更新:要避免聚合/窗口函数
的结果为空,请使用外部sum()
如下所示:COALESCE
COALESCE(sum(reps),0))
- 在这种情况下,您只需使用一个简单的
,而不是复杂且相对昂贵的组合odgroupby
+窗口函数DISTINCT
COALESCE()
最近在一些问题上,人们对此感到困惑
通常,sum()
或其他聚合函数忽略NULL
值。结果与值根本不存在时的结果相同。然而,也有一些特殊情况
应该注意的是,除了计数
,这些函数返回
未选择任何行时为空值。特别是,没有行的sum
返回null,而不是预期的零,array\u agg
返回null
而不是没有输入行时的空数组。合并
函数可用于将null替换为零或空数组
必要时
本演示应通过演示以下案例来澄清:
- 1个没有行的表
- 3个表,其中1行保留(
/NULL
/0
)1
- 3个表,其中2行包含
和(NULL
/NULL
/0
)1
tbl | ct|u all | ct|u i | simple|u sum |内部|合并|外部|合并
---------+--------+------+------------+----------------+----------------
t|u empty | 0 | 0 | | 0
t|0 | 1 | 1 | 0 | 0
图1 | 1 | 1 | 1 | 1 | 1
t|n | 1 | 0 | 0 | 0
t|0n | 2 | 1 | 0 | 0
t|1n | 2 | 1 | 1 | 1
t|nn | 2 | 0 | 0 | 0
因此,我最初的建议是草率的。您可能需要将与sum()合并
但如果您这样做,请使用外部合并
。原始查询中的内部COALESCE
,并没有覆盖所有角落的情况,很少有用
我有一个复杂的SQL查询
的确,你知道。但是它不必是那样的:
SELECT s.day
,COALESCE(sum(w.reps), 0) AS sum_reps -- assuming reps comes from workouts
,array_agg(e.workout_id) AS ids
FROM exercises e
JOIN workouts w ON w.id = e.workout_id AND w.user_id = 5
RIGHT JOIN (
SELECT now()::date + generate_series(-22, 0) AS day
) s ON s.day = e.created_at::date
GROUP BY 1
ORDER BY 1;
要点:
- 是左连接的反向孪晶。由于联接是从左到右应用的,因此不需要以这种方式使用括号
- 切勿将基本类型和函数名
date
用作标识符。我用天
代替
- 更新:要避免聚合/窗口函数
sum()
的结果为空,请使用外部COALESCE
如下所示:COALESCE(sum(reps),0))
- 在这种情况下,您只需使用一个简单的
groupby
,而不是复杂且相对昂贵的组合odDISTINCT
+窗口函数
聚合函数和COALESCE()
最近在一些问题上,人们对此感到困惑
通常,sum()
或其他聚合函数忽略NULL
值。结果与值根本不存在时的结果相同。然而,也有一些特殊情况
应该注意的是,除了计数
,这些函数返回
未选择任何行时为空值。特别是,没有行的
sum
返回null,而不是预期的零,array\u agg
返回null
而不是没有输入行时的空数组。合并
函数可用于将null替换为零或空数组
必要时
本演示应通过演示以下案例来澄清:
- 1个没有行的表
- 3张桌子
-- no rows
CREATE TABLE t_empty (i int);
-- INSERT nothing
CREATE TABLE t_0 (i int);
CREATE TABLE t_1 (i int);
CREATE TABLE t_n (i int);
-- 1 row
INSERT INTO t_0 VALUES (0);
INSERT INTO t_1 VALUES (1);
INSERT INTO t_n VALUES (NULL);
CREATE TABLE t_0n (i int);
CREATE TABLE t_1n (i int);
CREATE TABLE t_nn (i int);
-- 2 rows
INSERT INTO t_0n VALUES (0), (NULL);
INSERT INTO t_1n VALUES (1), (NULL);
INSERT INTO t_nn VALUES (NULL), (NULL);
SELECT 't_empty' AS tbl
,count(*) AS ct_all
,count(i) AS ct_i
,sum(i) AS simple_sum
,sum(COALESCE(i, 0)) AS inner_coalesce
,COALESCE(sum(i), 0) AS outer_coalesce
FROM t_empty
UNION ALL
SELECT 't_0', count(*), count(i)
,sum(i), sum(COALESCE(i, 0)), COALESCE(sum(i), 0) FROM t_0
UNION ALL
SELECT 't_1', count(*), count(i)
,sum(i), sum(COALESCE(i, 0)), COALESCE(sum(i), 0) FROM t_1
UNION ALL
SELECT 't_n', count(*), count(i)
,sum(i), sum(COALESCE(i, 0)), COALESCE(sum(i), 0) FROM t_n
UNION ALL
SELECT 't_0n', count(*), count(i)
,sum(i), sum(COALESCE(i, 0)), COALESCE(sum(i), 0) FROM t_0n
UNION ALL
SELECT 't_1n', count(*), count(i)
,sum(i), sum(COALESCE(i, 0)), COALESCE(sum(i), 0) FROM t_1n
UNION ALL
SELECT 't_nn', count(*), count(i)
,sum(i), sum(COALESCE(i, 0)), COALESCE(sum(i), 0) FROM t_nn;
tbl | ct_all | ct_i | simple_sum | inner_coalesce | outer_coalesce
---------+--------+------+------------+----------------+----------------
t_empty | 0 | 0 | <NULL> | <NULL> | 0
t_0 | 1 | 1 | 0 | 0 | 0
t_1 | 1 | 1 | 1 | 1 | 1
t_n | 1 | 0 | <NULL> | 0 | 0
t_0n | 2 | 1 | 0 | 0 | 0
t_1n | 2 | 1 | 1 | 1 | 1
t_nn | 2 | 0 | <NULL> | 0 | 0