Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

SQL Server - Сложни динамични обобщени колони

Имате малко бъркотия тук, защото имате две таблици в различни структури и искате да завъртите няколко колони. Първо бих започнал да пиша статична версия на вашата заявка, за да направя логиката правилна, след което ще премина през процеса на писане на динамична версия.

Тъй като искате да завъртите няколко колони, ще трябва да отмените завъртането на няколко колони в Контролите първо таблицата, след това осевата. Вие сте маркирали това като SQL Server 2008, така че можете да използвате CROSS APPLY за да отмените завъртането на колоните.

Предлагам да предприемете следните стъпки. Първо отменете завъртането на контролите таблица:

изберете ProjectId, col =ControlCode +'_'+col, valfrom( изберете c.ProjectId, c.ControlCode, c.ControlPoint, c.ControlScore, c.ControlValue от контролите c) dcross apply( изберете ' ControlPoint', cast(controlpoint as varchar(10)) union all select 'ControlScore', cast(ControlScore as varchar(10)) union all select 'ControlValue', ControlValue) c (col, val) 

Вижте SQL Fiddle с демонстрация . Това ще преобразува множеството ви редове в множество колони, подобно на:

<предварителен код>| ПРОЕКТИД | COL | VAL ||-----------|----------------|---------|| P001 | A_ControlPoint | 30.44 || P001 | A_ControlScore | 65,00 || P001 | A_ControlValue | Невалидно || P001 | C_ControlPoint | 45.30 || P001 | C_ControlScore | 85,00 || P001 | C_ControlValue | Валиден |

Второ, вземете данните от ControlChilds таблица в подобен формат, но използвайте вашия row_number() за да присвоите последователност за всяко дете:

изберете projectId, col =ControlCode+'_'+'Child'+cast(seq като varchar(10)), ControlChildValuefrom( изберете c.ProjectId, c.ControlCode, cc.ControlChildValue, row_number() over( дял от c.ProjectId, c.ControlCode ред от cc.ControlChildId) seq от контроли c вътрешно присъединяване controlchilds cc на c.controlid =cc.controlid) d 

Вижте SQL Fiddle с демонстрация . Това получава данните от тази таблица във формат:

<предварителен код>| ПРОЕКТИД | COL | CONTROLCHILDVALUE ||-----------|----------|------------------|| P001 | A_Дете1 | Да || P001 | A_Дете2 | Не || P001 | A_Дете3 | NA || P001 | A_Дете4 | Други || P001 | C_Дете1 | Да || P001 | C_Дете2 | SomeValue |

Сега можете лесно да използвате UNION ALL между двете заявки и приложете функцията PIVOT:

изберете ProjectId, A_ControlPoint, A_ControlScore, A_ControlValue, A_Child1, A_Child2, A_Child3, A_Child4, C_ControlPoint, C_ControlScore, C_ControlValue, C_Child1, C_Child2from( изберете ProjectId, col =ControlCode +'_'+col, val from ( изберете c.ProjectId, c.ControlCode, c.ControlPoint, c.ControlScore, c.ControlValue от контролите c) d кръстосано прилагане (изберете „ControlPoint“, cast(controlpoint като varchar(10)) обединение всички изберете „ControlScore“, cast( ControlScore като varchar(10)) съюз всички изберете 'ControlValue', ControlValue ) c (col, val) съюз всички изберете projectId, col =ControlCode+'_'+'Child'+cast(seq като varchar(10)), ControlChildValue от ( изберете c.ProjectId, c.ControlCode, cc.ControlChildValue, row_number() over(partition by c.ProjectId, c.ControlCode order by cc.ControlChildId) seq from controls c inner join controlchilds cc on c.controlid =cc.contr olid ) d) srcpivot( max(val) за колона в (A_ControlPoint, A_ControlScore, A_ControlValue, A_Child1, A_Child2, A_Child3, A_Child4, C_ControlPoint, C_ControlScore, C_ControlValue, C_Child1, C_Child2)) piv; 

Вижте SQL Fiddle с демонстрация .

Сега, след като имате правилната логика, можете да конвертирате това в динамична SQL версия:

DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX)select @cols =STUFF((SELECT ',' + QUOTENAME(col) from ( select ControlCode, col =ControlCode +'_' +col, seq, така че от контролите cross apply ( изберете 'ControlPoint', 0, 0 union all изберете 'ControlScore', 0, 1 union all изберете 'ControlValue', 0, 2 ) c (col, seq, so) union all изберете ControlCode, col =ControlCode+'_'+'Child'+cast(seq as varchar(10)), seq, 3 from ( select ControlCode, row_number() over(partition by c.ProjectId, c.ControlCode подреждане по cc.ControlChildId) seq от контроли c вътрешно присъединяване controlchilds cc на c.controlid =cc.controlid ) d) src група по ControlCode, seq, col, така че подреждане по ControlCode, така че, seq ЗА XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')set @query ='SELECT ProjectId, ' + @cols + ' from ( select ProjectId, col =ControlCode +''_ ''+col, val from ( изберете c.ProjectId, c.ControlCode, c.ControlPoint, c.ControlScore, c.ControlValue от контроли c ) d cross apply ( изберете ''ControlPoint'', cast(controlp oint като varchar(10)) съюз всички изберете ''ControlScore'', cast(ControlScore като varchar(10)) съюз всички изберете ''ControlValue'', ControlValue ) c (col, val) съюз всички изберете projectId, col =ControlCode+ ''_Child''+cast(seq as varchar(10)), ControlChildValue from ( select c.ProjectId, c.ControlCode, cc.ControlChildValue, row_number() over(partition by c.ProjectId, c.ControlCode order by cc. ControlChildId) seq от контроли c вътрешно присъединяване controlchilds cc на c.controlid =cc.controlid ) d) x pivot ( max(val) за col in (' + @cols + ') ) p 'exec sp_executesql @query; 

Вижте SQL Fiddle с демонстрация . Написах динамичната версия, за да запазя колоните в реда, който сте използвали във вашата извадка. Това може да се направи чрез използване на тип стойност на сортиране.

Това дава краен резултат от:

<предварителен код>| ПРОЕКТИД | A_КОНТРОЛНА ТОЧКА | A_CONTROLSCORE | A_CONTROLVALUE | A_CHILD1 | A_CHILD2 | A_CHILD3 | A_CHILD4 | C_CONTROLPOINT | C_CONTROLSCORE | C_CONTROLVALUE | C_CHILD1 | C_CHILD2 ||-----------|----------------|----------------|- ---------------|----------|----------|----------|- ---------|----------------|----------------|------ ----------|----------|-----------|| P001 | 30.44 | 65,00 | Невалиден | Да | Не | NA | Други | 45.30 | 85,00 | Валиден | Да | SomeValue |

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Скрипт на цялата база данни SQL-Server

  2. Как да премахнете водещи и последващи знаци в SQL Server

  3. SQL заявка за множество колони, използвайки Distinct само в една колона

  4. CONVERT() срещу TRY_CONVERT в SQL Server:Каква е разликата?

  5. Как да опиша таблица в SQL Server 2008?