Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用派生值可能多次出现的多列的动态透视_Sql_Sql Server_Tsql_Pivot - Fatal编程技术网

Sql 使用派生值可能多次出现的多列的动态透视

Sql 使用派生值可能多次出现的多列的动态透视,sql,sql-server,tsql,pivot,Sql,Sql Server,Tsql,Pivot,我试图找到一种方法,根据两列中的值动态地透视结果集 我有一个非常基本的查询,它返回与特定作业关联的事件的信息 SELECT num, dat, [jobevtcls-cde] ,cde FROM jobevt WHERE (num = 3177564) ORDER BY cde 查询结果如下: +=========+============+===============+=====+ | num | dat | jobevtcls-cde | cde | +====

我试图找到一种方法,根据两列中的值动态地透视结果集

我有一个非常基本的查询,它返回与特定作业关联的事件的信息

SELECT num, dat, [jobevtcls-cde] ,cde
FROM jobevt
WHERE   (num = 3177564)
ORDER BY cde
查询结果如下:

+=========+============+===============+=====+
|   num   |    dat     | jobevtcls-cde | cde |
+=========+============+===============+=====+
| 3177564 | 2021-02-24 | SYS           |  10 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  40 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  40 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  40 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  42 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  60 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  60 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           |  89 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           | 100 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           | 115 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | GEN           | 120 |
+---------+------------+---------------+-----+
| 3177564 | 2021-03-01 | GEN           | 120 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-26 | GEN           | 160 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           | 198 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | GEN           | 210 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-26 | GEN           | 220 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | GEN           | 310 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-26 | GEN           | 310 |
+---------+------------+---------------+-----+
| 3177564 | 2021-02-24 | SYS           | 422 |
+---------+------------+---------------+-----+
我希望将此数据透视,以将cde+[jobevtcls cde]显示为列标题,并将MAX(dat)显示为行值

下面的代码首先抱怨D中的第四列没有名字,所以我很难找出那个名字。SQL抱怨的另一件事是同一代码的多个实例,例如SYS40

DECLARE @JobEventKey NVARCHAR(MAX) = ''
DECLARE @SQL NVARCHAR(MAX) = ''

SELECT @JobEventKey += QUOTENAME([jobevtcls-cde] + CAST(cde AS VARCHAR(10))) + ','
FROM jobevt

WHERE jobevt.num = '3177564'

SET @JobEventKey = LEFT(@JobEventKey, LEN(@JobEventKey) -1)

SET @SQL = 

'SELECT * FROM
    (SELECT
         num
        ,dat
        ,cde
        ,[jobevtcls-cde] + CAST(cde AS VARCHAR(10))
    FROM
        jobevt
    WHERE
        (num = 3177564)
) AS D

