在 MS SQL 服务器中对所有 select 字段进行分组的更好方法

Better way to group by on all select fields in MS SQL Server

我试图提供一个真实数据仓库模式的简单示例,所以如果 table 太幼稚和初级,请原谅我。

Main table 被调用 ItemsItemName 作为主键:

还有两个名为 Propertiesattributes 的另外两个 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.ItemnameA.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中允许具有相同ItemNameProperty的两行对我来说没有意义,所以你应该为这对添加一个唯一约束列让程序员清楚地了解您的意图并查询优化器。有了这个约束,这里就不需要 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 中只有一行具有相同的 ItemNameAttributeName,则不需要 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'
;