具有动态生成列、聚合函数和无聚合列的 SQL Pivot

Posted

技术标签:

【中文标题】具有动态生成列、聚合函数和无聚合列的 SQL Pivot【英文标题】:SQL Pivot with dynamic generated columns, aggregate function and columns without aggregation 【发布时间】:2014-11-27 04:43:30 【问题描述】:

我有以下查询:

WITH preEKBE AS(
SELECT 
        EKPO . MANDT,
        EKPO . EBELN,
        EKPO . EBELP,
        DD07T.DDTEXT AS c_Meaning,
        EKBE . VGABE,
        EKBE . DMBTR,
        EKBE . MENGE, 
        COUNT(VGABE) OVER(PARTITION BY EKBE . EBELN, EKBE . EBELP, ZEKKN) AS c_COUNT,
        CONVERT (varchar(10),MIN(EKBE . BLDAT) OVER ( PARTITION BY EKBE . EBELN, EKBE . EBELP, EKBE . VGABE),104) AS c_EBKE_BLDAT_First,
        CONVERT (varchar(10),MIN(EKBE . BUDAT) OVER ( PARTITION BY EKBE . EBELN, EKBE . EBELP, EKBE . VGABE),104) AS c_EKBE_BUDAT_First,
        CONVERT (varchar(10),MAX(EKBE . BLDAT) OVER ( PARTITION BY EKBE . EBELN, EKBE . EBELP, EKBE . VGABE),104) AS c_EBKE_BLDAT_Last,
        CONVERT (varchar(10),MAX(EKBE . BUDAT) OVER ( PARTITION BY EKBE . EBELN, EKBE . EBELP, EKBE . VGABE),104) AS c_EKBE_BUDAT_Last
        FROM EKPO

LEFT JOIN EKKO 
        ON EKPO . MANDT = EKKO . MANDT
        AND EKPO . EBELN = EKKO . EBELN

LEFT JOIN EKBE
        ON EKPO . MANDT = EKBE . MANDT
        AND EKPO . EBELN = EKBE . EBELN
        AND EKPO . EBELP = EKBE . EBELP

LEFT JOIN DD07T
        ON DD07T . DOMNAME = 'VGABE'
        AND DD07T . DOMVALUE_L = EKBE.VGABE
        AND DD07T . DDLANGUAGE = 'D'
)

SELECT * INTO #preEKBE FROM preEKBE
ORDER BY EBELN , EBELP

它为我生成了这张表

+-------+------------+-------+-----------------------------+-------+---------+----------+---------+--------------------+--------------------+-------------------+-------------------+
| MANDT |   EBELN    | EBELP |          c_Meaning          | VGABE |  DMBTR  |  MENGE   | c_COUNT | c_EBKE_BLDAT_First | c_EKBE_BUDAT_First | c_EBKE_BLDAT_Last | c_EKBE_BUDAT_Last |
+-------+------------+-------+-----------------------------+-------+---------+----------+---------+--------------------+--------------------+-------------------+-------------------+
|   800 | 3000000004 | 00001 | Wareneingang                |     1 | 27.95   | 1.000    |       1 | 19.12.2000         | 19.12.2000         | 19.12.2000        | 19.12.2000        |
|   800 | 3000000004 | 00001 | Rechnungseingang            |     2 | 27.95   | 1.000    |       1 | 19.12.2000         | 21.12.2000         | 19.12.2000        | 21.12.2000        |
|   800 | 3000000004 | 00002 | Wareneingang                |     1 | 10.95   | 1.000    |       1 | 19.12.2000         | 19.12.2000         | 19.12.2000        | 19.12.2000        |
|   800 | 3000000004 | 00002 | Rechnungseingang            |     2 | 10.95   | 1.000    |       1 | 19.12.2000         | 21.12.2000         | 19.12.2000        | 21.12.2000        |
|   800 | 4500008499 | 00010 | Wareneingang                |     1 | 268.43  | 1.000    |       1 | 27.03.2000         | 27.03.2000         | 27.03.2000        | 27.03.2000        |
|   800 | 4500008499 | 00010 | Leistungserfassungsblatt    |     9 | 268.43  | 1.000    |       1 | 27.03.2000         | 27.03.2000         | 27.03.2000        | 27.03.2000        |
|   800 | 4500010470 | 00010 | Wareneingang                |     1 | 0.00    | 1092.000 |       6 | 07.02.2001         | 07.02.2001         | 07.02.2001        | 07.02.2001        |
|   800 | 4500010470 | 00010 | Wareneingang                |     1 | 0.00    | 3512.000 |       6 | 07.02.2001         | 07.02.2001         | 07.02.2001        | 07.02.2001        |
|   800 | 4500010470 | 00010 | Warenausgabe für Umlagerung |     6 | 1615.52 | 3512.000 |       6 | 07.02.2001         | 07.02.2001         | 07.02.2001        | 07.02.2001        |
|   800 | 4500010470 | 00010 | Warenausgabe für Umlagerung |     6 | 502.32  | 1092.000 |       6 | 07.02.2001         | 07.02.2001         | 07.02.2001        | 07.02.2001        |
|   800 | 4500010470 | 00010 | Lieferung zu Umlagerung     |     8 | 0.00    | 1092.000 |       6 | 01.01.1900         | 07.02.2001         | 01.01.1900        | 07.02.2001        |
|   800 | 4500010470 | 00010 | Lieferung zu Umlagerung     |     8 | 0.00    | 3512.000 |       6 | 01.01.1900         | 07.02.2001         | 01.01.1900        | 07.02.2001        |
+-------+------------+-------+-----------------------------+-------+---------+----------+---------+--------------------+--------------------+-------------------+-------------------+

