2010-06-02 3 views
3

Say У меня есть 2 таблицы:Нужна помощь с SQL Query

Person 

- Id 
- Name 

PersonAttribute 

- Id 
- PersonId 
- Name 
- Value 

Далее, скажем, что каждый человек имел 2 атрибуты (например, пол и возраст). Образец записи будет выглядеть так:

Person->Id = 1 
Person->Name = 'John Doe' 

PersonAttribute->Id = 1 
PersonAttribute->PersonId = 1 
PersonAttribute->Name = 'Gender' 
PersonAttribute->Value = 'Male' 

PersonAttribute->Id = 2 
PersonAttribute->PersonId = 1 
PersonAttribute->Name = 'Age' 
PersonAttribute->Value = '30' 

Вопрос: как я запрашиваю это такое, что я получаю результат:

«John Doe», «Мужской», «30»

ответ

4
SELECT p.name, p1.Value, p2.Value 
    FROM Person p, PersonAttribute p1, PersonAttribute p2 
    WHERE p.Id = p1.PersonId AND p.Id = p2.PersonId 
     AND p1.Name = 'Gender' AND p2.Name = 'Age' 
+1

Это не масштабируется, чтобы вытащить N число общих атрибутов и их значений. – Timothy

1

Оставив дизайн в стороне, вы всегда можете получить результат PIVOT, но вам нужно знать, сколько атрибутов вы выбираете заранее.

3

Я думаю, вам нужно перепроектировать вашу схему. Почему бы и нет?

Person 

- Id 
- Name 
- Gender 
- Birthday 
... 
+2

+1 Полностью согласен. Похоже, что возраст хранится в столбце строки PersonAttribute-> Value наряду с такими вещами, как «Мужской» (и, как вы указываете, это должно быть получено в любом случае) –

+0

Я не согласен. ОП разработал общую схему атрибутов, возможно, чтобы пользователи могли определять свои собственные атрибуты и назначать свои собственные значения.Однако его пример - бедный. – Timothy

+0

@ msi77 & @martinsmith: для схемы требуется, чтобы объект A имел 0 или более атрибутов. Пример «человек» - это просто: пример. Я использовал его, чтобы упростить мой вопрос и получить более быстрый ответ. – StackOverflowNewbie

0
SELECT Name, g.Value, a.Value 
FROM Person, 
PersonAttribute g INNER JOIN ON g.Name = "Gender", 
PersonAttribute a INNER JOIN ON a.Name = "Age" 
2

ВЫБОР p.Name, g.Value, a.value
от человека р INNER JOIN PersonAttribute г = О p.Id g.Id И g.Name = "Пол"
INNER JOIN PersonAttribute a ON p.Id = a.Id AND a.Name = "Age"

2

Сохранение пар значений значений дает гибкость, но очень громоздко для запроса. Взгляните на http://www.simple-talk.com/community/blogs/philfactor/archive/2008/05/29/56525.aspx

+0

+1 Я всегда думаю об этой статье, когда вижу такие схемы. –

+0

+1 это ужасная проблема. Концептуально это фантастика, но реализация - это боль. – Timothy

1

Нет простого способа сделать это.

Концепция сводной таблицы (уже упомянутая другим ответом) - это в основном то, что вы ищете, за исключением того, что сводные таблицы требуют, чтобы вы знали имена колонок, которые вы хотите использовать. Понятно, что это проблема, когда вы хотите использовать силу такого дизайна таблиц!

В моей предыдущей жизни я просто установил на X количество столбцов, например 20-30, и если они не существовали, то набор строк включал кучу нулевых значений. Ничего страшного.

select piv.name, 
    max(case piv.a_name when 'Gender' then piv.a_value else null end) as Gender, 
    max(case piv.a_name when 'Age' then piv.a_value else null end) as Age, 
    max(case piv.a_name when 'Hobby' then piv.a_value else null end) as Hobby 
from 
(select p.name as name, pa.name as a_name, pa.value as a_value 
from person p, personattribute pa 
where p.id = pa.personid) piv 
group by piv.name 

Это будет генерировать выходной сигнал следующим образом:

name | gender | age | hobby 
-----------+--------+-----+--------- 
Bob Swift | Male |  | Reading 
John Doe | Male | 30 | 
(2 rows) 

Который чертовски близко к тому, что вы ищете. Я оставлю все это до вашего уровня приложения.

Я также настоятельно рекомендую включить атрибут NAME как часть возвращаемого значения, чтобы обеспечить контекст для VALUE.

Эти типы так называемых конструкций атрибутов Entity-Attribute часто вынуждены полагаться на комбинацию специфических для сервера функций, хранимых процедур и жестко запрограммированных запросов.

Смежные вопросы