[英]SQL group by ID for multiple IDs using case when statements
[英]Errors when using multiple CASE statements [SQL]
在Microsoft SQL Server中使用SQL时,我遇到了一个非常具体的问题,即我要比较两个月之间的数据。 此数据可以具有两种状态之一-为简单起见,它可以是“ 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”处引发了语法错误。 希望这对某人有意义,并在此先感谢您提供的任何输入或技巧。
首先考虑最后一个问题,即“ 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
为了更轻松地检查状态更改,请以一个月的补偿将表连接到自身。
我在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
请参见下面的自我连接代码(由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'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.