【发布时间】:2021-12-28 16:21:54
【问题描述】:
我有几个表(在 SQL Server 2014 SP2 数据库中),我试图在这些表上进行透视,并且我试图从其中一个表中重命名一些列。
表格如下所示:
数据源快照
| snapshotId | snapshotTime |
-----------------------------------
| 1 | 2021-12-01 07:00 |
| 2 | 2021-12-02 07:00 |
...
数据源
| snapshotId | dsRecordId | dsId | dsName | dsTableDate |
---------------------------------------------------------------
| 1 | 1 | 1 | cpu | 2021-12-01 07:00 |
| 1 | 2 | 2 | mem | 2021-12-01 07:00 |
| 1 | 3 | 3 | cache | 2021-12-01 07:00 |
| 2 | 4 | 1 | cpu | 2021-12-01 07:00 |
| 2 | 5 | 2 | mem | 2021-12-01 07:00 |
| 2 | 6 | 3 | cache | 2021-12-01 07:00 |
...
数据源属性
这是一个截断的数据源属性列表。
| dsRecordId | dsPropPropertyRecordId | dsPropPropertyName | dsPropPropertyValue |
----------------------------------------------------------------------------------
| 1 | 1 | id | 1 |
| 1 | 2 | description | cpu stats |
| 1 | 3 | name | cpu |
| 1 | 4 | collectInterval | 300 |
| 1 | 5 | group | |
| 1 | 6 | dataPoints | System.Object[] |
| 2 | 7 | id | 2 |
| 2 | 8 | description | memory stats |
| 2 | 9 | name | mem |
| 2 | 10 | collectInterval | 300 |
| 2 | 11 | group | |
| 2 | 12 | dataPoints | System.Object[] |
| 3 | 13 | id | 3 |
| 3 | 14 | description | |
| 3 | 15 | name | cache |
| 3 | 16 | collectInterval | 600 |
| 3 | 17 | group | |
| 3 | 18 | dataPoints | System.Object[] |
...
数据点属性
这是一个截断的数据点属性列表。
| dsRecordId | dpRecordId | dpPropertyName | dpPropertyValue |
-----------------------------------------------------------------
| 1 | 1 | id | 1 |
| 1 | 2 | datasourceId | 1 |
| 1 | 3 | name | cpuState |
| 1 | 4 | description | |
| 1 | 5 | alertExpr | != 0 0 |
| 1 | 6 | type | 2 |
| 1 | 7 | id | 2 |
| 1 | 8 | datasourceId | 1 |
| 1 | 9 | name | freePercent |
| 1 | 10 | description | |
| 1 | 11 | alertExpr | >= 90 90 |
| 1 | 12 | type | 2 |
| 2 | 13 | id | 3 |
| 2 | 14 | datasourceId | 2 |
| 2 | 15 | name | freePercent |
| 2 | 16 | description | Memory utilization |
| 2 | 17 | alertExpr | >= 90 90 |
| 2 | 18 | type | 2 |
| 3 | 19 | id | 4 |
| 3 | 20 | datasourceId | 3 |
| 3 | 21 | name | state |
| 3 | 22 | description | |
| 3 | 23 | alertExpr | = 1 1 1 |
| 3 | 24 | type | 4 |
...
我正在尝试为每个数据源(但仅是该数据源条目的最新实例)和每个数据点(包括所有数据源属性)获取一行,其中数据点属性被旋转以使其成为列。像这样的:
| dsRecordId | id | description | name | collectInterval | group | dataPoints | dp_id | dp_datasourceId | dp_name | dp_description | dp_alertExpr | dp_type |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | 1 | cpu stats | cpu | 300 | | System.Object[] | 1 | 1 | cpuState | | != 0 0 | 2 |
| 1 | 1 | cpu stats | cpu | 300 | | System.Object[] | 2 | 1 | freePercent | | >= 90 90 | 2 |
| 2 | 2 | memory stats | mem | 300 | | System.Object[] | 3 | 2 | freePercent | Memory utilization | >= 90 90 | 2 |
| 3 | 3 | | cache | 600 | | System.Object[] | 4 | 3 | state | | = 1 1 1 | 4 |
我有一些 T-SQL 可以进行数据透视,但是因为数据源和数据点都具有 id、名称和描述属性,所以我必须在数据透视中排除这些属性。这个查询:
DECLARE
@dsPropPropertyColumns NVARCHAR(MAX) = '',
@dpPropertyColumns NVARCHAR(MAX) = '',
@sql NVARCHAR(MAX) = '';
-- select the property names
--- properties in the datasourceProperty table
SELECT @dsPropPropertyColumns = (
SELECT DISTINCT '[' + [dsPropPropertyName] + ']' + ','
FROM dbo.dataSourceSnapshot dss
LEFT OUTER JOIN dbo.datasource ds ON ds.snapshotId = dss.snapshotId
LEFT OUTER JOIN dbo.datasourceProperty dsp ON dsp.dsRecordId = ds.dsRecordId
WHERE dss.snapshotTime = (
SELECT MAX(snapshotTime) FROM dbo.dataSourceSnapshot
)
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)')
--- properties in the datapointProperty table
SELECT @dpPropertyColumns = (
SELECT DISTINCT '[' + [dpPropertyName] + ']' + ','
FROM dbo.dataSourceSnapshot dss
LEFT OUTER JOIN dbo.datasource ds ON ds.snapshotId = dss.snapshotId
LEFT OUTER JOIN dbo.datapointProperty dp ON dp.dsRecordId = ds.dsRecordId
WHERE dss.snapshotTime = (
SELECT MAX(snapshotTime) FROM dbo.dataSourceSnapshot
)
AND [dpPropertyName] NOT IN ('name','id', 'description')
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)')
-- remove the trailing comma
SET @dsPropPropertyColumns = LEFT(@dsPropPropertyColumns, LEN(@dsPropPropertyColumns) - 1);
SET @dpPropertyColumns = LEFT(@dpPropertyColumns, LEN(@dpPropertyColumns) - 1);
-- construct dynamic SQL
SET @sql ='
SELECT * FROM (
SELECT dsp.dsRecordId, dsp.dsPropPropertyName, dsp.dsPropPropertyValue, dp.dpPropertyName, dp.dpPropertyValue
FROM dbo.snapshot dss
LEFT OUTER JOIN dbo.datasource ds ON ds.snapshotId = dss.snapshotId
LEFT OUTER JOIN dbo.datasourceProperty dsp ON dsp.dsRecordId = ds.dsRecordId
LEFT OUTER JOIN dbo.datapointProperty dp ON dp.dsRecordId = ds.dsRecordId
WHERE dss.snapshotTime = (
SELECT MAX(snapshotTime) FROM dbo.dataSourceSnapshot
)
) t1
PIVOT (
MAX(dsPropPropertyValue) FOR dsPropPropertyName IN ('+ @dsPropPropertyColumns +')
) AS pivot_table
PIVOT (
MAX(dpPropertyValue) FOR dpPropertyName IN ('+ @dpPropertyColumns +')
) AS pivot_table2
ORDER BY id
'
EXECUTE sp_executesql @sql;
产生这个输出:
| dsRecordId | id | description | name | collectInterval | group | dataPoints | datasourceId | alertExpr | type |
----------------------------------------------------------------------------------------------------------------------------
| 1 | 1 | cpu stats | cpu | 300 | | System.Object[] | 1 | != 0 0 | 2 |
| 1 | 1 | cpu stats | cpu | 300 | | System.Object[] | 1 | >= 90 90 | 2 |
| 2 | 2 | memory stats | mem | 300 | | System.Object[] | 2 | >= 90 90 | 2 |
| 3 | 3 | | cache | 600 | | System.Object[] | 3 | = 1 1 1 | 4 |
我在第 38 行有 Select *...,因为我不知道所有属性名称。在我写这篇文章时,我突然想到,也许我可以以某种方式使用列名变量(@dsPropPropertyColumns 和@dpPropertyColumns)?那会是什么样子?
我查看了以下问题,但我认为它们没有回答我的问题:
问题是:如何动态生成用于透视的列列表,并将“dp_”添加到 datasourceProperty 表中的每个列名,这样我就可以包含 id;姓名;和描述列没有得到“重复的列名”错误?我认为这将产生所需的输出。
【问题讨论】:
-
我不明白这有什么帮助,你能更具体一点吗?我可以使用您的建议生成列表属性,但我仍然会得到两个“id”列:
SELECT '[' + [dsPropPropertyName] + ']' + ',' FROM dbo.snapshot dss LEFT OUTER JOIN dbo.datasource ds ON ds.snapshotId = dss.snapshotId LEFT OUTER JOIN dbo.datasourceProperty dsp ON dsp.dsRecordId = ds.dsRecordId WHERE dss.snapshotTime = ( SELECT MAX(dataSourceSnapshotTime) FROM logicmonitor.dataSourceSnapshot ) GROUP BY [dsPropPropertyName] -
SELECT @dpPropertyColumns = ( SELECT DISTINCT quotename(concat('dp_',[dpPropertyName])) ...SET @sql ='SELECT * FROM (...dsp.dsPropPropertyValue, concat('dp_', dp.dpPropertyName) as dpPropertyName, dp.dpPropertyValue ... -
@lptr,我进行了更改,现在我有了“dp_”列,这很棒。我没有的是每个数据点的一行。我认为枢轴会发生这种情况,因为有多个实例。
-
如果每个 dsRecordId 有多个数据点实例,则为数据点分配一个“分组编号”
SET @sql ='SELECT * FROM (...row_number() over(partition by dp.dsRecordId, dp.dpPropertyName order by dp.dpRecordId) as datapointrn,... -
这并没有达到我的预期。为了清楚起见(并合并引用名/concat),我创建了Output multiple rows after joining and pivoting multiple tables。我会将此标记为已回答。
标签: sql sql-server