PIVOT (
    MAX(dat)
    FOR cde IN (' + @JobEventKey +
    ')
) AS P'

EXECUTE sp_executesql @SQL
我对这类事情还比较陌生,所以任何指导都非常感谢。

我想知道为什么“相当新”的人总是倾向于从更复杂的东西开始,比如动态SQL?不管怎样,您的解决方案已经接近成功,而且错误很容易修复

动态SQL的一般指导原则:分步构建解决方案,并打印构造的查询(部分),以便在其构造过程中进行验证。这允许您执行构造的查询以验证结果

错误

没有为“D”的第4列指定列名

动态SQL查询中的子查询
D
缺少列名或别名。添加带有
as
的别名

为“p”多次指定了列“SYS40”

@JobEventKey
构建值的方法将生成一个类似
[SYS10]、[SYS40]、[SYS40]、…
的字符串。透视结果中的
pivot
列列表
P
需要唯一的列名。添加一个
分组依据
,以避免重复

DECLARE @JobEventKey NVARCHAR(MAX) = ''
DECLARE @SQL NVARCHAR(MAX) = ''

SELECT @JobEventKey += QUOTENAME(cls + CAST(cde AS VARCHAR(10))) + ','
FROM jobevt

WHERE jobevt.num = '3177564'
--> num=3177564 contains multiple rows for "[SYS40]"
--> the contatenations contains duplicates!

SET @JobEventKey = LEFT(@JobEventKey, LEN(@JobEventKey) -1)

SET @SQL = 

'SELECT * FROM
    (SELECT
         num
        ,dat
        ,cde
        ,cls + CAST(cde AS VARCHAR(10)) --> 4th column missing a name / alias!
    FROM
        jobevt
    WHERE
        (num = 3177564)
) AS D

PIVOT (
    MAX(dat)
    FOR cde IN (' + @JobEventKey +
    ')
) AS P'

EXECUTE sp_executesql @SQL
改进版

小调整:

  • 将nvarchar(最大值)替换为更合理的内容(取决于您的数据)
  • 尽可能使用表别名
  • 不要在整数值周围加引号(对于整型列)
  • 为数据透视后的排序列添加排序依据
最后,工作查询:

DECLARE @JobEventKey NVARCHAR(1000) = '';

SELECT @JobEventKey += QUOTENAME(je.cls + CONVERT(NVARCHAR(10), je.cde)) + ','
FROM jobevt je
WHERE je.num = 3177564
group by QUOTENAME(je.cls + CONVERT(NVARCHAR(10), je.cde))
order by QUOTENAME(je.cls + CONVERT(NVARCHAR(10), je.cde));

SET @JobEventKey = LEFT(@JobEventKey, LEN(@JobEventKey)-1);

-- validate keys
select @JobEventKey;

DECLARE @sql NVARCHAR(2000) = 
'SELECT P.*
 FROM ( SELECT je.num
              ,je.dat
              ,je.cls + CONVERT(NVARCHAR(10), cde) as clscde
        FROM jobevt je
        WHERE je.num = 3177564 ) AS d
 PIVOT (MAX(d.dat) FOR d.clscde IN (' + @JobEventKey + ')) AS P'

-- validate sql
select @sql;

-- execute
EXECUTE sp_executesql @sql;
结果

用于复制的数据:

create table jobevt
(
  num int,
  dat date,
  cls nvarchar(3),
  cde int
);


insert into jobevt (num, dat, cls, cde) values
(3177564, '2021-02-24', 'SYS',  10),
(3177564, '2021-02-24', 'SYS',  40),
(3177564, '2021-02-24', 'SYS',  40),
(3177564, '2021-02-24', 'SYS',  40),
(3177564, '2021-02-24', 'SYS',  42),
(3177564, '2021-02-24', 'SYS',  60),
(3177564, '2021-02-24', 'SYS',  60),
(3177564, '2021-02-24', 'SYS',  89),
(3177564, '2021-02-24', 'SYS', 100),
(3177564, '2021-02-24', 'SYS', 115),
(3177564, '2021-02-24', 'GEN', 120),
(3177564, '2021-03-01', 'GEN', 120),
(3177564, '2021-02-26', 'GEN', 160),
(3177564, '2021-02-24', 'SYS', 198),
(3177564, '2021-02-24', 'GEN', 210),
(3177564, '2021-02-26', 'GEN', 220),
(3177564, '2021-02-24', 'GEN', 310),
(3177564, '2021-02-26', 'GEN', 310),
(3177564, '2021-02-24', 'SYS', 422);
结果:

num      GEN120      GEN160      GEN210      GEN220      GEN310      SYS10       SYS100      SYS115      SYS198      SYS40       SYS42       SYS422      SYS60       SYS89
-------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------
3177564  2021-03-01  2021-02-26  2021-02-24  2021-02-26  2021-02-26  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24
我想知道为什么“相当新”的人总是倾向于从更复杂的东西开始,比如动态SQL?不管怎样,您的解决方案已经接近成功,而且错误很容易修复

动态SQL的一般指导原则:分步构建解决方案,并打印构造的查询(部分),以便在其构造过程中进行验证。这允许您执行构造的查询以验证结果

错误

没有为“D”的第4列指定列名

动态SQL查询中的子查询
D
缺少列名或别名。添加带有
as
的别名

为“p”多次指定了列“SYS40”

@JobEventKey
构建值的方法将生成一个类似
[SYS10]、[SYS40]、[SYS40]、…
的字符串。透视结果中的
pivot
列列表
P
需要唯一的列名。添加一个
分组依据
,以避免重复

DECLARE @JobEventKey NVARCHAR(MAX) = ''
DECLARE @SQL NVARCHAR(MAX) = ''

SELECT @JobEventKey += QUOTENAME(cls + CAST(cde AS VARCHAR(10))) + ','
FROM jobevt

WHERE jobevt.num = '3177564'
--> num=3177564 contains multiple rows for "[SYS40]"
--> the contatenations contains duplicates!

SET @JobEventKey = LEFT(@JobEventKey, LEN(@JobEventKey) -1)

SET @SQL = 

'SELECT * FROM
    (SELECT
         num
        ,dat
        ,cde
        ,cls + CAST(cde AS VARCHAR(10)) --> 4th column missing a name / alias!
    FROM
        jobevt
    WHERE
        (num = 3177564)
) AS D

PIVOT (
    MAX(dat)
    FOR cde IN (' + @JobEventKey +
    ')
) AS P'

EXECUTE sp_executesql @SQL
改进版

小调整:

  • 将nvarchar(最大值)替换为更合理的内容(取决于您的数据)
  • 尽可能使用表别名
  • 不要在整数值周围加引号(对于整型列)
  • 为数据透视后的排序列添加排序依据
最后,工作查询:

DECLARE @JobEventKey NVARCHAR(1000) = '';

SELECT @JobEventKey += QUOTENAME(je.cls + CONVERT(NVARCHAR(10), je.cde)) + ','
FROM jobevt je
WHERE je.num = 3177564
group by QUOTENAME(je.cls + CONVERT(NVARCHAR(10), je.cde))
order by QUOTENAME(je.cls + CONVERT(NVARCHAR(10), je.cde));

SET @JobEventKey = LEFT(@JobEventKey, LEN(@JobEventKey)-1);

-- validate keys
select @JobEventKey;

DECLARE @sql NVARCHAR(2000) = 
'SELECT P.*
 FROM ( SELECT je.num
              ,je.dat
              ,je.cls + CONVERT(NVARCHAR(10), cde) as clscde
        FROM jobevt je
        WHERE je.num = 3177564 ) AS d
 PIVOT (MAX(d.dat) FOR d.clscde IN (' + @JobEventKey + ')) AS P'

-- validate sql
select @sql;

-- execute
EXECUTE sp_executesql @sql;
结果

用于复制的数据:

create table jobevt
(
  num int,
  dat date,
  cls nvarchar(3),
  cde int
);


insert into jobevt (num, dat, cls, cde) values
(3177564, '2021-02-24', 'SYS',  10),
(3177564, '2021-02-24', 'SYS',  40),
(3177564, '2021-02-24', 'SYS',  40),
(3177564, '2021-02-24', 'SYS',  40),
(3177564, '2021-02-24', 'SYS',  42),
(3177564, '2021-02-24', 'SYS',  60),
(3177564, '2021-02-24', 'SYS',  60),
(3177564, '2021-02-24', 'SYS',  89),
(3177564, '2021-02-24', 'SYS', 100),
(3177564, '2021-02-24', 'SYS', 115),
(3177564, '2021-02-24', 'GEN', 120),
(3177564, '2021-03-01', 'GEN', 120),
(3177564, '2021-02-26', 'GEN', 160),
(3177564, '2021-02-24', 'SYS', 198),
(3177564, '2021-02-24', 'GEN', 210),
(3177564, '2021-02-26', 'GEN', 220),
(3177564, '2021-02-24', 'GEN', 310),
(3177564, '2021-02-26', 'GEN', 310),
(3177564, '2021-02-24', 'SYS', 422);
结果:

num      GEN120      GEN160      GEN210      GEN220      GEN310      SYS10       SYS100      SYS115      SYS198      SYS40       SYS42       SYS422      SYS60       SYS89
-------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------  ----------
3177564  2021-03-01  2021-02-26  2021-02-24  2021-02-26  2021-02-26  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24  2021-02-24

看看事情的实际情况。

你只需为第一段投赞成票。顺便说一句,标量变量聚合是不确定的,而且相当危险,您最好使用
string\u agg
for xml path
仅在第一段中就可以获得一个向上投票。顺便说一句,标量变量聚合是不确定的,而且相当危险,您最好使用
string\u agg
作为xml路径