现在我有了一个部分工作的动态 Pivot。

DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + VGABE) 
                    from #preEKBE t
                    cross apply
                    (                    
                      select 'c_DMBTR', 1 union all
                      select 'c_MENGE', 2 union all
                      select 'c_COUNT', 3     
                    ) c (col, so)
                    group by col, so, VGABE
                    order by VGABE, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = 'SELECT EBELN, EBELP,' + @cols + N' 
     from
     (
      select
        t.EBELN,
        t.EBELP,
        new_col = c.orig_col + ''_'' + VGABE,
        c.value
      from #preEKBE t

      cross apply
      (
        select ''c_MENGE'', t.MENGE union all
        select ''c_DMBTR'', t.DMBTR union all
        select ''c_COUNT'', t.c_COUNT 
      ) c (orig_col, value)
     ) x
     pivot 
     (
       sum(value)
       for new_col in (' + @cols + N')
     ) p 
     order by EBELN , EBELP' 
exec sp_executesql @query;

给我一​​个结果:

+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
|   EBELN    | EBELP | c_DMBTR_1 | c_MENGE_1 | c_COUNT_1 | c_DMBTR_2 | c_MENGE_2 | c_COUNT_2 | c_DMBTR_6 | c_MENGE_6 | c_COUNT_6 | c_DMBTR_7 | c_MENGE_7 | c_COUNT_7 | c_DMBTR_8 | c_MENGE_8 | c_COUNT_8 | c_DMBTR_9 | c_MENGE_9 | c_COUNT_9 | c_DMBTR_P | c_MENGE_P | c_COUNT_P | c_DMBTR_R | c_MENGE_R | c_COUNT_R |
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| 3000000004 | 00001 | 27.950    | 1.000     | 1.000     | 27.950    | 1.000     | 1.000     | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      |
| 3000000004 | 00002 | 10.950    | 1.000     | 1.000     | 10.950    | 1.000     | 1.000     | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      | NULL      |
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+

我需要动态查询,因为 VGABE 列要创建新的列名,并且可能存在未使用的值,我只希望使用 VGABE 值。

现在的问题是我想添加更多的列,这些列也应该动态生成。当 VGABE 为 1 时,我需要一个名为 c_Meaning_1 (nvarchar) 的列,它将具有与 DD07T 连接的值。

c_COUNT_ 代表每条记录的每个 VGABE 值的计数。该专栏完美运行。

在这些列之后,我还需要添加列c_BLDAT_First_c_BUDAT_First_c_BLDAT_Last_c_BUDAT_Last_,并将VGABE 的值连接到新列名称的末尾。此值在 CTE 中计算。

有没有办法不用临时表直接使用CTE?

