在单独的列中查询多个EAV属性

时间:2009-03-19 16:56:09

标签: sql entity-attribute-value

我在尝试编写查询时遇到问题。 (这比我之前的问题略有修改)

我的表格如下:

 tblTicketIssues.TicketID
 tblTicketIssues.RequesterID

 tblPersonnelProfile.PersonnelID
 tblPersonnelProfile.FirstName
 tblPersonnelProfile.LastName

 tblTicketAttribute.TicketID
 tblTicketAttribute.Attribute
 tblTicketAttribute.AttributeValue

我必须显示以下字段:

 TicketID, RequesterFullName, UrgentPriorityID, MediumPriorityID, 
 LowPrioritytID

这是具有挑战性的部分:

如果tblTicketAttribute.Attribute =“Urgent”,那么来自tblTicketAttribute.AttributeValue的值将显示在UrgentPriority列中

如果tblTicketAttribute.Attribute =“Medium”,那么来自tblTicketAttribute.AttributeValue的值将显示在MediumPriority列中

如果tblTicketAttribute.Attribute =“Low”,那么来自tblTicketAttribute.AttributeValue的值将显示在LowPriority列中

如果tblTicketAttribute.Attribute =“已关闭”则

tblTicketAttribute.Attribute中的值包括“Urgent”,“Medium”,“Low”,“Over30”,“Over60”,“Over90”,“Closed”

我不需要显示所有记录。只有“紧急”,“中等”和“ “低”。

4 个答案:

答案 0 :(得分:4)

我不是百分百肯定我理解,但我认为这满足了你所要求的。请注意,这是假设数据库是MySQL,您没有指定。如果它是其他的话,IF()和CONCAT()的语法可能略有不同。

编辑:根据Csharp的“答案”更新查询。 MAX - 这个名字有点像黑客。

SELECT t.TicketID,
    MAX(CONCAT(p.FirstName, ' ', p.LastName)) AS RequesterFullName,
    MAX(IF(a.Attribute = 'Urgent', a.AttributeValue, NULL)) AS UrgentPriorityID,
    MAX(IF(a.Attribute = 'Medium', a.AttributeValue, NULL)) AS MediumPriorityID,
    MAX(IF(a.Attribute = 'Low', a.AttributeValue, NULL)) AS LowPriorityID
FROM tblTicketIssues AS t
    LEFT JOIN tblPersonnelProfile AS p ON p.PersonnelID = t.RequesterID
    LEFT JOIN tblTicketAttribute AS a ON a.TicketID = t.TicketID
WHERE a.Attribute IN ('Urgent', 'Medium', 'Low')
GROUP BY t.TicketID;

答案 1 :(得分:2)

数据库设计使用tblTicketAttribute表的Entity-Attribute-Value模式。尝试获得这个相当普通的查询结果时遇到的困难表明EAV如何导致很多问题。

@Chad Birch的{​​{3}}是获得结果的一种方式。这是获得所需结果的另一种方法:

SELECT t.TicketID,
    CONCAT(p.FirstName, ' ', p.LastName) AS RequesterFullName,
    a1.AttributeValue AS UrgentPriorityID,
    a2.AttributeValue AS MediumPriorityID,
    a3.AttributeValue AS LowPriorityID
FROM tblTicketIssues AS t
  JOIN tblPersonnelProfile AS p ON (p.PersonnelID = t.RequesterID)
  LEFT JOIN tblTicketAttribute AS a1 
    ON (a1.TicketID = t.TicketID AND a1.Attribute = 'Urgent')
  LEFT JOIN tblTicketAttribute AS a2 
    ON (a2.TicketID = t.TicketID AND a2.Attribute = 'Medium')
  LEFT JOIN tblTicketAttribute AS a3 
    ON (a3.TicketID = t.TicketID AND a3.Attribute = 'Low');

此解决方案不使用GROUP BY子句,但对于要检索的每个属性,它确实需要单独的JOIN

另一种解决方案是在结果集的多行上获取属性:

SELECT t.TicketID,
    CONCAT(p.FirstName, ' ', p.LastName) AS RequesterFullName,
    a.AttributeValue AS AnyPriorityID
FROM tblTicketIssues AS t
  JOIN tblPersonnelProfile AS p ON (p.PersonnelID = t.RequesterID)
  LEFT JOIN tblTicketAttribute AS a 
    ON (a1.TicketID = t.TicketID AND a.Attribute IN ('Urgent', 'Medium', 'Low'));

此解决方案可以更好地扩展为SQL查询,因为您在获取更多属性时不必添加更多JOIN子句。但它确实意味着您必须对应用程序代码中的结果集进行一些后处理,以使其达到您想要的格式。

答案 2 :(得分:1)

我不知道你为什么要这样做,但是这里(假设是SQL Server):

 SELECT TicketID, FirstName + ' ' + LastName AS RequestFullName,
 CASE WHEN Attribute = "Low" THEN AttributeValue ELSE "" END AS LowPriorityID,
 CASE WHEN Attribute = "Medium" THEN AttributeValue ELSE "" END AS MediumPriorityID,
 CASE WHEN Attribute = "Urgent" THEN AttributeValue ELSE "" END AS UrgentPriorityID
 FROM ...
 WHERE Attribute IN ("Urgent", "Low", "Medium")

但这对我来说似乎是一种离奇的方式。

您能澄清一下tbTicketIssues和tbTicketAttributes之间的关系是一对一还是一对多?

答案 3 :(得分:0)

执行此类操作的一种相对简单的方法是将三个查询组合在一起。我怀疑你正在寻找的东西是这样的:

SELECT i.TicketID, a.FirstName, pp.AttributeValue AS UrgentPriorityID, null AS MediumPriorityID, null AS LowPrioritytID
FROM tblTicketIssues i, tblTicketAttribute a, tblPersonnelProfile pp
WHERE i.RequesterID = a.PersonnelID
AND i.TicketID = pp.TicketID
AND pp.Attribute = "Urgent"
UNION
SELECT i.TicketID, a.FirstName, null AS UrgentPriorityID, pp.AttributeValue AS MediumPriorityID, null AS LowPrioritytID
FROM tblTicketIssues i, tblTicketAttribute a, tblPersonnelProfile pp
WHERE i.RequesterID = a.PersonnelID
AND i.TicketID = pp.TicketID
AND pp.Attribute = "Medium"
UNION
SELECT i.TicketID, a.FirstName, null AS UrgentPriorityID, null AS MediumPriorityID, pp.AttributeValue AS LowPrioritytID
FROM tblTicketIssues i, tblTicketAttribute a, tblPersonnelProfile pp
WHERE i.RequesterID = a.PersonnelID
AND i.TicketID = pp.TicketID
AND pp.Attribute = "Low"

(这是SQL Server顺便说一句,不过我怀疑它几乎与任何RDBMS都不同)

毫无疑问,“光滑”的方式可以做到,但我喜欢这种方式,因为阅读它时非常简单。