创建包含查找表的视图时出现问题
Posted
技术标签:
【中文标题】创建包含查找表的视图时出现问题【英文标题】:Problem creating a view containing lookup tables 【发布时间】:2009-02-23 11:17:11 【问题描述】:应该很简单,但它给我带来了一些问题。
我有一个类似于以下的数据集:
User
UserID
Name
Age
UserPropertyValues
UserID
PropertyCodeValueID
PropertyCodes
PropertyCodeID
PropertyCodeName
PropertyCodeValues
PropertyCodeValueID
PropertyCodeID
PropertValue
现在让我们假设表格包含以下数据:
1 John 25
2 Sarah 34
1 2
1 3
2 1
2 3
1 FavColour
2 CarMake
3 PhoneType
1 1 Blue
2 1 Yellow
3 2 Ford
4 3 Mobile
5 3 Landline
现在,我希望创建一个视图来返回用户详细信息,以及属性代码 1 和 2 的属性值,如下所示:
John 25 Yellow Ford
Sarah 34 Blue Ford
到目前为止,我尝试过的查询往往会返回重复的数据行:
John 25 Yellow
John 25 Ford
Sarah 34 Blue
Sarah 34 Ford
感谢任何帮助,提前谢谢大家。
【问题讨论】:
【参考方案1】:输入数据:
DECLARE @User TABLE (UserID INT, Name VARCHAR(10), Age INT)
INSERT INTO @User
SELECT 1, 'John', 25 UNION
SELECT 2, 'Sarah', 34
DECLARE @UserPropertyValues TABLE(UserID INT, PropertyCodeValueID INT)
INSERT INTO @UserPropertyValues
SELECT 1, 2 UNION
SELECT 1, 3 UNION
SELECT 2, 1 UNION
SELECT 2, 3
DECLARE @PropertyCodes
TABLE (PropertyCodeID INT, PropertyCodeName VARCHAR(10))
INSERT INTO @PropertyCodes
SELECT 1, 'FavColour' UNION
SELECT 2, 'CarMake' UNION
SELECT 3, 'PhoneType'
DECLARE @PropertyCodeValues TABLE (PropertyCodeValueID INT,
PropertyCodeID INT, PropertValue VARCHAR(10))
INSERT INTO @PropertyCodeValues
SELECT 1, 1, 'Blue' UNION
SELECT 2, 1, 'Yellow' UNION
SELECT 3, 2, 'Ford' UNION
SELECT 4, 3, 'Mobile' UNION
SELECT 5, 3, 'Landline'
如果结果中只需要两个属性,并且每个用户都有这些属性,那么试试这个:
SELECT U.Name, U.Age, PCVFC.PropertValue, PCVCM.PropertValue
FROM @User U
INNER JOIN @UserPropertyValues UPVFC ON U.UserID = UPVFC.UserID
INNER JOIN @PropertyCodeValues PCVFC
ON UPVFC.PropertyCodeValueID = PCVFC.PropertyCodeValueID
AND PCVFC.PropertyCodeID = 1
INNER JOIN @UserPropertyValues UPVCM ON U.UserID = UPVCM.UserID
INNER JOIN @PropertyCodeValues PCVCM
ON UPVCM.PropertyCodeValueID = PCVCM.PropertyCodeValueID
AND PCVCM.PropertyCodeID = 2
[edit] 但是要更好地处理可能的 NULL 值,请使用:
SELECT U.Name, U.Age, FC.PropertValue, CM.PropertValue
FROM @User U
LEFT JOIN (
SELECT UserID, PropertValue FROM @UserPropertyValues UPV
INNER JOIN @PropertyCodeValues PCV
ON UPV.PropertyCodeValueID = PCV.PropertyCodeValueID
AND PCV.PropertyCodeID = 1
) FC ON U.UserID = FC.UserID
LEFT JOIN (
SELECT UserID, PropertValue FROM @UserPropertyValues UPV
INNER JOIN @PropertyCodeValues PCV
ON UPV.PropertyCodeValueID = PCV.PropertyCodeValueID
AND PCV.PropertyCodeID = 2
) CM ON U.UserID = CM.UserID
【讨论】:
很好,但我也想建议更改表结构。我认为使用具有不同含义的值的列是一个坏主意。我建议创建 FavColour、Carmake 和 Phonetype 表,并从 user 表中引用它们。 改变结构是个好主意——以防属性数量有限。但是,如果属性名称应该是可配置的并且属性的数量可能会增加,那么最好保持当前的设计。 感谢各位的建议。我理解对结构的关注,但是这是为了与我们的客户使用的现有解决方案进行交互,该解决方案强制执行这种结构。正如您正确指出的那样,它适用于可配置的属性(名称和编号)。 感谢到目前为止 Coldice 的帮助,它似乎确实接近我所需要的。但是请注意,所需的属性编号 (1, 2) 属于 PropertyCodes 表。 欢迎您,您能详细解释一下房产编号有什么问题吗?【参考方案2】:您真正需要的是尽快放弃这种类型的数据库设计。它永远不会是有效的。要获得三种类型的值,您必须加入表三次。一旦您拥有 30 或 40 种不同类型的信息,您将需要多次加入该表(并在那时留下联接)。此外,每当您需要任何信息时,您都需要加入此表。我认为这是在您的数据库中创建了一个主要的锁定问题。最初设计与我一起工作的数据库之一的人就是这样做的,当公司从一两个客户发展到我们行业中最大的客户时,它造成了巨大的性能问题。
如果属性是每个人可能只有一个 realted 记录的属性,请将它们放入 user 表中。如果他们有多个记录,那么为每种类型的信息创建一个单独的表(一个用于 hones,一个用于电子邮件,一个用于 cartype,等等)因为您最终想要收集的信息通常不仅仅是简单的值和每种类型的信息都不同,它们必须在单独的表中。然后,当您只需要查看一个值(例如电话号码而不是电子邮件)时,您就加入了该表,并且您不会干扰尝试访问电子邮件而不是电话号码的人。如果您有一辆黄色的福特或白色的本田,它只会存储在 auto 表中的一个记录中,而不是您设计中的两个属性记录中。
【讨论】:
【参考方案3】:SELECT
u.[Name],
u.Age,
pcv1.PropertValue,
pcv2.PropertValue
FROM
Users u
LEFT JOIN
( UserPropertyValues upv1
JOIN PropertyCodeValues pcv1 ON
upv1.PropertyCodeValueID = pcv1.PropertyCodeValueID
AND pcv1.PropertyCodeID = 1
)
ON upv1.UserID = u.UserID
LEFT JOIN (
UserPropertyValues upv2
JOIN PropertyCodeValues pcv2 ON
upv2.PropertyCodeValueID = pcv2.PropertyCodeValueID
AND pcv2.PropertyCodeID = 2
)
ON upv2.UserID = u.UserID
编辑:我将用户重命名为用户
Edit2 : 允许 null(未输入的值)
【讨论】:
这不会处理 NULL 值(如果用户只有一个属性)以上是关于创建包含查找表的视图时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
sql server 创建视图添加表时出现从其他数据库导入的表未显示出来