在 PostgreSQL 中呈现来自 3 个类似查询的数据
Presenting data from 3 similar queries in PostgreSQL
在我的 PostgreSQL 数据库中,我有以下架构:
CREATE TABLE survey_results (
id integer NOT NULL,
scores jsonb DEFAULT '{}'::jsonb,
raw jsonb,
created_at timestamp without time zone,
updated_at timestamp without time zone
);
在这个table中我有以下数据:
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (1, '{"medic": { "social": { "total": "high" } } }', null, now(), now());
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (2, '{"medic": { "social": { "total": "medium" } } }', null, now(), now());
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (3, '{"medic": { "social": { "total": "low" } } }', null, now(), now());
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (4, '{}', '{ "survey": { "denied": true } }', now(), now());
我想从这个 table 中获取以下格式的数据:
{
"positive": {
"2018-01-15": 2,
},
"negative": {
"2018-01-5": 1,
}
"declined": {
"2018-01-15": 1,
}
}
我可以像这样在 3 个单独的查询中获取此数据:
WITH positive_count AS (
SELECT
COUNT(*) AS count_all,
date(survey_results.created_at)
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('high','medium'))
GROUP BY date(survey_results.created_at)
), negative_count AS (
SELECT
COUNT(*) AS count_all,
date(survey_results.created_at)
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('low'))
GROUP BY date(survey_results.created_at)
), declined_count AS (
SELECT
COUNT(*) AS count_all,
date(survey_results.created_at)
FROM "survey_results"
WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')
GROUP BY date(survey_results.created_at)
)
SELECT * from positive_count;
如何将这些结合起来,以我描述的格式通过一个查询获取此数据?或者用以下方式格式化会更容易:
date |positive_count|negative_count| declined_count|
------------+--------------+--------------+----------------
2018-01-15 | 1 | 1 | 1 |
这里是sqlfiddle:
http://sqlfiddle.com/#!17/a9705/2
提前致谢。
要获得结果,请 table:
SELECT
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium'))) AS positive,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low'))) AS negative,
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')) AS declined
FROM survey_results
GROUP BY date(survey_results.created_at)
获取json格式
select
jsonb_build_object('positive',
json_agg(jsonb_build_object(date, positive)) FILTER (WHERE positive <> 0)
) ||
jsonb_build_object('negative',
json_agg( jsonb_build_object(date, negative)) FILTER (WHERE negative <> 0)
) ||
jsonb_build_object('declined',
json_agg(jsonb_build_object(date, declined)) FILTER (WHERE declined <> 0)
)
from (
SELECT
date(survey_results.created_at) as date,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium'))) AS positive,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low'))) AS negative,
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')) AS declined
FROM survey_results
GROUP BY date(survey_results.created_at)
) as t1;
或json基于您的原始查询
WITH positive_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*)
) as j
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('high','medium'))
GROUP BY date(survey_results.created_at)
), negative_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*)
) as j
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('low'))
GROUP BY date(survey_results.created_at)
), declined_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*)
) as j
FROM "survey_results"
WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')
GROUP BY date(survey_results.created_at)
)
SELECT
jsonb_build_object('positive', (SELECT json_agg(j) from positive_count)) ||
jsonb_build_object('negative', (SELECT json_agg(j) from negative_count)) ||
jsonb_build_object('declined', (SELECT json_agg(j) from declined_count))
;
编辑:
在评论之后,保留条目 0
WITH positive_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium')))
) as j
FROM "survey_results"
GROUP BY date(survey_results.created_at)
), negative_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low')))
) as j
FROM "survey_results"
GROUP BY date(survey_results.created_at)
), declined_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true'))
) as j
FROM "survey_results"
GROUP BY date(survey_results.created_at)
)
SELECT
jsonb_build_object('positive', (SELECT json_agg(j) from positive_count)) ||
jsonb_build_object('negative', (SELECT json_agg(j) from negative_count)) ||
jsonb_build_object('declined', (SELECT json_agg(j) from declined_count))
编辑日期在前的结构(见评论)
根据我的查询(这更有效,因为它只查询 table 一次)
select
json_agg(
jsonb_build_object(date,
jsonb_build_object('positive', positive) ||
jsonb_build_object('negative', negative) ||
jsonb_build_object('declined', declined)
))
from (
SELECT
date(survey_results.created_at) as date,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium'))) AS positive,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low'))) AS negative,
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')) AS declined
FROM survey_results
GROUP BY date(survey_results.created_at)
) as t1;
而且 WITH
查询会更复杂,因为 3 个查询中的每一个 return 都是日期,但我们只需要一个来源。当然,在条件进入 FILTER
之后,所有 3 个 WITH 查询 return 相同的行(只是差异计数)。所以我们可以从他们中的任何一个那里获取日期。但是为什么 运行 3 个查询,一个就够了?
我们确实需要 2 个查询(1 个子查询,就像我一样),因为有 2 个单独的聚合:1) 按日期聚合 2) 将此聚合的结果聚合到 1 行中。
您的 JSON 格式实施起来有点棘手。您尝试使用日期值作为键。这意味着,随着日期的增加,您的 JSON blob 中将有更多的键。
相反,我会在每个类别中创建一个列表。每个列表元素有两个键 created_at 和 count 并且可以重复。
{
"positive": {[{"created_at": "2018-01-15","count" :2},{"created_at": "2018-01-14","count" :1}]},
"negative": {[{"created_at": "2018-01-15","count" :1},{"created_at": "2018-01-14","count" :3}]},
"declined": {[{"created_at": "2018-01-15","count" :1},{"created_at": "2018-01-14","count" :1}]}
}
这个查询让你到达那里。
WITH status_count AS (
SELECT
CASE
WHEN (survey_results.scores #>> '{medic,social,total}'::text[]) = ANY (ARRAY['high'::text, 'medium'::text]) THEN 'positive'::text
WHEN (survey_results.scores #>> '{medic,social,total}'::text[]) = 'low'::text THEN 'negative'::text
WHEN COALESCE(survey_results.raw #>> '{survey,denied}'::text[], 'f'::text) = 'true'::text THEN 'declined'::text
ELSE NULL::text
END AS status,
date(survey_results.created_at) AS created_at
FROM survey_results
)
SELECT row_to_json(t.*) AS row_to_json
FROM ( SELECT ( SELECT array_to_json(array_agg(row_to_json(d.*))) AS array_to_json
FROM ( SELECT status_count.created_at,
count(status_count.status) AS count
FROM status_count
WHERE status_count.status = 'positive'::text
GROUP BY status_count.created_at, status_count.status) d) AS positive,
( SELECT array_to_json(array_agg(row_to_json(d.*))) AS array_to_json
FROM ( SELECT status_count.created_at,
count(status_count.status) AS count
FROM status_count
WHERE status_count.status = 'negative'::text
GROUP BY status_count.created_at, status_count.status) d) AS negative,
( SELECT array_to_json(array_agg(row_to_json(d.*))) AS array_to_json
FROM ( SELECT status_count.created_at,
count(status_count.status) AS count
FROM status_count
WHERE status_count.status = 'declined'::text
GROUP BY status_count.created_at, status_count.status) d) AS declined) t;
对于简单的 table 选项,您需要创建一个枢轴 table。为此,您需要安装 tablefunc
扩展。
CREATE EXTENSION tablefunc
之后您可以运行下面的查询,它会给您想要的结果。
SELECT ct.created_at,
ct.positive_count,
ct.negative_count,
ct.declined_count
FROM crosstab('
WITH status_count AS
(SELECT
CASE
WHEN (scores#>>''{medic,social,total}'' in (''high'',''medium'')) THEN ''positive''
WHEN (scores#>>''{medic,social,total}'' in(''low'') ) THEN ''negative''
WHEN (coalesce(raw#>>''{survey,denied}'',''f'') = ''true'') THEN ''declined''
END AS status,
date(survey_results.created_at) AS created_at
FROM survey_results)
SELECT created_at, status, count(status) FROM status_count GROUP BY created_at, status ORDER BY created_at, status'::text) ct(created_at date, declined_count bigint, negative_count bigint, positive_count bigint);
在我的 PostgreSQL 数据库中,我有以下架构:
CREATE TABLE survey_results (
id integer NOT NULL,
scores jsonb DEFAULT '{}'::jsonb,
raw jsonb,
created_at timestamp without time zone,
updated_at timestamp without time zone
);
在这个table中我有以下数据:
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (1, '{"medic": { "social": { "total": "high" } } }', null, now(), now());
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (2, '{"medic": { "social": { "total": "medium" } } }', null, now(), now());
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (3, '{"medic": { "social": { "total": "low" } } }', null, now(), now());
INSERT INTO survey_results (id, scores, raw, created_at, updated_at)
VALUES (4, '{}', '{ "survey": { "denied": true } }', now(), now());
我想从这个 table 中获取以下格式的数据:
{
"positive": {
"2018-01-15": 2,
},
"negative": {
"2018-01-5": 1,
}
"declined": {
"2018-01-15": 1,
}
}
我可以像这样在 3 个单独的查询中获取此数据:
WITH positive_count AS (
SELECT
COUNT(*) AS count_all,
date(survey_results.created_at)
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('high','medium'))
GROUP BY date(survey_results.created_at)
), negative_count AS (
SELECT
COUNT(*) AS count_all,
date(survey_results.created_at)
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('low'))
GROUP BY date(survey_results.created_at)
), declined_count AS (
SELECT
COUNT(*) AS count_all,
date(survey_results.created_at)
FROM "survey_results"
WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')
GROUP BY date(survey_results.created_at)
)
SELECT * from positive_count;
如何将这些结合起来,以我描述的格式通过一个查询获取此数据?或者用以下方式格式化会更容易:
date |positive_count|negative_count| declined_count|
------------+--------------+--------------+----------------
2018-01-15 | 1 | 1 | 1 |
这里是sqlfiddle:
http://sqlfiddle.com/#!17/a9705/2
提前致谢。
要获得结果,请 table:
SELECT
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium'))) AS positive,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low'))) AS negative,
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')) AS declined
FROM survey_results
GROUP BY date(survey_results.created_at)
获取json格式
select
jsonb_build_object('positive',
json_agg(jsonb_build_object(date, positive)) FILTER (WHERE positive <> 0)
) ||
jsonb_build_object('negative',
json_agg( jsonb_build_object(date, negative)) FILTER (WHERE negative <> 0)
) ||
jsonb_build_object('declined',
json_agg(jsonb_build_object(date, declined)) FILTER (WHERE declined <> 0)
)
from (
SELECT
date(survey_results.created_at) as date,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium'))) AS positive,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low'))) AS negative,
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')) AS declined
FROM survey_results
GROUP BY date(survey_results.created_at)
) as t1;
或json基于您的原始查询
WITH positive_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*)
) as j
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('high','medium'))
GROUP BY date(survey_results.created_at)
), negative_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*)
) as j
FROM "survey_results"
WHERE (scores#>>'{medic,social,total}' in('low'))
GROUP BY date(survey_results.created_at)
), declined_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*)
) as j
FROM "survey_results"
WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')
GROUP BY date(survey_results.created_at)
)
SELECT
jsonb_build_object('positive', (SELECT json_agg(j) from positive_count)) ||
jsonb_build_object('negative', (SELECT json_agg(j) from negative_count)) ||
jsonb_build_object('declined', (SELECT json_agg(j) from declined_count))
;
编辑: 在评论之后,保留条目 0
WITH positive_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium')))
) as j
FROM "survey_results"
GROUP BY date(survey_results.created_at)
), negative_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low')))
) as j
FROM "survey_results"
GROUP BY date(survey_results.created_at)
), declined_count AS (
SELECT
jsonb_build_object(
date(survey_results.created_at),
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true'))
) as j
FROM "survey_results"
GROUP BY date(survey_results.created_at)
)
SELECT
jsonb_build_object('positive', (SELECT json_agg(j) from positive_count)) ||
jsonb_build_object('negative', (SELECT json_agg(j) from negative_count)) ||
jsonb_build_object('declined', (SELECT json_agg(j) from declined_count))
编辑日期在前的结构(见评论)
根据我的查询(这更有效,因为它只查询 table 一次)
select
json_agg(
jsonb_build_object(date,
jsonb_build_object('positive', positive) ||
jsonb_build_object('negative', negative) ||
jsonb_build_object('declined', declined)
))
from (
SELECT
date(survey_results.created_at) as date,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('high','medium'))) AS positive,
COUNT(*) FILTER (WHERE (scores#>>'{medic,social,total}' in('low'))) AS negative,
COUNT(*) FILTER (WHERE (coalesce(raw#>>'{survey,denied}','f') = 'true')) AS declined
FROM survey_results
GROUP BY date(survey_results.created_at)
) as t1;
而且 WITH
查询会更复杂,因为 3 个查询中的每一个 return 都是日期,但我们只需要一个来源。当然,在条件进入 FILTER
之后,所有 3 个 WITH 查询 return 相同的行(只是差异计数)。所以我们可以从他们中的任何一个那里获取日期。但是为什么 运行 3 个查询,一个就够了?
我们确实需要 2 个查询(1 个子查询,就像我一样),因为有 2 个单独的聚合:1) 按日期聚合 2) 将此聚合的结果聚合到 1 行中。
您的 JSON 格式实施起来有点棘手。您尝试使用日期值作为键。这意味着,随着日期的增加,您的 JSON blob 中将有更多的键。
相反,我会在每个类别中创建一个列表。每个列表元素有两个键 created_at 和 count 并且可以重复。
{
"positive": {[{"created_at": "2018-01-15","count" :2},{"created_at": "2018-01-14","count" :1}]},
"negative": {[{"created_at": "2018-01-15","count" :1},{"created_at": "2018-01-14","count" :3}]},
"declined": {[{"created_at": "2018-01-15","count" :1},{"created_at": "2018-01-14","count" :1}]}
}
这个查询让你到达那里。
WITH status_count AS (
SELECT
CASE
WHEN (survey_results.scores #>> '{medic,social,total}'::text[]) = ANY (ARRAY['high'::text, 'medium'::text]) THEN 'positive'::text
WHEN (survey_results.scores #>> '{medic,social,total}'::text[]) = 'low'::text THEN 'negative'::text
WHEN COALESCE(survey_results.raw #>> '{survey,denied}'::text[], 'f'::text) = 'true'::text THEN 'declined'::text
ELSE NULL::text
END AS status,
date(survey_results.created_at) AS created_at
FROM survey_results
)
SELECT row_to_json(t.*) AS row_to_json
FROM ( SELECT ( SELECT array_to_json(array_agg(row_to_json(d.*))) AS array_to_json
FROM ( SELECT status_count.created_at,
count(status_count.status) AS count
FROM status_count
WHERE status_count.status = 'positive'::text
GROUP BY status_count.created_at, status_count.status) d) AS positive,
( SELECT array_to_json(array_agg(row_to_json(d.*))) AS array_to_json
FROM ( SELECT status_count.created_at,
count(status_count.status) AS count
FROM status_count
WHERE status_count.status = 'negative'::text
GROUP BY status_count.created_at, status_count.status) d) AS negative,
( SELECT array_to_json(array_agg(row_to_json(d.*))) AS array_to_json
FROM ( SELECT status_count.created_at,
count(status_count.status) AS count
FROM status_count
WHERE status_count.status = 'declined'::text
GROUP BY status_count.created_at, status_count.status) d) AS declined) t;
对于简单的 table 选项,您需要创建一个枢轴 table。为此,您需要安装 tablefunc
扩展。
CREATE EXTENSION tablefunc
之后您可以运行下面的查询,它会给您想要的结果。
SELECT ct.created_at,
ct.positive_count,
ct.negative_count,
ct.declined_count
FROM crosstab('
WITH status_count AS
(SELECT
CASE
WHEN (scores#>>''{medic,social,total}'' in (''high'',''medium'')) THEN ''positive''
WHEN (scores#>>''{medic,social,total}'' in(''low'') ) THEN ''negative''
WHEN (coalesce(raw#>>''{survey,denied}'',''f'') = ''true'') THEN ''declined''
END AS status,
date(survey_results.created_at) AS created_at
FROM survey_results)
SELECT created_at, status, count(status) FROM status_count GROUP BY created_at, status ORDER BY created_at, status'::text) ct(created_at date, declined_count bigint, negative_count bigint, positive_count bigint);