Таблицы соединения SQL

Таблица 1 содержит

ID|Name  
1  Mary  
2  John  

Вторая таблица содержит

ID|Color  
1  Red  
2  Blue  
2  Green  
2  Black  

Я хочу закончить с

ID|Name|Red|Blue|Green|Black  
1  Mary Y   Y  
2  John     Y     Y     Y

Спасибо за любую помощь.


Спасибо за ответы. Я собираюсь повторно опубликовать это с некоторой дополнительной информацией о том, что именно я пытаюсь сделать, что может усложнить это. Кто-нибудь может это закрыть?


person Harley    schedule 12.03.2010    source источник
comment
-1: Вы должны сообщить нам, какую СУБД вы используете.   -  person Jim G.    schedule 12.03.2010
comment
Я использую ADO для подключения к базе данных Visual Foxpro.   -  person Harley    schedule 12.03.2010
comment
Я думаю, что что-то упускаю... Как указал другой, между таблицами 1 и 2 нет никакой связи. Таблица 2 выглядит как просто цвета со своим собственным идентификатором, а не идентификатором человека. Должно быть что-то, что связывает таблицы, если ваши данные для второй таблицы не должны показывать 1 = красный, 1 = синий, 2 = синий, 2 = зеленый, 2 = черный. Если это так, запрос может быть разработан.   -  person DRapp    schedule 12.03.2010
comment
Да, значения идентификатора сильно отличаются от того, что показывает ваш набор результатов. Либо есть таблица ссылок, которую вы нам не показываете, либо примеры значений в вашей таблице цветов неверны (должно быть 5 строк с тремя идентификаторами = 2 и двумя строками с идентификатором = 1).   -  person AaronLS    schedule 12.03.2010
comment
Я не помню, чтобы размещал это таким образом, но я изменил его.   -  person Harley    schedule 12.03.2010


Ответы (5)


Если вы используете T-SQL, вы можете использовать PIVOT (http://msdn.microsoft.com/en-us/library/ms177410.aspx)

Вот запрос, который я использовал:

declare @tbl_names table(id int, name varchar(100))
declare @tbl_colors table(id int, color varchar(100))

insert into @tbl_names
select 1, 'Mary'
union
select 2, 'John'


insert into @tbl_colors
select 1, 'Red'
union
select 1, 'Blue'
union
select 2, 'Green'
union
select 2, 'Blue'
union
select 2, 'Black'

select name,
        case when [Red] is not null then 'Y' else '' end as Red,
        case when [Blue] is not null then 'Y' else '' end as Blue,
        case when [Green] is not null then 'Y' else '' end as Green,
        case when [Black] is not null then 'Y' else '' end as Black

from
(
select n.id, name, color from @tbl_names n
inner join @tbl_colors c on n.id = c.id
) as subq
pivot 
(
    min(id)
    FOR color IN ([Red], [Blue], [Green], [Black])
) as pvt

И вот вывод:

John        Y   Y   Y
Mary    Y   Y       
person Andrew Bezzub    schedule 12.03.2010
comment
Три проблемы с этим решением: 1) данные, которые вы ВСТАВЛЯЕТЕ в таблицы, не являются данными, указанными в вопросе, 2) это требует, чтобы вы строго ограничивали список цветов во время разработки, что маловероятно, и 3) это SQL Серверное решение, а не решение VFP (хотя я думаю, что OP добавил теги Foxpro только после того, как вы опубликовали решение). - person Larry Lustig; 12.03.2010
comment
Я взял данные из вопроса, похоже, Харли отредактировал его. То же и с Фокспро... - person Andrew Bezzub; 12.03.2010

Я могу использовать оператор CASE с подзапросом для ввода значений Y.

select ID, Name,
  case
    when exists (select * from Colors C where C.ID = N.ID and Color = 'Red') then
      'Y'
    else
      NULL
  end
,
 case
    when exists (select * from Colors C where C.ID = N.ID and Color = 'Blue') then
      'Y'
    else
      NULL
  end
,
 case
    when exists (select * from Colors C where C.ID = N.ID and Color = 'Green') then
      'Y'
    else
      NULL
  end
