我想知道如何更好地将以下查询写入Microsoft SQL Server。
我有三个表:surveys
,survey_presets
和survey_scenes
。它们包含以下列:
CREATE TABLE [dbo].[surveys](
[id] [int] IDENTITY(1,1) NOT NULL,
[caption] [nvarchar](255) NOT NULL,
[creation_time] [datetime] NOT NULL,
)
CREATE TABLE [dbo].[survey_presets](
[id] [int] IDENTITY(1,1) NOT NULL,
[survey_id] [int] NOT NULL,
[preset_id] [int] NOT NULL,
)
CREATE TABLE [dbo].[survey_scenes](
[id] [int] IDENTITY(1,1) NOT NULL,
[survey_id] [int] NOT NULL,
[scene_id] [int] NOT NULL,
)
survey_presets
和survey_scenes
surveys
列的survey_id
都有外键。
现在我想选择所有调查,每个调查都有相应的预设和场景。这是我想要的“伪查询”:
SELECT
surveys.*,
COUNT(survey_presets, where survey_presets.survey_id = surveys.id),
COUNT(survey_scenes, where survey_scenes.survey_id = surveys.id)
FROM surveys
ORDER BY suverys.creation_time
我可以对SELECT DISTINCT
,JOIN
,GROUP BY
等进行混乱,但我是T-SQL的新手,我怀疑我的查询在任何意义上都是最优的
答案 0 :(得分:2)
我会在子查询中进行计数,以避免使用笛卡尔积。由于您在presets
中可能会有一些匹配的行,而scenes
中的一些行也可能会成倍增加。您可以编写简单的连接查询,并通过计算distinct survey_presets.id
和distinct survey_scenes.id
来避免乘法。
SELECT
surveys.*,
isnull(presets_count, 0) presets_count,
isnull(scenes_count, 0) scenes_count
FROM surveys
LEFT JOIN
(
SELECT survey_id,
count(*) presets_count
FROM survey_presets
GROUP BY survey_id
) presets
ON surveys.id = presets.survey_id
LEFT JOIN
(
SELECT survey_id,
count(*) scenes_count
FROM survey_scenes
GROUP BY survey_id
) scenes
ON surveys.id = scenes.survey_id
ORDER BY surveys.creation_time
工作原理
您可以向查询的FROM部分引入一种名为derived table
的特殊子查询。派生表定义为括在括号中的普通查询,后跟表别名。它不能使用外部查询中的任何列,但可以公开您在ON部分中使用的列,以将派生表连接到查询的主体。
在这种情况下,派生表只计算按id分组的行;联接将计数连接到调查。
答案 1 :(得分:0)
SELECT surveys.ID, surveys.caption, surveys.creation_time,
count(survey_presets.survey_id) as survey_presets,
count(survey_scenes.survey_id) as survey_scenes
FROM surveys
LEFT OUTER JOIN survey_presets on survey_presets.survey_id = surveys.id
LEFT OUTER JOIN survey_scenes on survey_scenes.survey_id = surveys.id
GROUP BY surveys.ID, surveys.caption, surveys.creation_time
ORDER BY suverys.creation_time