2014-07-21 2 views
0

таблицы семьей, какSQL предложение запроса для горизонтального мудрой строки союза

No. ADD Member Det1 Det2 Det3 Det4 

1 Add1 Dad1 q  w  e  r 
1 Add1 Mom1 q  w  e  r 
1 Add1 Chd1 q  w  e  r 
1 Add1 Chd1 q  w  e  r 
1 Add2 Mom2 q  w  e  r 
1 Add2 Chd2 q  w  e  r 
1 Add2 Chd2 q  w  e  r 

ADD здесь как семья ID уникальной в семью, член является именем член и семья могут иметь какие-либо член номера.

Желаемый результат:

No. ADD Member Det1 Det2 Det3 Det4 Member Det1 Det2 Det3 Det4 .. more 
1 Add1 Dad1 q  w  e  r  Mom1 q  w  e  r .. more 
2 Add2 Mom2 q  w  e  r  Chd1 q  w  e  r .. more 

Я попытался с созданием псевдоним числа членов

SELECT a.ADD 
    ,a.Member 
    ,a.Det1 
    ,a.Det2 
    ,a.Det3 
    ,a.Det4 
    ,b.bDD 
    ,b.Member 
    ,b.Det1 
    ,b.Det2 
    ,b.Det3 
    ,b.Det4 
FROM Family a 
    ,Family b 
WHERE a.ADD = b.ADD 
+1

Я думаю, что стержень будет лучше для того, что вы пытаетесь сделать. – Jenn

+0

То, что вы пытаетесь сделать, называется PIVOTing запроса. Но ваш случай немного сложнее, потому что, если я понимаю, вы хотите установить свой набор результатов в две колонки. И ваш желаемый результат не подходит к реестрам, которые вы предоставляете в качестве примера. –

+0

Вам нужна динамическая перекрестная вкладка. Пейнт не будет работать, потому что у вас есть несколько агрегатов. Взгляните на эту статью, в которой объясняется, как это сделать. http://www.sqlservercentral.com/articles/Crosstab/65048/ –

ответ

0

EDIT: 11:26 PST. Я думаю, вам нужен динамический SQL, чтобы делать то, что вы хотите. Поскольку вы делаете сложный набор блоков, который вы добавляете по столбцу и повторяете имена столбцов.

declare @Temp table ([No] int, [Add] varchar(4), Member varchar(4), Det1 char, Det2 char, Det3 char, Det4 char); 

insert into @Temp values 
(1, 'Add1', 'Dad1', 'q','w','e','r'), 
(1, 'Add1', 'Mom1', 'q','w','e','r'), 
(1, 'Add1', 'Chd1', 'q','w','e','r'), 
(1, 'Add1', 'Chd1', 'q','w','e','r'), 
(1, 'Add2', 'Mom2', 'q','w','e','r'), 
(1, 'Add2', 'Chd2', 'q','w','e','r'), 
(1, 'Add2', 'Chd2', 'q','w','e','r') 


if object_id('tempdb..#Temp') is not null 
    drop table #temp 

select 
    No 
, [Add] 
, Member 
, Det1 
, Det2 
, Det3 
, Det4 
, dense_rank() over(order by [Add]) as part 
, row_number() over(partition by [Add] order by Member) as rwn 

into #Temp 
from @Temp 

declare 
    @Cursor int = 1 
, @Max int 

, @Addendum varchar(max) = '' 
, @NL char = char(10) 
, @SQL nvarchar(max) 
, @Part int 
; 

-- set up my loop prep 

-- statement to execute later 
select @SQL = 'Select No, [Add] ' + @NL + 'from #Temp' + @NL + 'group by No, [Add]'; 

-- max iteration of an occurence 
Select @Max = max(rwn) from #Temp 

-- ensure we use the part that has the max occurrence, less we get less results than we need 
Select @Part = max(part) from #Temp where rwn = @Max 

-- While the statement is looping it is adding to itself dynamically to select your values. I could do a loop of a loop 
-- to get only certain values you want too, but this is enough for an example. EG, set a bit for Det1, Det2 and then make a statement for those things too. 
While @Cursor <= @Max 
BEGIN 
    Select @Addendum += @NL + ', max(case when rwn = ' + cast(@Cursor as varchar) + ' then Member end) as Member ' + 
     @NL + ', max(case when rwn = ' + cast(@Cursor as varchar) + ' then Det1 end) as Det1 ' + 
     @NL + ', max(case when rwn = ' + cast(@Cursor as varchar) + ' then Det2 end) as Det2 ' + 
     @NL + ', max(case when rwn = ' + cast(@Cursor as varchar) + ' then Det3 end) as Det3 ' + 
     @NL + ', max(case when rwn = ' + cast(@Cursor as varchar) + ' then Det4 end) as Det4 ' 
    from #Temp where part = @Part and rwn = @Cursor 

    Select @Cursor += 1; 