,
 case
    when exists (select * from Colors C where C.ID = N.ID and Color = 'Black') then
      'Y'
    else
      NULL
  end
from Names N
person AaronLS    schedule 12.03.2010
comment
Я думаю, что это решение будет очень медленным... так много подзапросов. - person Ender; 12.03.2010
comment
@Ender Использование уникальных ограничений в таблице Colors может помочь улучшить план выполнения, поскольку он сможет предсказать, что подзапрос является скалярным запросом. Либо это, либо поворотный, либо другой случай, который использует Ларри, для которого потребуется 4 соединения (или соединение для каждого возможного цвета). При такой ротации данных часто возникают довольно медленные запросы. Этого можно было бы избежать с помощью лучшего дизайна таблицы, но похоже, что постер ограничен тем, что уже реализовано сторонней системой. Я чувствую его боль, потому что это сложная ситуация. - person AaronLS; 12.03.2010

Я думаю, у вас должно получиться что-то вроде этого:

SELECT  t1.ID, 
        t1.Name, 
        CASE 
            WHEN red.ID IS NULL THEN '' 
            ELSE 'Y' 
        END As Red,
        CASE 
            WHEN blue.ID IS NULL THEN '' 
            ELSE 'Y' 
        END As Blue
FROM    Table1 t1 
    LEFT JOIN   Table2 Red 
        ON t1.ID = Red.ID AND Red.Color = 'Red'
    LEFT JOIN   Table2 Blue
        ON t1.ID = Blue.ID AND Blue.Color = 'Blue'

MS Sql не поддерживает запросы PIVOT, такие как MS Access.

person Ender    schedule 12.03.2010
comment
Просто нужно исправить условия присоединения к Red.Color и Blue.Color. - person ; 12.03.2010
comment
SQl Server 2005 и выше действительно имеют PIVOT и UNPIVOT. - person DancesWithBamboo; 12.03.2010
comment
Правильно, но вы все равно в конечном итоге вводите каждый столбец / переменную, на которую хотите повернуться. В MS Access есть способ динамического создания сводного запроса на основе значений. Это то, что я имел в виду, говоря, что MS Access - person Ender; 12.03.2010

Как отмечали другие комментаторы, вы не показываете, как именно вы связываете людей и цвета. Если вы используете таблицу связывания (person_id, color_id), то нет способа решить эту проблему в стандартном SQL, поскольку для этого требуется сводная или перекрестная таблица, которая не является частью стандартного SQL.

Если вы хотите добавить условие, что количество цветов ограничено и известно, а также время разработки, вы можете придумать решение, используя одно соединение для каждого цвета и функции CASE или IF в SQL. Но это было бы некрасиво, и, кроме того, я бы не стал доверять этому условию, чтобы оно оставалось верным очень долго.

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

В противном случае вам придется сделать это в хранимой процедуре или в коде приложения.

person Larry Lustig    schedule 12.03.2010
comment
Нет таблицы связывания, только общий идентификатор. Во второй таблице у нас в настоящее время есть 11 возможных значений для «цвета», поэтому каждый уникальный идентификатор из первой таблицы может иметь до 11 записей во второй таблице. - person Harley; 12.03.2010
comment
Кроме того, первая таблица содержит 285 000 записей, а вторая — 773 000, поэтому создание связывающей таблицы перед выполнением запроса может оказаться нецелесообразным. Поскольку таблицы поддерживаются с помощью стороннего программного обеспечения, добавление таблицы ссылок в свой код, вероятно, никогда не произойдет. - person Harley; 12.03.2010
comment
Теперь это имеет больше смысла, когда вы обновили значения идентификаторов в таблице 2 с 1, 2, 3, 4 до 1, 2, 2, 2. Однако выходные данные по-прежнему не соответствуют вашим табличным данным, так как нет Мэри / Блю записать в таблицу 2. - person Larry Lustig; 13.03.2010

Вопреки тому, что говорили некоторые другие плакаты; Не вижу необходимости в третьем столе. Если цвета являются хорошо известным перечислением в вашем приложении, вам не нужна таблица «Цвет».

То, что вы ищете, это PIVOT, подобный этому one.

person DancesWithBamboo    schedule 12.03.2010