如果我要加入的查询返回:
IDApplication ContactDate CInfo
1 01/06/2016 pie
1 10/01/2016 cake
1 03/02/2015 banana
2 03/06/2016 cake
2 23/12/2015 apple
IDApplication ReplyDate RInfo
1 30/05/2016 circle
1 03/05/2016 square
1 04/02/2015 triangle
1 14/01/2016 pentagon
2 04/06/2016 square
2 01/02/2016 pentagon
2 10/06/2016 circle
我需要将其退回:
IDApplication ContactDate CInfo ReplyDate RInfo
1 01/06/2016 pie NULL NULL
1 10/01/2016 cake 30/05/2016 circle
1 03/02/2015 banana 04/02/2015 triangle
2 03/06/2016 cake 10/06/2016 square
2 23/12/2015 apple 01/02/2016 pentagon
我需要它返回第二个表/查询信息,其中日期大于第一个表中的任何相应应用程序日期,但不大于第一个表中的任何后续日期。
因此对于上面的第一条记录,它是NULL,因为在回复表中没有回复信息,并且在回复表中没有回复信息(因此没有回复),但第二条记录的回复日期为30/05/2016因为这是该申请的最大回复日期。更重要的是,对于第5条记录,回复日期是2016年2月1日,这个日期大于联系日期,但不是申请2的最大回复日期,即2016年6月10日,但另一个申请2的联系日期是在这两者之间需要显示下一个联系日期之前的最大日期。
这是让我的大脑受伤的逻辑。
我已经加入了关于回复日期大于联系日期的第二个查询,但这导致它为所有更大的日期显示行。
我需要以大于基表日期的日期加入记录,但是这些日期不大于下一个最大基表日期。
答案 0 :(得分:2)
我对这类问题的解决方法通常是将它们分解为小步骤,每个步骤都可以作为CTE实现,因此我得到了一些非常容易阅读和理解的东西。如果需要,我总是可以尝试将其折叠成更少的步骤。这是一个可能的解决方案。请参阅注释,了解其工作原理。
--------------------------------------------------------------------------------
-- Set up the sample data from the question.
--------------------------------------------------------------------------------
declare @Contact table (IDApplication int, ContactDate date, CInfo varchar(32));
declare @Reply table (IDApplication int, ReplyDate date, RInfo varchar(32));
insert @Contact values
(1, '2016-06-01',' pie'),
(1, '2016-01-10', 'cake'),
(1, '2015-02-03', 'banana'),
(2, '2016-06-03', 'cake'),
(2, '2015-12-23', 'apple');
insert @Reply values
(1, '2016-05-30', 'circle'),
(1, '2016-05-03', 'square'),
(1, '2015-02-04', 'triangle'),
(1, '2016-01-14', 'pentagon'),
(2, '2016-06-04', 'square'),
(2, '2016-02-01', 'pentagon'),
(2, '2016-06-10', 'circle');
--------------------------------------------------------------------------------
-- Step 1: Sequence each group of contacts by contact date.
--------------------------------------------------------------------------------
with OrderedContactCTE as
(
select
*,
[Sequence] = row_number() over (partition by IDApplication order by ContactDate)
from
@Contact
),
--------------------------------------------------------------------------------
-- Step 2: Match each contact with the subsequent contact (where one exists)
-- having the same IDApplication value. The date of the subsequent
-- contact will act as the upper bound on reply dates that are valid for
-- the original contact. Assign each contact a unique identifier that
-- we'll use in the following step.
--------------------------------------------------------------------------------
PairedContactCTE as
(
select
UniqueID = row_number() over (order by Contact.IDApplication, Contact.[Sequence]),
Contact.IDApplication,
Contact.ContactDate,
Contact.CInfo,
NextContactDate = NextContact.ContactDate
from
OrderedContactCTE Contact
left join OrderedContactCTE NextContact on
Contact.IDApplication = NextContact.IDApplication and
Contact.[Sequence] = NextContact.[Sequence] - 1
),
--------------------------------------------------------------------------------
-- Step 3: Match every contact with all replies that are strictly after the
-- original contact date and, where applicable, strictly before the
-- subsequent contact date. For each unique contact, sequence the
-- replies in reverse order by reply date.
--------------------------------------------------------------------------------
OrderedResponseCTE as
(
select
Contact.*,
Reply.ReplyDate,
Reply.RInfo,
[Sequence] = row_number() over (partition by Contact.UniqueID order by Reply.ReplyDate desc)
from
PairedContactCTE Contact
left join @Reply Reply on
Contact.IDApplication = Reply.IDApplication and
Contact.ContactDate < Reply.ReplyDate and
(
Contact.NextContactDate is null or
Contact.NextContactDate > Reply.ReplyDate
)
)
--------------------------------------------------------------------------------
-- Step 4: Finally, select each contact and the date/info of the latest reply
-- which is an eligible match for that contact.
--------------------------------------------------------------------------------
select
IDApplication,
ContactDate,
CInfo,
ReplyDate,
RInfo
from
OrderedResponseCTE
where
[Sequence] = 1;
答案 1 :(得分:1)
经过大约15分钟的心理折磨,我能够简化这个问题。唯一的空洞是我不确定连接条件是否只匹配每种情况下的单个记录。我怀疑还有另一个你没有明确提到的连接条件。
SELECT t1.IDApplication, t1.ContactDate, t1.CInfo,
t2.ReplyDate, t2.RInfo
FROM table1 t1
LEFT JOIN
table2 t2
ON t1.IDApplication = t2.IDApplication AND
t2.ReplyDate > t1.ContactDate AND
t2.ReplyDate < (SELECT MIN(t.ContactDate)
FROM table1 t
WHERE t.ContactDate > t1.ContactDate AND
t.IDApplication = t1.IDApplication)
答案 2 :(得分:1)
我没有要测试的SQL Server实例。让我知道这有多接近(Tim的解决方案的延伸)
SELECT c1.IDApplication, c1.ContactDate, c1.CInfo, r1.ReplyDate, r1.RInfo
FROM contact_table c1
LEFT JOIN
reply_table r1
ON c1.IDApplication = r1.IDApplication AND
r1.ReplyDate > c1.ContactDate AND
r1.ReplyDate < ( SELECT isnull(MIN(c2.ContactDate),'31-DEC-9999')
FROM contact_table c2
WHERE c2.ContactDate > c1.ContactDate AND
c2.IDApplication = c1.IDApplication ) AND
NOT EXISTS ( SELECT null
FROM reply_table r2
WHERE r2.IDApplication = r1.IDApplication AND
r2.ReplyDate > r1.ReplyDate AND
r2.ReplyDate < ( SELECT isnull(MIN(c2.ContactDate),'31-DEC-9999')
FROM contact_table c2
WHERE c2.ContactDate > c1.ContactDate AND
c2.IDApplication = c1.IDApplication ) )
答案 3 :(得分:0)
如果你记录依赖于记录上面的一些数据,那么最好实现一些存储过程逻辑。像这样:
/*
CREATE TABLE App (Id INT, ContractDate DATETIME, CInfo VARCHAR(100))
CREATE TABLE Reply (Id INT, ReplyDate DATETIME, RInfo VARCHAR(100))
INSERT App SELECT 1, '06/01/2016',' pie'
INSERT App SELECT 1, '01/10/2016', 'cake'
INSERT App SELECT 1, '02/03/2015', 'banana'
INSERT App SELECT 2, '06/03/2016', 'cake'
INSERT App SELECT 2, '12/23/2015', 'apple'
INSERT Reply SELECT 1, '05/30/2016', 'circle'
INSERT Reply SELECT 1, '05/03/2016', 'square'
INSERT Reply SELECT 1, '02/04/2015', 'triangle'
INSERT Reply SELECT 1, '01/14/2016', 'pentagon'
INSERT Reply SELECT 2, '06/04/2016', 'square'
INSERT Reply SELECT 2, '02/01/2016', 'pentagon'
INSERT Reply SELECT 2, '06/10/2016', 'circle'
*/
--SELECT * FROM App
DECLARE @AppReply TABLE (Id INT, ContractDate DATETIME, CInfo VARCHAR(100), ReplyDate DATETIME, RInfo VARCHAR(100))
DECLARE
@Id INT,
@PrevId INT,
@ContractDate DATETIME,
@PrevContractDate DATETIME,
@CInfo VARCHAR(100)
DECLARE appcursor CURSOR FAST_FORWARD FOR
SELECT Id, ContractDate, CInfo FROM App
OPEN appcursor
FETCH NEXT FROM appcursor
INTO @Id, @ContractDate, @CInfo
WHILE @@FETCH_STATUS = 0
BEGIN
IF(@Id != @PrevId)
SET @PrevContractDate = NULL
INSERT @AppReply (Id, ContractDate, CInfo)
SELECT TOP 1 @Id, @ContractDate, @CInfo
UPDATE @AppReply SET ReplyDate = R.ReplyDate, RInfo = R.RInfo
FROM @AppReply AR
LEFT JOIN Reply R ON R.Id = AR.Id
AND R.ReplyDate > AR.ContractDate AND R.ReplyDate < ISNULL(@PrevContractDate, DATEADD(DD, 1, R.ReplyDate))
WHERE AR.Id = @Id AND AR.CInfo = @CInfo
SET @PrevContractDate = @ContractDate
SET @PrevId = @Id
FETCH NEXT FROM appcursor
INTO @Id, @ContractDate, @CInfo
END
CLOSE appcursor;
DEALLOCATE appcursor;
SELECT * FROM @AppReply
希望这会有所帮助。 P.S。:这个查询编写得很快。对不起它的逻辑很差。