在MS SQL Server中对所有选择字段进行分组的更好方法

时间:2015-10-04 14:47:13

标签: sql sql-server group-by distinct

我试图提供一个真实数据仓库架构的简单示例,所以如果表格如此天真和基本,请原谅我。

主表名为Items,其中ItemName为主键:

Items Table

还有另外两个名为Propertiesattributes的表格,其中id列(自动标识)为主键:

Attributes

Properties

问题:我想像这样查询这些表:

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'

结果如下:

Results

查询的真实部分是I.ItemnameA.AttributeName作为不同的值,因此添加了GROUP BY来模拟这两个字段上的不同值。请注意,过滤是基于Property列完成的,但我不需要选择列表中的属性。然而,我在选择列表中也需要Items表的其他字段(Col1,Col2,Col3,Col4)。我的问题是我可以重写这个查询,以便我不必在所有这些额外的字段上分组吗?提供的查询是否有效?如果我必须使用它,我可以使用索引来提高查询速度吗?它可以是什么索引?

2 个答案:

答案 0 :(得分:1)

从我从查询的逻辑中得到的结果,你只对'Prop1'感兴趣,所以你可以内心加入到那里。因此,假设您的items表没有重复项,那么您只需要获取不同的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

答案 1 :(得分:1)

看起来您不需要GROUP任何内容。

首先,您要查找包含属性Prop1的所有项目:

SELECT Properties.ItemName
FROM Properties
WHERE Properties.Property = 'Prop1'

在此表中允许两行具有相同ItemNameProperty的行是没有意义的,因此您应该为这对列添加唯一约束以使您的意图清晰程序员和查询优化器。有了这个约束,就不需要GROUP BY了。

由于您要按Property过滤,我会在此表中添加以下唯一索引。它将强制执行约束并帮助进行搜索。索引中列的顺序很重要。

CREATE UNIQUE NONCLUSTERED INDEX [IX_Properties] ON [dbo].[Properties]
(
    [Property] ASC,
    [ItemName] ASC
))

实际上,我会考虑从此表中删除ID列,并将该唯一索引作为主键,尤其是在许多外键中未使用此ID时。它也可能是有用的(对于其他可能的查询)向该表添加第二个唯一索引,这两个列以另一个顺序列出。

类似的想法适用于Attributes表。一旦您明确指出ItemName表中只有一行AttributeNameAttributes,则不需要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'
;