2015-09-25 1 views
0

Я пытаюсь написать запрос с переменным числом столбцов в зависимости от данных, но я никогда такого не делал.Как сделать кросс-вкладку, где количество столбцов меняется? (ADO SQL Server)

Мы бежим ADO и надеемся иметь один запрос (возможно, с подзапросов), но никакого другого кодирования или GO заявления, хранимые процедуры и т.д.

Мы планируем использовать результаты этого запроса в редактируемая сетка.

Ниже приведен образец наших данных. У нас есть список сотрудников и список проектов. Обратите внимание, что это не «суммированная» перекрестная вкладка. На каждую ячейку есть только один номер источника.

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

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

Редактировать: Поскольку мы пишем запрос в коде и отправляем его, мы можем генерировать запрос как динамически. Нам не нужно динамически генерировать код. Например, в наших данных ниже мы сможем прочитать (на нашем родном языке) таблицу Project и знать, что у нас есть 3 проекта и их имена. Мы можем использовать их в Pivot я вижу от чтения, но просто не знаю, как ...

Crosstab source and results

+0

Пожалуйста, оставьте свои попытки и, если это возможно, создать макет в [SQLFiddle] (http://sqlfiddle.com/) или [Rextester] (http://rextester.com/ runcode), чтобы упростить вам поддержку –

ответ

3

Как о чем-то вроде этого: http://sqlfiddle.com/#!6/2ded1/6

declare @pivotquery as nvarchar(max) 
declare @columnname as nvarchar(max) 
select @columnname= isnull(@columnname + ',','') 
     + quotename(name) 
from (select name from project) as t2 
set @pivotquery = 
    N'with t1 as (
     select ph.employee, e.name as empname, p.name, ph.hours 
     from project_hours ph 
     inner join project p 
     on p.id = ph.project 
     inner join employees e 
     on e.id = ph.employee 
     ) 
     select * 
     from t1 
     pivot(sum(hours) for name in (' + @columnname + ')) as pivot_table' 
exec sp_executesql @pivotquery 

с существенной помощью и Дальнейшее объяснение здесь: http://sqlhints.com/2014/03/18/dynamic-pivot-in-sql-server/

EDIT: Когда я снова прочитал ваш вопрос, я заметил, что вы создаете запрос в коде, и в этом случае вам, вероятно, не нужна утилита выше, а простая точка, где вы построить пункт for name in в вашей программе, например: http://sqlfiddle.com/#!6/2ded1/12

with t1 as (
    select ph.employee, e.name as empname, p.name, ph.hours 
    from project_hours ph 
    inner join project p 
    on p.id = ph.project 
    inner join employees e 
    on e.id = ph.employee 
) 
select * 
from t1 
pivot(sum(hours) 
     for name in ([First Floor], [Basement], [Parking Lot A])) 
     as hours_summary 
+0

Спасибо, Кендалл! – Tom

1

Для будущих читателей, здесь является обобщенным ANSI-синтаксис SQL-запрос с использованием двух вложенных таблиц, полученных подзапросов.

Этот запрос должен быть совместим с большинством RDMS (SQL Server, MySQL, SQLite, Oracle, PostgreSQL, DB2), поскольку она не использует никаких функций КТР Window (WITH) или функции базы данных конкретных как SQL сервера Pivot():

SELECT [Key], [Employee Name], [Age], 
     Max(FF) As [First Floor], 
     Max(BSMT) As [Basement], 
     Max(PRKLotA) As [Parking Lot A]  
FROM (
    SELECT dT.Key, 
      dT.[Employee Name], 
      dT.[Age], 
      CASE WHEN dT.Project = 'First Floor' THEN dT.Hours END As FF, 
      CASE WHEN dT.Project = 'Basement' THEN dT.Hours END As BSMT, 
      CASE WHEN dT.Project = 'Parking Lot A' THEN dT.Hours END As PRKLotA 
    FROM (
      SELECT [Employees].Key, 
       [Employees.[Employee Name], 
       Employees.Age, Projects.Project, 
       [Project Hours].Hours 
      FROM [Project Hours] 
      INNER JOIN Employees ON [Project Hours].[Employees FK] = Employees.Key 
      INNER JOIN Projects ON [Project Hours].[Projects FK] = Projects.Key 
    ) AS dT 
) As dT2  
GROUP BY [Key], [Employee Name], [Age] 

Выход:

Key Employee Name Age First Floor  Basement Parking Lot A 
1   Tim  40   1000   3000  
2   John  5   2000   4000    5000