如何按照下面的要求从 SQL 服务器中检索数据?
How to retrieve data from SQL Server as required below?
我有一个这样的 table :
CustName Country RecordedTime
---------------------------------------------
Alex Australia 2018-Jun-01 08:00 AM
Alex China 2018-Jun-01 10:00 AM
Alex Japan 2018-Jun-01 11:00 AM
John Australia 2018-Jun-01 08:00 AM
John China 2018-Jun-02 08:00 AM
Bob Australia 2018-Jun-02 09:00 AM
Bob Brazil 2018-Jun-03 09:50 AM
如果记录在系统中是全新的,那么它应该在给定日期的审计和历史字段(结果集中的两个附加字段)中显示 'ADD' & 'NEW'。
如果记录在那天被编辑了两次,那么它应该在审计字段中显示 'ADD' 和 'CHANGE ' 以及在历史状态字段中显示 'BEFORE' 和 'CURRENT' 的两个条目分别针对给定的日期。
例如,我的结果应该是这样的;
当我将输入日期传递为 2018-Jun-01 时,输出应如下所示:
CustName Country RecordedTime Audit History
----------------------------------------------------------------
Alex Australia 2018-Jun-01 08:00 AM ADD NEW
Alex China 2018-Jun-01 10:00 AM CHANGE BEFORE
Alex Japan 2018-Jun-01 11:00 AM CHANGE CURRENT
John Australia 2018-Jun-01 08:00 AM ADD NEW
当我将输入日期传递为 2018-Jun-02 时,输出应如下所示:
CustName Country RecordedTime Audit History
-----------------------------------------------------------------
John China 2018-Jun-02 08:00 AM CHANGE CURRENT
Bob Australia 2018-Jun-02 09:00 AM ADD NEW
当我将输入日期传递为 2018-Jun-02 时,输出应如下所示:
CustName Country RecordedTime Audit History
----------------------------------------------------------------
Bob Brazil 2018-Jun-03 09:50 AM CHANGE CURRENT
我尝试了很多方法,但仍然缺少一些实现此目的的方案。有人可以解释一下吗?
一种方法是通过如下所示的 cte,其中我们有 row_number() 函数来双向跟踪序列。
; with cte as
(
select *, rn= row_number() over(partition by CustName order by RecordedTime),
rn2=row_number() over(partition by CustName order by RecordedTime desc)
from records
)
, cte2 as
(
select *, audit='New', History='Change' from cte where rn=1
union
select *, audit='Change', History='Current' from cte where rn2=1 and rn<>1
union
select *, audit='Change', History='before' from cte where rn>1 and rn2<>1
)
select
CustName,
Country,
RecordedTime,
audit,
History
from cte2
order by CustName,RecordedTime
我会简单地使用 case
表达式。
select t.*,
(case when seqnum = 1 then 'ADD' else 'CHANGE' end) as audit,
(case when seqnum = 1 then 'NEW'
when seqnum_day = 1 then 'CURRENT'
else 'BEFORE'
end) as history
from (select t.*,
row_number() over (partition by custname order by recordedtime) as seqnum,
row_number() over (partition by custname, cast(recordedtime as date) order by recordedtime desc) as seqnum_day
from t
) t;
sqlfiddle:http://sqlfiddle.com/#!18/43c08/27
你可以试试
CASE WHEN
和 RANK
与 Windows 函数
;WITH CTE (CustName,Country,RecordedTime,rn) AS(
SELECT *,RANK() OVER(PARTITION BY CustName ORDER BY RecordedTime) rn
FROM T
)
SELECT t.*,
(CASE WHEN rn = 1 then 'ADD' ELSE 'CHANGE' END) 'Audit',
(CASE
WHEN rn = 1 then 'NEW'
WHEN t2.mRn = rn then 'CURRENT'
ELSE 'BEFORE' END) 'History'
FROM CTE t LEFT JOIN (
SELECT MAX(rn) mRn,CustName FROM CTE GROUP BY CustName
) t2 on t2.mRn = t.rn and t2.CustName = t.CustName
WHERE CONVERT(char(10), RecordedTime,126) = '2018-06-02'
sqlfiddle:http://sqlfiddle.com/#!18/43c08/26
我有一个这样的 table :
CustName Country RecordedTime
---------------------------------------------
Alex Australia 2018-Jun-01 08:00 AM
Alex China 2018-Jun-01 10:00 AM
Alex Japan 2018-Jun-01 11:00 AM
John Australia 2018-Jun-01 08:00 AM
John China 2018-Jun-02 08:00 AM
Bob Australia 2018-Jun-02 09:00 AM
Bob Brazil 2018-Jun-03 09:50 AM
如果记录在系统中是全新的,那么它应该在给定日期的审计和历史字段(结果集中的两个附加字段)中显示 'ADD' & 'NEW'。
如果记录在那天被编辑了两次,那么它应该在审计字段中显示 'ADD' 和 'CHANGE ' 以及在历史状态字段中显示 'BEFORE' 和 'CURRENT' 的两个条目分别针对给定的日期。
例如,我的结果应该是这样的;
当我将输入日期传递为 2018-Jun-01 时,输出应如下所示:
CustName Country RecordedTime Audit History
----------------------------------------------------------------
Alex Australia 2018-Jun-01 08:00 AM ADD NEW
Alex China 2018-Jun-01 10:00 AM CHANGE BEFORE
Alex Japan 2018-Jun-01 11:00 AM CHANGE CURRENT
John Australia 2018-Jun-01 08:00 AM ADD NEW
当我将输入日期传递为 2018-Jun-02 时,输出应如下所示:
CustName Country RecordedTime Audit History
-----------------------------------------------------------------
John China 2018-Jun-02 08:00 AM CHANGE CURRENT
Bob Australia 2018-Jun-02 09:00 AM ADD NEW
当我将输入日期传递为 2018-Jun-02 时,输出应如下所示:
CustName Country RecordedTime Audit History
----------------------------------------------------------------
Bob Brazil 2018-Jun-03 09:50 AM CHANGE CURRENT
我尝试了很多方法,但仍然缺少一些实现此目的的方案。有人可以解释一下吗?
一种方法是通过如下所示的 cte,其中我们有 row_number() 函数来双向跟踪序列。
; with cte as
(
select *, rn= row_number() over(partition by CustName order by RecordedTime),
rn2=row_number() over(partition by CustName order by RecordedTime desc)
from records
)
, cte2 as
(
select *, audit='New', History='Change' from cte where rn=1
union
select *, audit='Change', History='Current' from cte where rn2=1 and rn<>1
union
select *, audit='Change', History='before' from cte where rn>1 and rn2<>1
)
select
CustName,
Country,
RecordedTime,
audit,
History
from cte2
order by CustName,RecordedTime
我会简单地使用 case
表达式。
select t.*,
(case when seqnum = 1 then 'ADD' else 'CHANGE' end) as audit,
(case when seqnum = 1 then 'NEW'
when seqnum_day = 1 then 'CURRENT'
else 'BEFORE'
end) as history
from (select t.*,
row_number() over (partition by custname order by recordedtime) as seqnum,
row_number() over (partition by custname, cast(recordedtime as date) order by recordedtime desc) as seqnum_day
from t
) t;
sqlfiddle:http://sqlfiddle.com/#!18/43c08/27
你可以试试
CASE WHEN
和 RANK
与 Windows 函数
;WITH CTE (CustName,Country,RecordedTime,rn) AS(
SELECT *,RANK() OVER(PARTITION BY CustName ORDER BY RecordedTime) rn
FROM T
)
SELECT t.*,
(CASE WHEN rn = 1 then 'ADD' ELSE 'CHANGE' END) 'Audit',
(CASE
WHEN rn = 1 then 'NEW'
WHEN t2.mRn = rn then 'CURRENT'
ELSE 'BEFORE' END) 'History'
FROM CTE t LEFT JOIN (
SELECT MAX(rn) mRn,CustName FROM CTE GROUP BY CustName
) t2 on t2.mRn = t.rn and t2.CustName = t.CustName
WHERE CONVERT(char(10), RecordedTime,126) = '2018-06-02'
sqlfiddle:http://sqlfiddle.com/#!18/43c08/26