【问题标题】:Dynamic case statement using SQL Server 2008 R2使用 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);

卡住:但是卡住了@dates2001-01-01to2001-01-05 进入BETWEEN '2001-01-01' AND '2001-01-05'

【问题讨论】:

  • 您为什么要这样做?好像你在这里把一个简单的问题复杂化了。
  • 只需创建一个包含名称、开始日期和结束日期的查找表。然后你只需要将它加入到你的查询中。如果它们每年都重置,请将列设为 yearnamestart_dateend_date

标签: sql-server sql-server-2008-r2


【解决方案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 的方法那样存在编码问题喜欢:&lt;"&amp;
  • @MAK 当前数据库是否与安装 SQL# 的数据库相同?如果没有,您需要将函数的名称完全限定为:[dbname].SQL#.String_Split4K()
  • 是的!我得到了它。非常感谢你陪我这么久。
  • @MAK 这是一个单独的问题。无论如何,我无法完全提供帮助,但您应该打开一个新问题并在此处添加带有该 URL 的评论。我可以说我刚刚在PostgreSQL中找到了一个内置的拆分功能:regexp_split_to_table
猜你喜欢
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-30
  • 1970-01-01
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多