0

应该很简单,但它给我带来了几个问题。

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

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

任何帮助表示赞赏,在此先感谢大家。

4

3 回答 3

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

[编辑] 但要处理可能的 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
于 2009-02-23T12:11:26.967 回答
1

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

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

于 2009-02-23T18:21:19.527 回答
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:允许为空(未输入的值)

于 2009-02-23T13:49:10.740 回答