SQL查找条件不存在的最新日期

时间:2015-08-12 10:15:27

标签: sql sql-server

我对SQL很陌生,正在研究一段时间以来彻底打败我的查询。我经常访问这个网站 - 由于你的所有专业知识,这是一个非常好的资源,通常我找到了我需要的东西,但这次我认为我的查询有点过于具体,我找不到适用的东西。请问有人帮我一把吗?

我有两个表:一个Client表和一个Contact(aka约会)表。我需要找到的是所有客户最近的预约日期(在特定日期之前,在本案例中为'11 / 08/2015'),其中当天任何预约的结果不是'2'。每个客户可能在一天内有多个约会,任何这些约会的结果为'2'意味着我们必须忽略整天并且回到下一个最近的一天......

例如,客户'3'的预约日期应为'01/07 / 2015'(并且只有一行),而不是'16 / 07/2015'的两行,因为其中一个约会'16 / 07/2015'的结果为'2'。结果的所有其他值都是可接受的(包括NULL),而不是'2'。

同一天的多次约会是我发现棘手的部分 - 我可以使用Select MAX(或TOP 1)声明找到最新的约会日,但是当我添加“<> '2'“它仍然会继续返回可能有结果'2'的同一天,因为同一天的其他约会有另一个结果。我一直试图玩我的桌子和GROUP BY而不是现有的,但我似乎没有取得任何进展。

Contact
ClientID    AppDate Outcome
1   30/07/2015 17:00    2
1   01/07/2015 17:00    3
2   03/03/2015 16:00    NULL
2   01/03/2015 16:00    NULL
3   16/07/2015 15:40    6
3   16/07/2015 15:40    2
3   01/07/2015 15:40    3
4   05/08/2015 12:30    6
4   05/08/2015 12:30    2
4   01/08/2015 12:30    3
5   23/07/2015 15:30    2
5   23/07/2015 15:30    NULL
5   01/07/2015 15:30    4
6   20/07/2015 10:10    NULL
6   20/07/2015 10:10    2
6   01/07/2015 10:10    6
7   23/07/2015 15:40    2
7   01/07/2015 15:40    1
7   23/06/2015 15:40    8
8   13/07/2015 11:30    2
8   13/07/2015 11:30    6
8   01/07/2015 11:30    2
8   01/06/2015 11:30    3
9   29/07/2015 17:00    3
9   29/07/2015 17:00    6
10  14/07/2015 11:00    NULL
10  01/07/2015 11:00    5


Client      
ClientID    Forename    Surname
1       I       B
2       J       B
3       S       C
4       S       T
5       P       C
6       K       D
7       P       E
8       P       H
9       S       F
10      A       G

如果我错过了一些明显的东西,我会道歉!感谢阅读和任何回复。我附上我的截断查询,以便您获得一般娱乐......

SELECT
cli.ClientID ,
cli.Forename ,
cli.Surname ,
con.AppDate ,
con.Outcome 


FROM
Client AS cli

INNER JOIN
Contact AS con
ON cli.ClientID = con.ClientID 
AND con.AppDate =
    (SELECT MAX(con1.AppDate) 
    FROM Contact AS con1
    WHERE con.ClientID = con1.ClientID 
    AND con1.AppDate < '11/08/2015  00:00:00'
    AND con1.Outcome <> '2')


ORDER BY
cli.ClientID 

编辑:

感谢Linoff先生提出的Cross Apply查询,它完美无缺。

很抱歉,我之前没有包含预期的输出。供参考(对于将来处理类似问题的其他人)我希望获得:

Appointments        
Client ID   Act Date and Time   Outcome
1   01/07/2015 17:00    3
2   03/03/2015 16:00    NULL
3   01/07/2015 15:40    3
4   01/08/2015 12:30    3
5   01/07/2015 15:30    4
6   01/07/2015 10:10    6
7   01/07/2015 15:40    1
8   01/06/2015 11:30    3
9   29/07/2015 17:00    3
9   29/07/2015 17:00    6
10  14/07/2015 11:00    NULL

3 个答案:

答案 0 :(得分:2)

我认为cross apply是解决此问题的最佳方法:

select c.*, con.*
from client c cross apply
     (select top 1 con.*
      from (select con.*,
                   sum(case when Outcome = 2 then 1 else 0 end) over (partition by ClientId, AppDate) as num2s
            from contact con
            where con.ClientId = c.ClientId and
                  con.AppDate < '2015-11-08'
           ) con
      where num2s = 0
      order by AppDate desc
     ) con;

在这种情况下,cross apply的工作方式与相关子查询非常相似,但您可以返回多个值。子查询使用窗口函数来计算&#34; 2&#34;在某一天,其余逻辑应该非常明显。

这将从最近的日期返回一行并进行适当的约会。如果您想要多个此类行,请使用with ties

答案 1 :(得分:1)

你需要做的是找出一个条件,该条件选出结果为2的所有日期并将其过滤掉。

这样的事情:

WITH ClientCTE AS
(
SELECT MAX(con1.AppDate) AS AppDate ,ClientID
    FROM Contact AS con1
    WHERE con.ClientID = con1.ClientID 
    AND con1.AppDate < '11/08/2015  00:00:00'
    AND con1.Outcome  <> '2'
    AND con1.AppDate NOT IN (SELECT AppDate FROM Contact WHERE Outcome  = '2')) 

SELECT 
* FROM Client C
INNER JOIN
Contact AS con
ON cli.ClientID = con.ClientID 
INNER JOIN ClientCTE  CTE
ON cli.ClientID = CTE.ClientCTE
AND CTE.AppDate = con.AppDate

让我知道它是否有效

答案 2 :(得分:0)

请尝试以下查询。 它使用MAX(case...) OVER( partition BY CAST(AppDate as DATE)窗口函数标记在同一天具有2个结果的所有约会以及WHERE子句来过滤日期。 然后在外flag子句中使用此WHERE来删除不需要的数据并加入联系人和客户端表

SELECT
    cli.ClientID ,
    cli.Forename ,
    cli.Surname ,
    con.AppDate ,
    con.Outcome 
  from 
    client cli right join contact con
        on con.ClientID=cli.ClientID
    inner join
    (
        select ClientID,MAX(AppDate)as lastDate from 
                (       select *,  
                            MAX(CASE when ISNULL(Outcome,1) =2 then 1 else 0 end) OVER(PARTITION BY CAST(AppDate as DATE),ClientID ORDER BY AppDate) as flag 
                        from Contact 
                        where AppDate< '2015-11-08'
                ) p 
            where flag =0  group by ClientID
        ) s
on s.ClientId=con.ClientID and s.lastDate=con.AppDate

此处还有用于演示的sql小提琴的链接: http://sqlfiddle.com/#!6/c519d/2