获取SQL Server数据库中列值从no更改为yes的日期

时间:2018-03-22 07:33:52

标签: sql sql-server

我有一张表,其中包含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日,因为这是指标进入范围的日期,是

6 个答案:

答案 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