在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 |
+----------+------+-------+
数据库结构要复杂得多,不幸的是我无法改变它。
编辑:解决方案不应将foo
和bar
用作查询中的硬编码值。
答案 0 :(得分:2)
您可以在日期group by
:
SELECT Date
, max(case when vt.name = 'foo' then v.value end) as Foo
, max(case when vt.name = 'bar' then v.value end) as Bar
FROM Values v
LEFT JOIN
value_type vt
ON vt.value_id = v.id
group by
Date
顺便说一句,外键似乎不寻常。我希望value_type
表中的values
列,而不是value_id
表中的values_type
列!有比值类型更多的值,对吗?
create table [values] (id int, date datetime, value float)
insert [values] values (1, '2010-01-01', 1.0)
insert [values] values (2, '2010-01-01', 2.0)
insert [values] values (3, '2010-01-02', 4.0)
insert [values] values (4, '2010-01-03', 5.0)
create table value_types (value_id int, name varchar(max))
insert value_types values (1,'foo'), (2,'bar'), (3,'bar'), (4,'foo')
declare @sql varchar(max)
set @sql = ''
select @sql = @sql + ', max(case when vt.name = ''' +
name + ''' then v.value end) as ' + name + CHAR(13) + CHAR(10)
from value_types
group by
name
set @sql = 'SELECT Date
' + @sql +
'FROM [values] v
LEFT JOIN
value_types vt
ON vt.value_id = v.id
group by
Date'
exec (@sql)
打印:
Date bar foo
----------- ------- -------
2010-01-01 2 1
2010-01-02 4 NULL
2010-01-03 NULL 5
答案 1 :(得分:2)
对于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
答案 2 :(得分:0)
根据新要求更新: 您需要为查询动态生成SQL语句,或者如果要将其加载到应用程序中,则可以转换原始查询或类似查询中的数据。
答案 3 :(得分:0)
未经测试:你可以定义一个视图来连接pk-fk对上的表,然后尝试这样的事情:
Select date,
case name when "foo" then value else null end as foo,
case name when "base" then value else null end as bar
from mytable
order by date
您需要提前知道可能值的范围。
为了使其更灵活,您可以从存储过程中“name”的不同值构建动态case语句,并在此字符串上调用exec()。