END 

-- 'stuff' is a sql syntax to insert in a specific place a chunk of something. 
Select @SQL = stuff(@SQL, charindex('from', @SQL), 0, @Addendum + @NL); 

-- I want to now 'execute' the statement I just built up in memory to select what I need 
exec sp_executesql @SQL 

Похоже, вы просто делаете сложную группировку, но я не уверен, из вашего примера, если вы желаете, чтобы явно оставить некоторые из ваших членов. Это будет работать как на SQL Server 2008 и выше, как:

declare @Temp table ([No] int, [Add] varchar(4), Member varchar(4), Det1 char, Det2 char, Det3 char, Det4 char); 

insert into @Temp values 
(1, 'Add1', 'Dad1', 'q','w','e','r'), 
(1, 'Add1', 'Mom1', 'q','w','e','r'), 
(1, 'Add1', 'Chd1', 'q','w','e','r'), 
(1, 'Add1', 'Chd1', 'q','w','e','r'), 
(1, 'Add2', 'Mom2', 'q','w','e','r'), 
(1, 'Add2', 'Chd2', 'q','w','e','r'), 
(1, 'Add2', 'Chd2', 'q','w','e','r') 

Select * 
from @Temp 

select 
    No 
, [Add] 
, Member 
, max(Det1) as Det1 
, max(Det2) as Det2 
, max(Det3) as Det3 
, max(Det4) as Det4 
from @Temp 
group by No, [Add], Member 

процедура А «Pivot» хорош для принятия множества значений, которые обычно ассоциируются с одним значением «типа». Это хорошо для вещей, которые представляют собой несколько строк для значений поиска.

Как у вас есть человек, и они связаны с таблицей заказов и заказ столик имеет столбец типа, который связан с таблицей перекодировки, которая является ключевой таблицей пары как

1 = рубашка, 2 = брюки , 3 = ботинки, 4 = носки, 5 = ремень, 6 = шляпа, 7 = часы и т. Д.

Вы можете сделать поворот для нескольких вещей простым прохождением левого соединения и выражением типа " вы хотите отступить. EG:

from person p 
left join order o1 on p.personid = o1.personid and o1.type = 1 
left join order o2 on p.personid = o2.personid and o2.type = 2 

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

Select p.PersonName, o1.Value, o2.Value 

Обычно Pivot используется, когда у вас есть целая куча типов, и вы не хотите делать несколько левых объединений. Когда вы выполняете набор последовательностей, которые вы хотите сгруппировать, вам действительно нужно сделать «группу» для простых наборов. Я мог бы сделать это путем:

  1. стандартная группа по перечисленным выше, где каждый столбец в «группе» контролирует поток, а затем делает агрегат («макс», использованный выше), чтобы найти только одно значение максимальное появление этой группировки. Если ваши No, Add и Member будут иметь одно значение, это означает, что это работает.
  2. макс (случай, когда то заканчивается) заявление, которое делает группировку для меня в выражении, как показано ниже:

    Выберите у.PersonName , макс (случай, когда КодЗаказ = 1, то OrderAmount конца) , макс (случай, когда КодЗаказ = 2, то OrderAmount конца) , макс (случай, когда КодЗаказ = 3, то OrderAmount конца) от @Person у присоединиться к @Orders х on x.PersonId = y.PersonId group by PersonName

  3. Оконные функции, которые дают мне возможность динамической группировки без предложения «group by».

    Выберите y.PersonName , OrderAmount , row_number() над (раздел по PersonName порядке по OrderAmount) orderbyAmount , row_number() над (раздел по PersonName порядке по убыванию) OrderAmount orderbyAmountDesc , не более (случай, когда OrderID = 1, затем OrderAmount end) over (partition by PersonName)

    , max (в случае, когда OrderID = 2, а затем OrderAmount end) over (partition by PersonName) , max (в случае, когда OrderID = 3, затем OrderAmount end) over (partition by PersonName) от @Person y присоединиться к @Orders x на x.PersonId = y.PersonI d

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

+0

@djangojazz Нет, все члены в семье должны появляться в одной строке без повторения * No * и * ADD *. –

+0

@ Конрад, я пропустил это. Я бы использовал динамический SQL в этом случае с оконными функциями. Там может быть более элегантный способ сделать это, но вам нужно учитывать, если члены больше для одной группы, чем другие. Обновление пришло ... – djangojazz

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