在 MS SQL 服务器中对所有 select 字段进行分组的更好方法
Better way to group by on all select fields in MS SQL Server
我试图提供一个真实数据仓库模式的简单示例,所以如果 table 太幼稚和初级,请原谅我。
Main table 被调用 Items
以 ItemName
作为主键:
还有两个名为 Properties
和 attributes
的另外两个 table 都以 id
列(自动标识)作为主键:
问题: 我想这样查询这些table:
SELECT
I.ItemName, A.AttributeName, I.Col1, I.Col2, I.Col3, I.Col4,
pForFilter.Property
FROM
Items I
LEFT OUTER JOIN
attributes A ON I.ItemName = A.ItemName
LEFT OUTER JOIN
Properties pForFilter On I.ItemName = pForFilter.ItemName
GROUP BY
I.ItemName, A.AttributeName, I.Col1, I.Col2, I.Col3, I.Col4,
pForFilter.Property
HAVING
pForFilter.Property = 'Prop1'
结果如下:
查询的实部是I.Itemname
,A.AttributeName
作为不同的值,所以添加了GROUP BY
来模拟这两个字段的不同值。请注意,过滤是基于 Property
列完成的,但我不需要 select 列表中的 属性。然而,我还需要 select 列表中的 Items
table 的其他字段(Col1、Col2、Col3、Col4)。我的问题是我可以重写这个查询,这样我就不必对所有这些额外的字段进行分组了吗?提供的查询是否有效?如果我必须使用它,我可以使用索引来提高我的查询速度吗?它可以是什么索引?
从我从你的查询逻辑中得到的信息来看,你只对 'Prop1'
感兴趣,所以你可以直接连接到它。因此,假设您的项目 table 没有重复项,那么您只需要获取不同的 ItemName、AttributeName 组合。像这样的查询将为您提供 group by
中这么多列所需的信息
SELECT I.ItemName, attr.AttributeName, I.Col1,
I.Col1, I.Col2, I.Col3, I.Col4, prop.Property
FROM Items I
INNER JOIN (SELECT p.ItemName, p.Property
FROM Properties p
WHERE p.Property = 'Prop1'
GROUP BY p.ItemName, p.Property) prop
ON I.ItemName = prop.ItemName
LEFT JOIN (SELECT A.ItemName, A.AttributeName
FROM Attributes A
GROUP BY A.ItemName, A.AttributeName) attr
ON I.ItemName = attr.ItemName
看起来你不需要GROUP
任何东西。
首先您想找到所有具有 属性 Prop1
:
的项目
SELECT Properties.ItemName
FROM Properties
WHERE Properties.Property = 'Prop1'
在这个table中允许具有相同ItemName
和Property
的两行对我来说没有意义,所以你应该为这对添加一个唯一约束列让程序员清楚地了解您的意图并查询优化器。有了这个约束,这里就不需要 GROUP BY
。
由于您要按 Property
进行过滤,我将向此 table 添加以下唯一索引。它将强制执行约束并帮助搜索。索引中列的顺序很重要。
CREATE UNIQUE NONCLUSTERED INDEX [IX_Properties] ON [dbo].[Properties]
(
[Property] ASC,
[ItemName] ASC
))
事实上,我会考虑从此 table 中删除 ID
列并将该唯一索引设为主键,尤其是如果此 ID
未在许多外键中使用。向此 table 添加第二个唯一索引(对于其他可能的查询)也可能很有用,这两列以另一个顺序列出。
类似的想法适用于 Attributes
table。一旦明确说明 Attributes
table 中只有一行具有相同的 ItemName
和 AttributeName
,则不需要 GROUP BY
。
您的查询变为:
SELECT
I.ItemName
,Attributes.AttributeName
,I.Col1
,I.Col2
,I.Col3
,I.Col4
FROM
Items AS I
INNER JOIN Properties ON Properties.ItemName = I.ItemName
INNER JOIN Attributes ON Attributes.ItemName = I.ItemName
WHERE
Properties.Property = 'Prop1'
;
我试图提供一个真实数据仓库模式的简单示例,所以如果 table 太幼稚和初级,请原谅我。
Main table 被调用 Items
以 ItemName
作为主键:
还有两个名为 Properties
和 attributes
的另外两个 table 都以 id
列(自动标识)作为主键:
问题: 我想这样查询这些table:
SELECT
I.ItemName, A.AttributeName, I.Col1, I.Col2, I.Col3, I.Col4,
pForFilter.Property
FROM
Items I
LEFT OUTER JOIN
attributes A ON I.ItemName = A.ItemName
LEFT OUTER JOIN
Properties pForFilter On I.ItemName = pForFilter.ItemName
GROUP BY
I.ItemName, A.AttributeName, I.Col1, I.Col2, I.Col3, I.Col4,
pForFilter.Property
HAVING
pForFilter.Property = 'Prop1'
结果如下:
查询的实部是I.Itemname
,A.AttributeName
作为不同的值,所以添加了GROUP BY
来模拟这两个字段的不同值。请注意,过滤是基于 Property
列完成的,但我不需要 select 列表中的 属性。然而,我还需要 select 列表中的 Items
table 的其他字段(Col1、Col2、Col3、Col4)。我的问题是我可以重写这个查询,这样我就不必对所有这些额外的字段进行分组了吗?提供的查询是否有效?如果我必须使用它,我可以使用索引来提高我的查询速度吗?它可以是什么索引?
从我从你的查询逻辑中得到的信息来看,你只对 'Prop1'
感兴趣,所以你可以直接连接到它。因此,假设您的项目 table 没有重复项,那么您只需要获取不同的 ItemName、AttributeName 组合。像这样的查询将为您提供 group by
SELECT I.ItemName, attr.AttributeName, I.Col1,
I.Col1, I.Col2, I.Col3, I.Col4, prop.Property
FROM Items I
INNER JOIN (SELECT p.ItemName, p.Property
FROM Properties p
WHERE p.Property = 'Prop1'
GROUP BY p.ItemName, p.Property) prop
ON I.ItemName = prop.ItemName
LEFT JOIN (SELECT A.ItemName, A.AttributeName
FROM Attributes A
GROUP BY A.ItemName, A.AttributeName) attr
ON I.ItemName = attr.ItemName
看起来你不需要GROUP
任何东西。
首先您想找到所有具有 属性 Prop1
:
SELECT Properties.ItemName
FROM Properties
WHERE Properties.Property = 'Prop1'
在这个table中允许具有相同ItemName
和Property
的两行对我来说没有意义,所以你应该为这对添加一个唯一约束列让程序员清楚地了解您的意图并查询优化器。有了这个约束,这里就不需要 GROUP BY
。
由于您要按 Property
进行过滤,我将向此 table 添加以下唯一索引。它将强制执行约束并帮助搜索。索引中列的顺序很重要。
CREATE UNIQUE NONCLUSTERED INDEX [IX_Properties] ON [dbo].[Properties]
(
[Property] ASC,
[ItemName] ASC
))
事实上,我会考虑从此 table 中删除 ID
列并将该唯一索引设为主键,尤其是如果此 ID
未在许多外键中使用。向此 table 添加第二个唯一索引(对于其他可能的查询)也可能很有用,这两列以另一个顺序列出。
类似的想法适用于 Attributes
table。一旦明确说明 Attributes
table 中只有一行具有相同的 ItemName
和 AttributeName
,则不需要 GROUP BY
。
您的查询变为:
SELECT
I.ItemName
,Attributes.AttributeName
,I.Col1
,I.Col2
,I.Col3
,I.Col4
FROM
Items AS I
INNER JOIN Properties ON Properties.ItemName = I.ItemName
INNER JOIN Attributes ON Attributes.ItemName = I.ItemName
WHERE
Properties.Property = 'Prop1'
;