在我的数据库中,我具有以下架构:
CREATE TABLE survey_results (
id integer NOT NULL
);
CREATE TABLE slide_results (
id integer NOT NULL,
survey_result_id integer,
tags character varying[] DEFAULT '{}'::character varying[],
content character varying,
created_at timestamp with time zone NOT NULL
);
INSERT INTO survey_results (id)
VALUES (1);
INSERT INTO slide_results (id, survey_result_id, tags, content, created_at)
VALUES (1, 1, '{food}', 'Food slide', now());
INSERT INTO slide_results (id, survey_result_id, tags, content, created_at)
VALUES (2, 1, '{motivation}', 'Motivation slide', now());
现在,我想要一个SQL查询,该查询将返回调查结果ID和具有指定标签的幻灯片结果的内容。我写了这样的东西:
select distinct on(sr.id)
sr.id,
slr.content AS food,
slr2.content AS motivation
from survey_results sr
LEFT JOIN slide_results slr ON slr.survey_result_id = sr.id AND slr.id IN (
SELECT id as id
FROM slide_results
WHERE 'food' = ANY(tags)
ORDER BY created_at desc
)
LEFT JOIN slide_results slr2 ON slr2.survey_result_id = sr.id AND slr2.id IN (
SELECT id as id
FROM slide_results
WHERE 'motivation' = ANY(tags)
ORDER BY created_at desc
)
group by slr.content, slr2.content, sr.id
返回:
| id | food | motivation |
| --- | ---------- | ---------------- |
| 1 | Food slide | Motivation slide |
此查询工作正常,但我想知道是否有更好的方法?
编辑:
我忘了添加链接做db-fiddle:
答案 0 :(得分:1)
我会这样写查询:
SELECT DISTINCT ON (sr.id)
sr.id,
slr.content AS food,
slr2.content AS motivation
FROM survey_results AS sr
LEFT JOIN (SELECT survey_result_id, content, created_at
FROM slide_results
WHERE '{food}' <@ tags) AS slr
ON slr.survey_result_id = sr.id
LEFT JOIN (SELECT survey_result_id, content, created_at
FROM slide_results
WHERE '{motivation}' <@ tags) AS slr2
ON slr2.survey_result_id = sr.id
ORDER BY sr.id, slr.created_at DESC, slr2.created_at DESC;
ORDER BY
必须在外部查询中才能生效。
使用<@
而不是=ANY
可以在slide_results.tags
上使用GIN索引。
在FROM
列表中使用子选择可以避免不必要的联接和效率低的IN
子查询。
答案 1 :(得分:1)
我不能保证这会比您拥有的更好,但是它似乎更具可扩展性。在没有看到完整的数据集和所需结果的情况下,很难知道这是否会适得其反:
select
sl.survey_result_id,
array_to_string (array_agg (distinct sl.content) filter
(where 'food' = any (sl.tags)), ',') as food,
array_to_string (array_agg (distinct sl.content) filter
(where 'motivation' = any (sl.tags)), ',') as motivation
from
survey_results s
join slide_results sl on s.id = sl.survey_result_id
group by survey_result_id