一尘不染

使用sql选择的值作为另一个选择的行名

sql

在MSSQL服务器上,给出以下表:

TABLE values {
    int id;
    timestamp date;
    int value;
}

TABLE value_type {
    int value_id; // foreign key on values.id
    text name;
}

我可以发出类似的查询:

SELECT date, name, value
FROM values
LEFT JOIN value_type ON value_id = id;

并得到类似:

+----------+------+-------+
| date     | name | value |
+----------+------+-------+
| 01.01.10 | foo  |  1.0  |
+----------+------+-------+
| 01.01.10 | bar  |  2.0  |
+----------+------+-------+
| 02.01.10 | bar  |  4.0  |
+----------+------+-------+
| 03.01.10 | foo  |  5.0  |
+----------+------+-------+

如果我想要这样的数据,查询数据库的最有效方法是什么?

+----------+------+-------+
| date     | foo  | bar   |
+----------+------+-------+
| 01.01.10 | 1.0  |  2.0  |
+----------+------+-------+
| 02.01.10 | NULL |  4.0  |
+----------+------+-------+
| 03.01.10 | 5.0  |  NULL |
+----------+------+-------+

数据库结构要复杂得多,不幸的是我无法更改它。

编辑 :解决方案不应在查询中使用foobar作为硬编码值。


阅读 158

收藏
2021-03-08

共1个答案

一尘不染

对于SQL Server 2005+,可以使用动态SQL和PIVOT

DECLARE @ValuesNames NVARCHAR(4000), @Query NVARCHAR(MAX)
SET @ValuesNames = ''

SELECT @ValuesNames = @ValuesNames + QUOTENAME([name]) + ','
FROM [values] A
INNER JOIN value_type B
ON B.value_id = A.id
GROUP BY [name]
ORDER BY [name]

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

SET @Query = '
SELECT [date], '+@ValuesNames+'
FROM (  SELECT [date], [name], value
        FROM [values]
        LEFT JOIN value_type ON value_id = id) A
PIVOT(SUM(value) FOR [name] IN ('+@ValuesNames+')) AS PT
'
EXEC sp_executesql @Query
2021-03-08