我不知道如何解决这个问题,因为我正在处理多种数据类型,并且它们的聚合方式各不相同。当VGABE 有值 1 和 9 时,它应该如下所示:

+---------------+-----------+-----------+-----------+----------------------+----------------------+---------------------+---------------------+---------------------------+------------+-----------+-----------+----------------------+----------------------+---------------------+---------------------+
|  C_MEANING_1  | C_DMBTR_1 | C_MENGE_1 | C_COUNT_1 | C_EBKE_BLDAT_FIRST_1 | C_EKBE_BUDAT_FIRST_1 | C_EBKE_BLDAT_LAST_1 | C_EKBE_BUDAT_LAST_1 |        C_MEANING_9        | C_DMBTR_9  | C_MENGE_9 | C_COUNT_9 | C_EBKE_BLDAT_FIRST_9 | C_EKBE_BUDAT_FIRST_9 | C_EBKE_BLDAT_LAST_9 | C_EKBE_BUDAT_LAST_9 |
+---------------+-----------+-----------+-----------+----------------------+----------------------+---------------------+---------------------+---------------------------+------------+-----------+-----------+----------------------+----------------------+---------------------+---------------------+
| Wareneingang: | 10,00     |         1 |         1 | 19.12.2000           | 19.12.2000           | 19.12.2000          | 19.12.2000          | Leistungserfassungsblatt: |          0 |         0 |         0 | NULL                 | NULL                 | NULL                | NULL                |
| Wareneingang: | 0         |         0 |         0 | NULL                 | NULL                 | NULL                | NULL                | Leistungserfassungsblatt: |         20 |         2 |         1 | 19.12.2000           | 19.12.2000           | 19.12.2000          | 19.12.2000          |
+---------------+-----------+-----------+-----------+----------------------+----------------------+---------------------+---------------------+---------------------------+------------+-----------+-----------+----------------------+----------------------+---------------------+---------------------+

对于每个VGABE 值,应该按照上面给出的顺序有一个自己的列。如果您需要更多信息,请询问我。我将 SQL Server 2014 与 SQL Management Studio 2014 和 TSQL 一起使用。

【问题讨论】:

也许我没有完全理解这个问题,但是如果您只想返回与VGABE = 1 关联的行,那么您应该能够将WHERE 过滤器添加到动态列生成中。然后,您还将在枢轴的子查询和类似于此demo 的最终选择列表中包含您想要的其他列(c_EBKE_BLDAT_Firstc_EKBE_BUDAT_First 等)。如果这不是您想要的,那么您可能需要更新问题以使其更清楚。 查询应该为 VGABE 中的每个值创建列。因此,当 VGABE 中有值 (1,3,7,R) 时,它应该创建从最低值开始的列_-> c_Meaning_X c_DMBTR_X c_MENGE_X c_COUNT_X c c_BLDAT_First_X c_BUDAT_First_X c_BLDAT_Last_X c_BUDAT_Last_X(其中 X 代表 VGABE 中的值)。列必须按此顺序。 这里比较棘手的是 c_Meaning_X 中的内容取决于 VGABE 中的值,并且在表 DD07T (join) 中。如果有例如 VGABE 9,那么它必须从 DD07T.DDTEXT 为每条记录创建内容为“Leistungserfassungsblatt”的列 c_Meaning_9,无论是否只有一条记录使用 vgabe 9,而其他记录则没有。 当您在演示中删除 WHERE 过滤器时,您会以正确的顺序获得列。最后一项任务是将c_Meaning_X 添加到具有相同VGABE 值的列前面,在c_COUNT_X 之后添加具有DATE (c_EBKE_BLDAT_First_X, c_EKBE_BUDAT_First_X) 的列 【参考方案1】:

好吧,这里有些混乱,因为您想将具有多行的多个列转换为更多列,除此之外,您还需要为每个列使用不同的聚合,因为其中一些您需要SUM 和其他您必须使用 MAXMIN(在字符串/日期上)。

您应该始终尝试使用较小版本的静态查询来使逻辑正确,而不是直接进入动态 sql 版本。在我看来,这使得使用动态 SQL 变得更加容易,因为您无需猜测该做什么或什么不正确。

我首先从一个查询开始,该查询获取您需要求和的每个项目的总数。

