Sql 使用GroupBy获取PIVOT

Sql 使用GroupBy获取PIVOT,sql,sql-server,sql-server-2008,pivot,pivot-table,Sql,Sql Server,Sql Server 2008,Pivot,Pivot Table,我有这张桌子: Person Job Day EndDay 1 101 1 12 1 102 2 11 1 103 3 11 3 101 1 11 3 102 2 11 3 JobOff 3 11 2 101 1 11 2 1

我有这张桌子:

Person      Job     Day  EndDay
1           101     1    12
1           102     2    11
1           103     3    11
3           101     1    11
3           102     2    11 
3           JobOff  3    11
2           101     1    11
2           102     2    11
2           103     3    11
2           JobOff  4    11
...
Day (Columns)
Person  (Rows)
Person  1    2    3       4
1       101  102  103     N/A
2       101  102  103     JobOff
3       101  102  JobOff  N/A
附言:我的日子快到N了,我不知道。因此,静态SQL在这里是不可行的

我需要将其更改为以下形式:

Person      Job     Day  EndDay
1           101     1    12
1           102     2    11
1           103     3    11
3           101     1    11
3           102     2    11 
3           JobOff  3    11
2           101     1    11
2           102     2    11
2           103     3    11
2           JobOff  4    11
...
Day (Columns)
Person  (Rows)
Person  1    2    3       4
1       101  102  103     N/A
2       101  102  103     JobOff
3       101  102  JobOff  N/A
任何帮助都将不胜感激。我对SQL非常陌生

多亏了Roman,我有了这个S.程序:

CREATE PROCEDURE [dbo].[MyStoredProcedure] AS
BEGIN

declare @stmt nvarchar(max)

select @stmt =
    isnull(@stmt + ', ', '') + 
    'isnull(max(case when [Day] = ' + cast([Day_I] as nvarchar(max)) + 
    ' then Job end), ''N/A'') as [' + cast([Day_I] as nvarchar(max)) + ']'
from (select distinct [Day_I] from dbo.Solution) as t
order by [Day_I]

select @stmt = '
select
    Person_I, ' + @stmt +'
from dbo.Solution_Format
group by Person_I'

END
但是当我像这样执行这个存储过程时:

exec MyStoredProcedure

它没有显示任何结果。没有错误

一种方法是使用多个自联接

Select
  t1.Person,
  COALESCE(t1.Job, 'N/A') [1],
  COALESCE(t2.Job, 'N/A' )[2],
  COALESCE(t3.Job, 'N/A') [3], 
  COALESCE(t4.Job, 'N/A') [4]
FROM 
  table1 t1
  LEFT JOIN table1  t2
  ON t1.Person =  t2.Person
    and t2.Day = 2
  LEFT JOIN table1  t3
   ON t1.Person =  t3.Person
     and t3.Day = 3
  LEFT JOIN table1  t4
    ON t1.Person =  t4.Person
     and t4.Day = 4
WHERE
   t1.Day = 1
ORDER BY 
  t1.Person

另一种方法是使用MAX(CASE),但我不喜欢这样使用聚合

Select
  t1.Person,
  COALESCE(MAX(CASE WHEN t1.Day = 1 then t1.Job END), 'N/A') [1],
  COALESCE(MAX(CASE WHEN t1.Day = 2 then t1.Job END), 'N/A') [2],
  COALESCE(MAX(CASE WHEN t1.Day = 3 then t1.Job END), 'N/A') [3],
  COALESCE(MAX(CASE WHEN t1.Day = 4 then t1.Job END), 'N/A') [4]

FROM 
  table1 t1
GROUP BY
  t1.Person

最后是pivot子句,我不太喜欢,因为这里的MAX

SELECT person, 
       COALESCE([1], 'N/A') [1], 
       COALESCE([2], 'N/A') [2], 
       COALESCE([3], 'N/A') [3], 
       COALESCE([4], 'N/A') [4] 
FROM   (SELECT t1.person, 
               t1.day, 
               t1.job 
        FROM   table1 t1) p 
       PIVOT (Max (job) 
             FOR day IN ( [1], 
                          [2], 
                          [3], 
                          [4]) ) AS pvt 

一种方法是使用多个自联接

