Запрос нескольких атрибутов EAV в отдельных столбцах - PullRequest
0 голосов
/ 19 марта 2009

Я сталкиваюсь с проблемами при попытке написать запрос. (это немного изменено из моего предыдущего вопроса)

Мои таблицы расположены следующим образом:

 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 включают «Срочно», «Средний», «Низкий», «Более 30», «Более 60», «Более 90», «Закрыт»

Мне не нужно отображать все записи. Только «Срочно», «Средне» и «Низко».

Ответы [ 4 ]

4 голосов
/ 19 марта 2009

Я не уверен на 100%, что понимаю, но я думаю, что это удовлетворит то, что вы просите. Обратите внимание, что это предполагало, что база данных - 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;
2 голосов
/ 19 марта 2009

Проект базы данных использует шаблон Entity-Attribute-Value для таблицы tblTicketAttribute. Трудность, с которой вы столкнулись при попытке получить этот довольно обычный результат запроса, показывает, как EAV вызывает много проблем.

Решение от @Chad Birch - один из способов получить результат. Вот еще один способ получить желаемый результат:

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 при получении большего количества атрибутов. Но это означает, что вам нужно выполнить некоторую постобработку результирующего набора в коде приложения, чтобы получить его в нужном формате.

1 голос
/ 19 марта 2009

Я понятия не имею, почему вы хотите сделать это таким образом, но здесь (при условии 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 один к одному или один ко многим?

0 голосов
/ 19 марта 2009

Одним из относительно простых способов сделать что-то подобное было бы объединить три запроса вместе. Я подозреваю, что то, что вы ищете, будет примерно таким:

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, хотя я сомневаюсь, что это будет сильно отличаться в любой СУБД)

Есть, несомненно, «скользкие» способы, которыми это можно сделать, но мне нравится этот способ, потому что он очень прост при чтении.

...