【问题标题】:Errors when using multiple CASE statements [SQL]使用多个 CASE 语句时出错 [SQL]
【发布时间】:2017-08-15 07:12:50
【问题描述】:

在 Microsoft SQL Server 中使用 SQL,我有一个非常具体的问题,我在比较两个月之间的数据。该数据可以具有两种状态之一——为了简单起见,它可以是“1”或“0”,或者基本上是“是”或“否”。

我想考虑以下场景:

  • 如果某行在一个月内的状态为“1”,然后在下个月变为“0”,反之亦然
  • 如果状态从一个月到另一个月没有变化(即“1”到“1”或“0”到“0”)
  • 如果状态值在上个月为空,下个月变为“1”或“0”

我假设我可以为此使用多个 CASE 语句。此外,由于我要一起检查这两个月,我似乎无法将其他场景编码到我的 SQL 中。

我正在尝试找到某种方法将所有 CASE 语句压缩为仅生成一个额外的列,而我遇到的另一个问题是第三个 CASE 语句在第一个“IN”处引发语法错误。希望这对某人有意义,并提前感谢您提供的任何意见或提示。

【问题讨论】:

  • 如果您提供了示例数据,它会更容易提供帮助。但我猜你可能想获取最新数据(例如select top 1 status from mytable t order by date desc)并交叉应用/加入上个月的数据(例如cross apply (select top 1 status from mytable where date < dateadd(month, 0, datediff(month, 0, t.date)) order by date desc) as c)或类似的东西?然后在单个 case 语句中对 t.status 和 c.status 进行比较?

标签: sql sql-server compare case


【解决方案1】:

解决你的最后一个问题,首先,“IN”的语法不正确:

 case
 when T.status is null in t.date between '01-01-2017' and '01-31-2017'  
 and T.status = '1' in T.date between '02-01-2017' and '02-28-2017' then 'New Status to 1'
 else
 'test'
 end

试试:

 case
 when (T.status is null AND t.date between '01-01-2017' and '01-31-2017')  
 OR (T.status = '1' AND T.date between '02-01-2017' and '02-28-2017') then 'New Status to 1'
 else
 'test'
 end

为了更轻松地检查状态变化,请将您的表连接到自身,并带有 1 个月的偏移量。

【讨论】:

  • @programr,很高兴你已经解决了你的问题。 “IN”正在测试一个值是否是集合的成员。例如,(A,B,C) 中的 X 为真,即 X 等于 A、B 或 C。请参阅:msdn.microsoft.com/en-us/library/ms177682.aspx
【解决方案2】:

我在 WITH 子句中添加了一个包含输入数据的示例表,它可能符合您的要求。我正在使用 SQL Server 支持的 LAG() 分析函数。请记住,在分析窗口分区的第一行中,LAG() 返回 NULL - 因为在这种情况下没有前一行。

在 SQL Server 以外的其他 DBMS 中,您需要使用 ANSI 连接运算符 || 而不是 + 来连接两个字符串。

WITH
input(input_id,monthfirst,status) AS (
          SELECT 1,DATE '2017-01-01',0
UNION ALL SELECT 1,DATE '2017-02-01',1
UNION ALL SELECT 1,DATE '2017-03-01',0
UNION ALL SELECT 2,DATE '2017-01-01',1
UNION ALL SELECT 2,DATE '2017-02-01',1
UNION ALL SELECT 2,DATE '2017-03-01',0
UNION ALL SELECT 3,DATE '2017-01-01',CAST(NULL AS INT)
UNION ALL SELECT 3,DATE '2017-02-01',1
UNION ALL SELECT 3,DATE '2017-03-01',0
)
,
input_with_prev_status AS (
SELECT
  *
, LAG(status) OVER (PARTITION BY input_id ORDER BY monthfirst) AS prev_status
FROM input
)
SELECT
  input_id
, monthfirst
, status
, CASE
    WHEN prev_status IS NULL AND status IS NOT NULL
      THEN 'New status to ' + CAST(status AS CHAR(1))
    WHEN prev_status <> status
      THEN 'Status changed to ' + CAST(status AS CHAR(1))
    WHEN prev_status = status
      THEN 'no status change'
    WHEN prev_status IS NULL AND status IS NULL
      THEN 'status remains missing'
    ELSE 'unforeseen status change'
  END AS status_change
FROM input_with_prev_status
;
input_id|monthfirst|status|status_change
       1|2017-01-01|     0|New status to 0
       1|2017-02-01|     1|Status changed to 1
       1|2017-03-01|     0|Status changed to 0
       2|2017-01-01|     1|New status to 1
       2|2017-02-01|     1|no status change
       2|2017-03-01|     0|Status changed to 0
       3|2017-01-01|-     |status remains missing
       3|2017-02-01|     1|New status to 1
       3|2017-03-01|     0|Status changed to 0

【讨论】:

    【解决方案3】:

    请参阅下面的自加入代码(由 Dejan 建议)。您需要使用表 T 中的键列创建 ON 语句

    select 
      case 
      when (T1.[status] = '1' and T2. [status] = '1') or (T1.[status] = '0' and T2. [status] = '0') then 'No Change'
      when T1.[status] = '1' and T2. [status] = '0' then 'Status Changed to 0'
      when T1.[status] = '0' and T2. [status] = '1' then 'Status Changed to 1'
      when T.status is null and  T2. [status] = '1' then 'New Status to 1'
     else
     'test'
      end
    table T1 
    inner join T2
       on ....join on the key column
    where T1.date between '01-01-2017' and '31-01-2017' 
    and T2.date between '01-02-2017' and '28-02-2017'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      • 2014-08-18
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多