SQL查询动态列的方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL查询动态列的方法相关的知识,希望对你有一定的参考价值。
有一个表,列名为包括name varchar(10),month_t varchar(7),D1 int,D2 int,D3 int,D4 int,D5 int,D6 int,D7 int ......D31 int 共33列。
现在给一个变量@day int,
当这个变量为1时,执行查询 select * from 表 where D1=1
当这个变量为2时,执行查询 select * from 表 where D2=2
当这个变量为3时,执行查询 select * from 表 where D3=3
......
当这个变量为31时,执行查询 select * from 表 where D31=31
请问这个存储过程怎么写??
fangliang911的猜想完全正确。
就事论事吧
create proc xxx @day int
as
if @day=1 select * from 表 where D1=@day
if @day=2 select * from 表 where D2=@day
if @day=3 select * from 表 where D3=@day
if @day=4 select * from 表 where D4=@day
后面就不写了,共要31行,恐怕也是最好想出的办法了 参考技术B 你这貌似 只能一个一个判断:
create procedure pro_info
@day int
as
if @day=1
begin
select * from 表 where d1=1
end
if..... 参考技术C Oracle 数据库:
create or replace PROCEDURE XXX(
day INTEGER;
)IS
v_sql VARCHAR;
BEGIN
v_sql := 'select * from 表 where D'||to_char(day)||'='||to_char(day);
Execute immediate v_sql;
END; 参考技术D create proc xxx @day int
as
declare @D int
set @D=@D+@day
select * from 表 where @D=@day 第5个回答 2008-07-03 晕,有这样建库的?
SQL Server 2005 中带有动态列的交叉表查询
【中文标题】SQL Server 2005 中带有动态列的交叉表查询【英文标题】:Crosstab Query with Dynamic Columns in SQL Server 2005 up 【发布时间】:2012-09-07 12:33:23 【问题描述】:我在 SQL Server 中遇到交叉表查询问题。
假设我有如下数据:
| ScoreID | StudentID | Name | Sex | SubjectName | Score |
------------------------------------------------------------------
| 1 | 1 | Student A | Male | C | 100 |
| 2 | 1 | Student A | Male | C++ | 40 |
| 3 | 1 | Student A | Male | English | 60 |
| 4 | 1 | Student A | Male | Database | 15 |
| 5 | 1 | Student A | Male | Math | 50 |
| 6 | 2 | Student B | Male | C | 77 |
| 7 | 2 | Student B | Male | C++ | 12 |
| 8 | 2 | Student B | Male | English | 56 |
| 9 | 2 | Student B | Male | Database | 34 |
| 10 | 2 | Student B | Male | Math | 76 |
| 11 | 3 | Student C | Female | C | 24 |
| 12 | 3 | Student C | Female | C++ | 10 |
| 13 | 3 | Student C | Female | English | 15 |
| 14 | 3 | Student C | Female | Database | 40 |
| 15 | 3 | Student C | Female | Math | 21 |
| 16 | 4 | Student D | Female | C | 17 |
| 17 | 4 | Student D | Female | C++ | 34 |
| 18 | 4 | Student D | Female | English | 24 |
| 19 | 4 | Student D | Female | Database | 56 |
| 20 | 4 | Student D | Female | Math | 43 |
我想查询结果如下:
| StuID| Name | Sex | C | C++ | Eng | DB | Math | Total | Average |
| 1 | Student A | Male | 100| 40 | 60 | 15 | 50 | 265 | 54 |
| 2 | Student B | Male | 77 | 12 | 56 | 34 | 76 | 255 | 51 |
| 3 | Student C | Female | 24 | 10 | 15 | 40 | 21 | 110 | 22 |
| 4 | Student D | Female | 17 | 34 | 24 | 56 | 43 | 174 | 34.8 |
如何查询以显示这样的输出? 注意:
主题名称:
C C++ 英语 数据库数学
将根据学生所学的科目而改变。
请到http://sqlfiddle.com/#!6/2ba07/1测试这个查询。
【问题讨论】:
【参考方案1】:有两种方法可以执行PIVOT
静态方法,其中您对值进行硬编码,而动态方法则在您执行时确定列。
即使您需要动态版本,有时从静态的PIVOT
开始,然后转向动态版本会更容易。
静态版本:
SELECT studentid, name, sex,[C], [C++], [English], [Database], [Math], total, average
from
(
select s1.studentid, name, sex, subjectname, score, total, average
from Score s1
inner join
(
select studentid, sum(score) total, avg(score) average
from score
group by studentid
) s2
on s1.studentid = s2.studentid
) x
pivot
(
min(score)
for subjectname in ([C], [C++], [English], [Database], [Math])
) p
见SQL Fiddle with demo
现在,如果您不知道要转换的值,那么您可以使用动态 SQL:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(SubjectName)
from Score
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT studentid, name, sex,' + @cols + ', total, average
from
(
select s1.studentid, name, sex, subjectname, score, total, average
from Score s1
inner join
(
select studentid, sum(score) total, avg(score) average
from score
group by studentid
) s2
on s1.studentid = s2.studentid
) x
pivot
(
min(score)
for subjectname in (' + @cols + ')
) p '
execute(@query)
见SQL Fiddle with Demo
两个版本将产生相同的结果。
只是为了完善答案,如果您没有 PIVOT
函数,那么您可以使用 CASE
和聚合函数获得此结果:
select s1.studentid, name, sex,
min(case when subjectname = 'C' then score end) C,
min(case when subjectname = 'C++' then score end) [C++],
min(case when subjectname = 'English' then score end) English,
min(case when subjectname = 'Database' then score end) [Database],
min(case when subjectname = 'Math' then score end) Math,
total, average
from Score s1
inner join
(
select studentid, sum(score) total, avg(score) average
from score
group by studentid
) s2
on s1.studentid = s2.studentid
group by s1.studentid, name, sex, total, average
见SQL Fiddle with Demo
【讨论】:
非常感谢您的解决方案。这就是我需要的。再次感谢。 在分配@cols 时,有什么办法可以按字母顺序对subjectName 进行排序? @Sunny 是的,您可以同时使用GROUP BY
和ORDER BY
,而不是使用DISTINCT
,以按任意顺序对名称进行排序——参见降序演示——sqlfiddle.com/#!6/2ba07/176
【参考方案2】:
在这种情况下,您需要使用 SQL PIVOT。请参考以下链接:
Pivot on Unknown Number of Columns
Pivot two or more columns in SQL Server
Pivots with Dynamic Columns in SQL Server
【讨论】:
【参考方案3】:这需要在运行时构建 SQL 查询字符串。 SQL Server 中的列名、计数和数据类型始终是静态的(最重要的原因是优化器在优化时必须知道查询数据流)。
所以我建议你在运行时构建一个PIVOT
-query 并通过sp_executesql
运行它。请注意,您必须对枢轴列值进行硬编码。小心正确地逃脱它们。您不能为它们使用参数。
或者,您可以为每个列数构建一个这样的查询,并将参数仅用于枢轴值。您必须分配一些虚拟列名称,例如Pivot0, Pivot1, ...
。对于每列计数,您仍然需要一个查询模板。除非您愿意将最大数量的枢轴列硬编码到查询中(比如 20)。在这种情况下,您实际上可以使用静态 SQL。
【讨论】:
投反对票的人是否愿意发表评论?这个答案是正确的,AFAIK。以上是关于SQL查询动态列的方法的主要内容,如果未能解决你的问题,请参考以下文章