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