Select
  t1.Person,
  COALESCE(t1.Job, 'N/A') [1],
  COALESCE(t2.Job, 'N/A' )[2],
  COALESCE(t3.Job, 'N/A') [3], 
  COALESCE(t4.Job, 'N/A') [4]
FROM 
  table1 t1
  LEFT JOIN table1  t2
  ON t1.Person =  t2.Person
    and t2.Day = 2
  LEFT JOIN table1  t3
   ON t1.Person =  t3.Person
     and t3.Day = 3
  LEFT JOIN table1  t4
    ON t1.Person =  t4.Person
     and t4.Day = 4
WHERE
   t1.Day = 1
ORDER BY 
  t1.Person

另一种方法是使用MAX(CASE),但我不喜欢这样使用聚合

Select
  t1.Person,
  COALESCE(MAX(CASE WHEN t1.Day = 1 then t1.Job END), 'N/A') [1],
  COALESCE(MAX(CASE WHEN t1.Day = 2 then t1.Job END), 'N/A') [2],
  COALESCE(MAX(CASE WHEN t1.Day = 3 then t1.Job END), 'N/A') [3],
  COALESCE(MAX(CASE WHEN t1.Day = 4 then t1.Job END), 'N/A') [4]

FROM 
  table1 t1
GROUP BY
  t1.Person

最后是pivot子句,我不太喜欢,因为这里的MAX

SELECT person, 
       COALESCE([1], 'N/A') [1], 
       COALESCE([2], 'N/A') [2], 
       COALESCE([3], 'N/A') [3], 
       COALESCE([4], 'N/A') [4] 
FROM   (SELECT t1.person, 
               t1.day, 
               t1.job 
        FROM   table1 t1) p 
       PIVOT (Max (job) 
             FOR day IN ( [1], 
                          [2], 
                          [3], 
                          [4]) ) AS pvt 

如果需要对任意数量的列执行此操作,也可以使用动态SQL执行此操作:

create procedure [dbo].[MyStoredProcedure]
as
begin   
    declare @stmt nvarchar(max)

    select @stmt =
        isnull(@stmt + ', ', '') + 
        'isnull(max(case when [Day] = ' + cast([Day] as nvarchar(max)) + 
        ' then Job end), ''N/A'') as [' + cast([Day] as nvarchar(max)) + ']'
    from (select distinct [Day] from Table1) as t
    order by [Day]

    select @stmt = '
    select
        Person, ' + @stmt +'
    from Table1
    group by Person'

    exec sp_executesql
        @stmt = @stmt
end

如果需要对任意数量的列执行此操作,也可以使用动态SQL执行此操作:

create procedure [dbo].[MyStoredProcedure]
as
begin   
    declare @stmt nvarchar(max)

    select @stmt =
        isnull(@stmt + ', ', '') + 
        'isnull(max(case when [Day] = ' + cast([Day] as nvarchar(max)) + 
        ' then Job end), ''N/A'') as [' + cast([Day] as nvarchar(max)) + ']'
    from (select distinct [Day] from Table1) as t
    order by [Day]

    select @stmt = '
    select
        Person, ' + @stmt +'
    from Table1
    group by Person'

    exec sp_executesql
        @stmt = @stmt
end

谢谢!不过,我的日子(专栏)您的动态解决方案可以运行吗?@RG-3您忘记执行语句-
exec sp_executesql@stmt=@stmt
,但是,当我通过C#调用此存储过程时,我不想将任何内容作为参数输入:\n您不必输入参数。只需创建不带参数的过程并在其中写入整个语句即可it@RomanP请看我在问题中的编辑。你会得到要点的。谢谢!不过,我的日子(专栏)您的动态解决方案可以运行吗?@RG-3您忘记执行语句-
exec sp_executesql@stmt=@stmt
,但是,当我通过C#调用此存储过程时,我不想将任何内容作为参数输入:\n您不必输入参数。只需创建不带参数的过程并在其中写入整个语句即可it@RomanPekar:请看我在问题中的编辑。您将了解要点。我的天数(列)最多63或更多…如果我这样做,将需要大量的代码行。@RG-3您可以很容易地生成SQL语句。它是否在上的运行时生成不应基于您的要求。我的天数(列)最多63行或更多…如果我继续这样做,将需要很多行代码。@RG-3您可以非常轻松地生成SQL语句。它是否在运行时生成取决于您的要求。