使用 SQL Server 2008 R2 的动态案例语句
Posted
技术标签:
【中文标题】使用 SQL Server 2008 R2 的动态案例语句【英文标题】:Dynamic case statement using SQL Server 2008 R2 【发布时间】:2014-12-11 17:10:50 【问题描述】:我有如下case语句如下图:
例子:
我有case statement
:
case cola
when cola between '2001-01-01' and '2001-01-05' then 'G1'
when cola between '2001-01-10' and '2001-01-15' then 'G2'
when cola between '2001-01-20' and '2001-01-25' then 'G3'
when cola between '2001-02-01' and '2001-02-05' then 'G4'
when cola between '2001-02-10' and '2001-02-15' then 'G5'
else ''
end
注意:现在我想创建动态案例语句,因为值日期和名称作为参数传递,它可能会改变。
Declare @dates varchar(max) = '2001-01-01to2001-01-05,2001-01-10to2001-01-15,
2001-01-20to2001-01-25,2001-02-01to2001-02-05,
2001-02-10to2001-02-15'
Declare @names varchar(max) = 'G1,G2,G3,G4,G5'
变量中的值可能会根据要求而变化,它将是动态的。所以case语句应该是动态的,不使用循环。
我的失败尝试:
DECLARE @Name varchar(max)
DECLARE @Dates varchar(max)
DECLARE @SQL varchar(max)
DECLARE @SQL1 varchar(max)
SET @Name = 'G1,G2,G3,G4,G5'
SET @dates = '2001-01-01to2001-01-05,2001-01-10to2001-01-15,
2001-01-20to2001-01-25,2001-02-01to2001-02-05,
2001-02-10to2001-02-15'
SELECT @SQL = STUFF((SELECT ' ' + Value FROM
(
SELECT 'WHEN Cola Between '''' AND '''' THEN ''' + A.Value + '''' AS Value
FROM
(
SELECT
Split.a.value('.', 'VARCHAR(100)') AS Value
FROM
(
SELECT CAST ('<M>' + REPLACE(@Name, ',',
'</M><M>') + '</M>' AS XML) AS Value
) AS A
CROSS APPLY Value.nodes ('/M') AS Split(a)
) AS A
) AS B
FOR XML PATH (''), type).value('.', 'Varchar(max)'),1,1,'') + ''
SET @SQL1 = 'CASE Cola '+@SQL+' ELSE '''' END'
PRINT(@SQL1);
卡住:但是卡住了@dates
2001-01-01to2001-01-05
进入BETWEEN '2001-01-01' AND '2001-01-05'
。
【问题讨论】:
您为什么要这样做?好像你在这里把一个简单的问题复杂化了。 只需创建一个包含名称、开始日期和结束日期的查找表。然后你只需要将它加入到你的查询中。如果它们每年都重置,请将列设为year
、name
、start_date
和 end_date
。
【参考方案1】:
只需创建一个临时表(可以动态插入)并在LEFT JOIN
中使用它。 LEFT JOIN
(连同COALESCE
)说明ELSE ''
条件,但如果没有ELSE
条件并且所有范围都在数据中表示,则应使用INNER JOIN
(并且不需要COALESCE
)。
为了从两个单独的变量动态填充临时表,这些变量的数据仅按 CSV 列表中的位置对齐,其中一个是二维数组,需要在逗号和字符串“to ",我使用了 CTE(以便更容易拆分二维 @Dates 变量)和基于 SQLCLR 的字符串拆分器。我使用的拆分器来自SQL# 库(我是它的创建者,但此功能在免费版本中)但您可以使用任何您喜欢的拆分器(但请不要使用基于 WHILE 循环的拆分器)很傻)。
CREATE TABLE #Cola
(
StartDate DATETIME NOT NULL,
EndDate DATETIME NOT NULL,
Name NVARCHAR(50) NOT NULL
);
DECLARE @Dates VARCHAR(MAX) = '2001-01-01to2001-01-05,2001-01-10to2001-01-15,
2001-01-20to2001-01-25,2001-02-01to2001-02-05,
2001-02-10to2001-02-15';
DECLARE @Names VARCHAR(MAX) = 'G1,G2,G3,G4,G5';
-- dynamic population of temp table from two variables (@Dates being 2 dimensional)
;WITH cte AS
(
SELECT vals.SplitNum,
vals.SplitVal,
CHARINDEX(N'to', vals.SplitVal) AS [WhereToSplit]
FROM SQL#.String_Split4k(@dates, ',', 1) vals
)
INSERT INTO #Cola (StartDate, EndDate, Name)
SELECT CONVERT(DATETIME, SUBSTRING(cte.SplitVal, (cte.WhereToSplit - 10), 10)),
CONVERT(DATETIME, SUBSTRING(cte.SplitVal, (cte.WhereToSplit + 2), 10)),
names.SplitVal
FROM cte
INNER JOIN SQL#.String_Split4k(@names, ',', 1) names
ON names.SplitNum = cte.SplitNum; -- keep the values aligned by position
SELECT tab.fields, COALESCE(cola.[Name], '') AS [Cola]
FROM SchemaName.TableName tab
LEFT JOIN #Cola cola
ON tab.cola BETWEEN cola.StartDate AND cola.EndDate
【讨论】:
但是我从前端得到@dates
和@name
作为逗号分隔的字符串,如上所示。那么如何将它们插入到临时表中呢?
@MAK 我在您最初的尝试中看到您正在执行基于 XML 的内联拆分器。至少你应该把它变成一个内联 TVF,在这种情况下,它可以用来代替“SQL#.String_Split4k”而无需其他更改。但是继续使用基于 SQLCLR 的拆分器也没有什么坏处,因为它们是最快的 并且 如果您使用特殊的 XML 字符,则不会像基于 XML 的方法那样存在编码问题喜欢:<
、"
或 &
。
@MAK 当前数据库是否与安装 SQL# 的数据库相同?如果没有,您需要将函数的名称完全限定为:[dbname].SQL#.String_Split4K()
。
是的!我得到了它。非常感谢你陪我这么久。
@MAK 这是一个单独的问题。无论如何,我无法完全提供帮助,但您应该打开一个新问题并在此处添加带有该 URL 的评论。我可以说我刚刚在PostgreSQL中找到了一个内置的拆分功能:regexp_split_to_table。以上是关于使用 SQL Server 2008 R2 的动态案例语句的主要内容,如果未能解决你的问题,请参考以下文章
windows 2012 r2怎么安装sql server 2008 r2
windows server2012 r2能安装sqlserver2008 R2吗