select ebeln, ebelp, 
  c_Meaning, 
  vgabe, 
  dmbtr = cast(sum(dmbtr) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
  menge = cast(sum(menge) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
  c_count = cast(sum(c_count) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
  c_EBKE_BLDAT_First = cast(c_EBKE_BLDAT_First as varchar(50)), 
  c_EKBE_BUDAT_First = cast(c_EKBE_BUDAT_First as varchar(50)),
  c_EBKE_BLDAT_Last = cast(c_EBKE_BLDAT_Last as varchar(50)),
  c_EKBE_BUDAT_Last = cast(c_EKBE_BUDAT_Last as varchar(50))
from preEKBE

见SQL Fiddle with Demo。这将获得最终结果中所需的所有值,因为您将获得 ebelnebelpvgabe 组合的总和。您会看到我还将所有值转换为相同的数据类型——这是下一步所必需的——unpivot。由于所有数据都将存储在同一列中,因此它们需要相同的数据类型。

select d.ebeln, d.ebelp,
  new_col = c.orig_col + '_' + cast(d.vgabe as varchar(2)),
  c.value
from
(
  select ebeln, ebelp, 
    c_Meaning, 
    vgabe, 
    dmbtr = cast(sum(dmbtr) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
    menge = cast(sum(menge) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
    c_count = cast(sum(c_count) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
    c_EBKE_BLDAT_First = cast(c_EBKE_BLDAT_First as varchar(50)), 
    c_EKBE_BUDAT_First = cast(c_EKBE_BUDAT_First as varchar(50)),
    c_EBKE_BLDAT_Last = cast(c_EBKE_BLDAT_Last as varchar(50)),
    c_EKBE_BUDAT_Last = cast(c_EKBE_BUDAT_Last as varchar(50))
  from preEKBE
) d
cross apply 
(
  select 'c_Meaning', c_Meaning union all
  select 'c_MENGE', menge union all
  select 'c_DMBTR', dmbtr union all
  select 'c_count', c_count union all
  select 'c_EBKE_BLDAT_First', c_EBKE_BLDAT_First union all
  select 'c_EKBE_BUDAT_First', c_EKBE_BUDAT_First union all
  select 'c_EBKE_BLDAT_Last', c_EBKE_BLDAT_Last union all
  select 'c_EKBE_BUDAT_Last', c_EKBE_BUDAT_Last
) c (orig_col, value)

见SQL Fiddle with Demo。现在你得到了如下所示的数据:

|      EBELN | EBELP |              NEW_COL |                       VALUE |
|------------|-------|----------------------|-----------------------------|
| 3000000004 |     1 |          c_Meaning_1 |                Wareneingang |
| 3000000004 |     1 |            c_MENGE_1 |                           1 |
| 3000000004 |     1 |            c_DMBTR_1 |                       27.95 |
| 3000000004 |     1 |            c_count_1 |                           1 |
| 3000000004 |     1 | c_EBKE_BLDAT_First_1 |                  19.12.2000 |
| 3000000004 |     1 | c_EKBE_BUDAT_First_1 |                  19.12.2000 |

最后,您将应用 PIVOT 函数:

select ebeln, 
  ebelp,
  c_Meaning_1, c_MENGE_1, c_DMBTR_1, c_count_1,
  c_EBKE_BLDAT_First_1, c_EKBE_BUDAT_First_1,
  c_EBKE_BLDAT_Last_1, c_EKBE_BUDAT_Last_1
from
(
  select d.ebeln, d.ebelp,
    new_col = c.orig_col + '_' + cast(d.vgabe as varchar(2)),
    c.value
  from
  (
    select ebeln, ebelp, 
      c_Meaning, 
      vgabe, 
      dmbtr = cast(sum(dmbtr) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
      menge = cast(sum(menge) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
      c_count = cast(sum(c_count) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
      c_EBKE_BLDAT_First = cast(c_EBKE_BLDAT_First as varchar(50)), 
      c_EKBE_BUDAT_First = cast(c_EKBE_BUDAT_First as varchar(50)),
      c_EBKE_BLDAT_Last = cast(c_EBKE_BLDAT_Last as varchar(50)),
      c_EKBE_BUDAT_Last = cast(c_EKBE_BUDAT_Last as varchar(50))
    from preEKBE
  ) d
  cross apply 
  (
    select 'c_Meaning', c_Meaning union all
    select 'c_MENGE', menge union all
    select 'c_DMBTR', dmbtr union all
    select 'c_count', c_count union all
    select 'c_EBKE_BLDAT_First', c_EBKE_BLDAT_First union all
    select 'c_EKBE_BUDAT_First', c_EKBE_BUDAT_First union all
    select 'c_EBKE_BLDAT_Last', c_EBKE_BLDAT_Last union all
    select 'c_EKBE_BUDAT_Last', c_EKBE_BUDAT_Last
  ) c (orig_col, value)
) src
pivot
(
  max(value)
  for new_col in (c_Meaning_1, c_MENGE_1, c_DMBTR_1, c_count_1,
                  c_EBKE_BLDAT_First_1, c_EKBE_BUDAT_First_1,
                  c_EBKE_BLDAT_Last_1, c_EKBE_BUDAT_Last_1)
) piv;

见SQL Fiddle with Demo。

现在您有了工作逻辑,您可以将其转换为动态 sql:

DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + cast(VGABE as varchar(2))) 
                    from preEKBE t
                    cross apply
                    (   
                      select 'c_meaning', 0 union all
                      select 'c_DMBTR', 1 union all
                      select 'c_MENGE', 2 union all
                      select 'c_COUNT', 3 union all
                      select 'c_EBKE_BLDAT_FIRST', 4 union all
                      select 'c_EKBE_BUDAT_FIRST', 5 union all
                      select 'c_EBKE_BLDAT_LAST', 6 union all
                      select 'c_EKBE_BUDAT_LAST', 7
                    ) c (col, so)
                    group by col, so, VGABE
                    order by VGABE, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query 
  = 'SELECT EBELN, EBELP, ' + @cols + N' 
     from
     (
      select d.ebeln, 
        d.ebelp,
        new_col = c.orig_col + ''_'' + cast(d.vgabe as varchar(2)),
        c.value
      from
      (
        select ebeln, ebelp, 
          c_Meaning, 
          vgabe, 
          dmbtr = cast(sum(dmbtr) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
          menge = cast(sum(menge) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
          c_count = cast(sum(c_count) over(partition by ebeln, ebelp, vgabe) as varchar(50)),
          c_EBKE_BLDAT_First = cast(c_EBKE_BLDAT_First as varchar(50)), 
          c_EKBE_BUDAT_First = cast(c_EKBE_BUDAT_First as varchar(50)),
          c_EBKE_BLDAT_Last = cast(c_EBKE_BLDAT_Last as varchar(50)),
          c_EKBE_BUDAT_Last = cast(c_EKBE_BUDAT_Last as varchar(50))
        from preEKBE
      ) d
      cross apply
      (
        select ''c_meaning'', d.c_meaning union all
        select ''c_MENGE'', d.MENGE union all
        select ''c_DMBTR'', d.DMBTR union all
        select ''c_COUNT'', d.c_COUNT union all
        select ''c_EBKE_BLDAT_First'', d.c_EBKE_BLDAT_First union all
        select ''c_EKBE_BUDAT_First'', d.c_EKBE_BUDAT_First union all
        select ''c_EBKE_BLDAT_Last'', d.c_EBKE_BLDAT_Last union all
        select ''c_EKBE_BUDAT_Last'', d.c_EKBE_BUDAT_Last
      ) c (orig_col, value)
     ) x
     pivot 
     (
       max(value)
       for new_col in (' + @cols + N')
     ) p 
     order by EBELN , EBELP' 

exec sp_executesql @query;

见SQL Fiddle with Demo。这给出了最终结果:

|      EBELN | EBELP |  C_MEANING_1 | C_DMBTR_1 | C_MENGE_1 | C_COUNT_1 | C_EBKE_BLDAT_FIRST_1 | C_EKBE_BUDAT_FIRST_1 | C_EBKE_BLDAT_LAST_1 | C_EKBE_BUDAT_LAST_1 |      C_MEANING_2 | C_DMBTR_2 | C_MENGE_2 | C_COUNT_2 | C_EBKE_BLDAT_FIRST_2 | C_EKBE_BUDAT_FIRST_2 | C_EBKE_BLDAT_LAST_2 | C_EKBE_BUDAT_LAST_2 |                 C_MEANING_6 | C_DMBTR_6 | C_MENGE_6 | C_COUNT_6 | C_EBKE_BLDAT_FIRST_6 | C_EKBE_BUDAT_FIRST_6 | C_EBKE_BLDAT_LAST_6 | C_EKBE_BUDAT_LAST_6 |             C_MEANING_8 | C_DMBTR_8 | C_MENGE_8 | C_COUNT_8 | C_EBKE_BLDAT_FIRST_8 | C_EKBE_BUDAT_FIRST_8 | C_EBKE_BLDAT_LAST_8 | C_EKBE_BUDAT_LAST_8 |              C_MEANING_9 | C_DMBTR_9 | C_MENGE_9 | C_COUNT_9 | C_EBKE_BLDAT_FIRST_9 | C_EKBE_BUDAT_FIRST_9 | C_EBKE_BLDAT_LAST_9 | C_EKBE_BUDAT_LAST_9 |
|------------|-------|--------------|-----------|-----------|-----------|----------------------|----------------------|---------------------|---------------------|------------------|-----------|-----------|-----------|----------------------|----------------------|---------------------|---------------------|-----------------------------|-----------|-----------|-----------|----------------------|----------------------|---------------------|---------------------|-------------------------|-----------|-----------|-----------|----------------------|----------------------|---------------------|---------------------|--------------------------|-----------|-----------|-----------|----------------------|----------------------|---------------------|---------------------|
| 3000000004 |     1 | Wareneingang |     27.95 |         1 |         1 |           19.12.2000 |           19.12.2000 |          19.12.2000 |          19.12.2000 | Rechnungseingang |     27.95 |         1 |         1 |           19.12.2000 |           21.12.2000 |          19.12.2000 |          21.12.2000 |                      (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |                  (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |                   (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |
| 3000000004 |     2 | Wareneingang |     10.95 |         1 |         1 |           19.12.2000 |           19.12.2000 |          19.12.2000 |          19.12.2000 | Rechnungseingang |     10.95 |         1 |         1 |           19.12.2000 |           21.12.2000 |          19.12.2000 |          21.12.2000 |                      (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |                  (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |                   (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |
| 4500008499 |    10 | Wareneingang |    268.43 |         1 |         1 |           27.03.2000 |           27.03.2000 |          27.03.2000 |          27.03.2000 |           (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |                      (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |                  (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) | Leistungserfassungsblatt |    268.43 |         1 |         1 |           27.03.2000 |           27.03.2000 |          27.03.2000 |          27.03.2000 |
| 4500010470 |    10 | Wareneingang |      0.00 |      4604 |        12 |           07.02.2001 |           07.02.2001 |          07.02.2001 |          07.02.2001 |           (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) | Warenausgabe für Umlagerung |   2117.84 |      4604 |        12 |           07.02.2001 |           07.02.2001 |          07.02.2001 |          07.02.2001 | Lieferung zu Umlagerung |      0.00 |      4604 |        12 |           01.01.1900 |           07.02.2001 |          01.01.1900 |          07.02.2001 |                   (null) |    (null) |    (null) |    (null) |               (null) |               (null) |              (null) |              (null) |

【讨论】:

天哪,老兄!你太棒了。这就是我所说的。我尝试使用 MAX() 进行思考,但没有在 MAX() 之前对每条记录进行 SUM()。太好了,非常感谢您的耐心和时间阅读我的神秘帖子。我想知道如何解决 c_Meaning 中的 NULL 值的问题。一旦有一列带有 c_Meaning_1 我希望每条记录都有值“Wareneingang:”等等.. 没有足够的 Markdown 来强调 always 这个词。有些人似乎根本不明白。

以上是关于具有动态生成列、聚合函数和无聚合列的 SQL Pivot的主要内容,如果未能解决你的问题,请参考以下文章

SQL聚合函数

动态 SQL 透视查询中的分组和聚合函数

Pandas Dataframe groupby 聚合函数和动态列的最大值和最小值之间的差异

同一列上具有多个聚合的 T-SQL Pivot

SQL语句汇总——聚合函数分组子查询及组合查询

具有特定列的RadDataGrid,C#中的聚合和分组