创建包含查找表的视图时出现问题

时间:2009-02-23 11:17:12

标签: sql database view

应该很简单,但这会给我带来一些问题。

我有一个类似于以下的数据集:

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

感谢任何帮助,提前谢谢大家。

3 个答案:

答案 0 :(得分:2)

输入数据:

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

答案 1 :(得分:1)

您真正需要的是尽快放弃这种类型的数据库设计。它永远不会有效率。要获得三种类型的值,您必须三次加入表中。一旦您有30或40种不同类型的信息,您将需要多次加入该表(并且左键加入该表)。每当您需要任何信息时,您都需要加入此表。我认为这是在数据库中创建一个主要的锁定问题。最初设计我使用的数据库之一的人就是这样做的,当公司从拥有一两个客户发展成为我们行业中最大的客户时,就会产生巨大的性能问题。

如果属性是每个人可能只有一个实际记录的属性,则将它们放入用户表中。如果他们将有多个记录,那么为每种类型的信息创建一个单独的表(一个用于hones,一个用于电子邮件,一个用于cartype等)。因为您最终想要收集的信息通常不仅仅是简单的值和对于每种类型的信息,它们必须在不同的表中。然后,当您只需要查看一个值(比如电话号码而不是电子邮件)时,您就可以加入到该表中,并且您不会干扰尝试访问电子邮件而非电话号码的人。如果您有黄色福特或白色本田,它将仅存储在自动表中的一个记录中,而不是存储在您设计中的两个属性记录中。

答案 2 :(得分:0)

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:允许为空(未输入值)