我有一张表,其中包含ID,日期,标记指示(包括是或否包含值) 我希望获得最新日期,当标志指示符从No变为Yes时,它确定截至今天该ID是否在范围内。
ID Date Flag Indicator
1 2-Jan-15 No
1 4-Jan-16 Yes
1 2-Jan-17 No
1 1-Jan-18 Yes
上述结果必须是2018年1月1日 但是对于下面
ID日期标志指示器 2 2月1日至15日 2 4月1日 - 16日 2月2日 - 1月17日 2 1 1月18日否
Result must be null
因为根据最新日期标志指示符为“否”,这意味着它不在范围内。
ID日期标志指示器 4 2月1日至15日 4月4日 - 4月是的 4月2日 - 1月17日 4 1月1日 - 18日是
结果是2016年1月4日,因为这是指标进入范围的日期,是
答案 0 :(得分:1)
这是一个使用窗口函数的方法:
select t.*,
(case when flag = 'Yes' and prev_flag = 'No' and
running_no = max(partition by id running_no) over ()
then 'Yes' else 'No'
end) as new_flag
from (select t.*,
sum(case when flag = 'No' then 1 else 0 end) over (partition by id order by date) as running_no,
lag(flag) over (partition by id order by date) as prev_flag
from t
) t;
窗口函数通常比使用相关子查询,自联接或apply
的解决方案表现更好。
如果您只想为每个id添加一行,那么我想到使用相关子查询:
select top (1) with ties t.*
from t
where t.flag = 'yes' and
t.date > (select max(t2.date) from t t2 where t2.id = t.id and t2.flag = 'no')
order by row_number() over (partition by id order by date);
答案 1 :(得分:0)
检查最大无日期,然后检索该日期之后的最小日期。
;WITH MaxNoDateByID AS
(
SELECT
N.ID,
MaxNoDate = MAX(N.Date)
FROM
NumberedDates AS N
WHERE
N.Flag = 'No'
GROUP BY
N.ID
)
SELECT
T.ID,
MinYesDateAfterNo = MIN(T.Date)
FROM
YourTable AS T
INNER JOIN MaxNoDateByID AS M ON T.ID = M.ID
WHERE
T.Date > M.MaxNoDate -- Assuming all dates after MaxNoDate are supposed to be Flag Yes
GROUP BY
T.ID
答案 2 :(得分:0)
这可能对您有所帮助
CREATE TABLE [dbo].[flagindicator](
[id] [int] NULL,
[date] [date] NULL,
[flagindicator] [varchar](50) NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (1, CAST(0x6F390B00 AS Date), N'No')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (1, CAST(0xDE3A0B00 AS Date), N'Yes')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (1, CAST(0x4A3C0B00 AS Date), N'No')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (1, CAST(0xB63D0B00 AS Date), N'Yes')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (2, CAST(0xB63D0B00 AS Date), N'Yes')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (2, CAST(0x4A3C0B00 AS Date), N'No')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (2, CAST(0xDE3A0B00 AS Date), N'Yes')
INSERT [dbo].[flagindicator] ([id], [date], [flagindicator]) VALUES (2, CAST(0x6F390B00 AS Date), N'No')
SELECT id,ISNULL(MAX(CASE WHEN flagindicator='Yes' THEN date END ),'') indicator FROM flagindicator GROUP BY id
答案 3 :(得分:0)
使用带有相关性的子查询
select * from table t
where Date = (select max(Date) from table where id = t.id) and
[Flag Indicator] = 'Yes'
编辑:
使用INNER JOIN
作为包含max_date的自我联接,为每个ID correlation 方法
select
top (1) with ties t.Id,
(case when (select top 1 [Flag Indicator] from table
where id = c.id and date = c.MAXDATE) <> 'No'
then date end) as Date
from table t inner join (
select id, max(date) MAXDATE from table group by id
) c on c.id = t.id
order by row_number() over(partition by t.Id
order by case when [Flag Indicator] = 'Yes'
then 0 else 1 end)
检查Demo
答案 4 :(得分:0)
编辑1
我已将输出日期更正为第一个,而不是最后一个
编辑2
添加针对相同ID /日期的保护
添加了优化版本。
我假设您的[Date]
列是DATETIME
,这样您就可以找到所需的输出:
DECLARE @YourDesiredID INT = 1;
;WITH
t1 as (select distinct ID from YourTable),
m1 as (
select *,
ROW_NUMBER() over (partition by id order by id, t.date, flag) desc) n,
LAG (flag, 1, 'No ') OVER (partition by id order by id, t.date, flag desc) ) PrevFlag
from YourTable t
),
t2 as (select * from m1 where n=1 and flag = 'Yes'),
m2 as (
select id, max(m1.date) [date]
from m1
where flag = 'Yes' and PrevFlag = 'No '
group by id
)
select
--t1.id,
m2.date
from t1
left join t2 on t1.id = t2.id
left join m2 on m2.id = t2.id
where t.ID = @YourDesiredID
优化版可以使用MAX([Date])
代替ROW_NUMBER()
,但您必须确保不能拥有更多具有相同ID /日期的记录。
这些是优化的子查询:
t1 as (select ID, max(date) maxdate from t group by id),
m1 as (select *, LAG (flag, 1, 'No') OVER (partition by id order by id, t.date, flag desc) PrevFlag from t),
t2 as (select m1.* from m1 join t1 on t1.id = m1.id where maxdate = date and flag = 'Yes'),
答案 5 :(得分:0)
还有另一种方法来完成这项任务,我认为这是@GordonLinoff答案的优化,这更简单,更高效。
select t.id, min(date) date
from YourTable
left join (
select id, max(date) maxdate_no
from YourTable
where flag = 'no'
group by id
) tn on tn.ID = t.ID
where t.flag = 'yes' and t.date > tn.maxdate_no
group by t.id