使用多个CASE语句时出错[SQL]

时间:2017-03-22 22:48:06

标签: sql sql-server compare case

在Microsoft SQL Server中使用SQL,我有一个非常具体的问题,我在两个月之间比较数据。这些数据可以具有两种状态之一' - 为了保持简单,它可以是“1”或“0”,也可以是“是”或“否”。

我想考虑以下情况:

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

我假设我可以使用多个CASE语句,到目前为止我所拥有的内容如下:直到我遇到困难:

select
     --determine if status changes from 1 to 0 between two months or stays the same
     case
     when T.[status] = '1' and T.date between '01-01-2017' and '02-28-2017'
     then 'No Change'
     else
     'Status Changed to 0'
     end,

     --determine if status changes from 0 to 1 between two months or stays the same
     case
     when T.[status] = '0' and T.date between '01-01-2017' and '02-28-2017'
     then 'No Change'
     else 
     'Status Changed to 1'
     end,

     --determine if there was new row that didn't appear in first month with a status of 1 or 0 in second month
     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
     'New Status of 1'
     end, *
from table T
where ....

此代码适用于第一个CASE语句,用于在新列中显示从1到0的状态更改,但是它为第二个状态创建了另一个列,我不确定它是否按照我的意图运行。此外,由于我正在一起检查这两个月,我似乎无法将其他方案编码到我的SQL中。

我正在尝试找到一些方法来压缩所有CASE语句,只产生一个额外的列,而我遇到的另一个问题是第三个CASE语句在第一个“IN”处抛出语法错误。希望这对某人有意义,并提前感谢您提供的任何输入或提示。

3 个答案:

答案 0 :(得分:0)

考虑到你的上一个问题,首先是“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 :(得分:0)

我在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

答案 2 :(得分:0)

请参阅下面的自我加入代码(由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'