我试图提供一个真实数据仓库架构的简单示例,所以如果表格如此天真和基本,请原谅我。
主表名为Items
,其中ItemName
为主键:
还有另外两个名为Properties
和attributes
的表格,其中id
列(自动标识)为主键:
问题:我想像这样查询这些表:
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
列完成的,但我不需要选择列表中的属性。然而,我在选择列表中也需要Items
表的其他字段(Col1,Col2,Col3,Col4)。我的问题是我可以重写这个查询,以便我不必在所有这些额外的字段上分组吗?提供的查询是否有效?如果我必须使用它,我可以使用索引来提高查询速度吗?它可以是什么索引?
答案 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'
在此表中允许两行具有相同ItemName
和Property
的行是没有意义的,因此您应该为这对列添加唯一约束以使您的意图清晰程序员和查询优化器。有了这个约束,就不需要GROUP BY
了。
由于您要按Property
过滤,我会在此表中添加以下唯一索引。它将强制执行约束并帮助进行搜索。索引中列的顺序很重要。
CREATE UNIQUE NONCLUSTERED INDEX [IX_Properties] ON [dbo].[Properties]
(
[Property] ASC,
[ItemName] ASC
))
实际上,我会考虑从此表中删除ID
列,并将该唯一索引作为主键,尤其是在许多外键中未使用此ID
时。它也可能是有用的(对于其他可能的查询)向该表添加第二个唯一索引,这两个列以另一个顺序列出。
类似的想法适用于Attributes
表。一旦您明确指出ItemName
表中只有一行AttributeName
和Attributes
,则不需要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'
;