我正在尝试编写一个存储过程,该存储过程将仅返回在{strong> all 或右侧未产生任何结果的记录。在右侧找到的记录的“ strong>”中,仅返回在另一个表中具有匹配项的结果集。
为说明我要达到的目的,请首先考虑以下表格定义:
LEFT JOIN
第一个表CREATE TYPE [dbo].[TvpDocumentsSent] AS TABLE
(
DocumentId INT
, RecipientId INT
, TransactionId INT
);
CREATE TABLE [dbo].[Recipients]
(
RecipientId INT
, GroupId INT
)
CREATE TABLE [dbo[.[RecipientEmails]
(
RecipientId INT
, TransactionID INT
)
CREATE TABLE [dbo].[DocumentTransactions]
(
TransactionId INT
, DocumentId INT
)
在存储过程中用作表值参数。它表示我们正在检查的记录。
第二张表TvpDocumentsSent
包含所有潜在的文档接收者。值得注意的是,收件人被分组放置(由Recipients
表示)。群组中的所有收件人都应在文档之前收到文档,该文档被标记为可存档。顺便说一句,这就是我正在努力的部分。
接下来,GroupId
表将容纳已发送给收件人的所有电子邮件(可能包含也可能不包含文档)。
后一个表RecipientEmails
存储已发生的所有文档交易的日志。这告诉我发送了什么文档(由DocumentTransactions
指示)。尽管此表上没有没有 DocumentId
,但是RecipientId
可用于通过TransactionId
表将DocumentTransaction追溯到收件人。
我正在苦苦挣扎的是如何编写一个查询,该查询只给我通过RecipientEmails
传递的记录的子集;只有那些没有其他收件人等待组中的人或的所有收件人都已收到该文件(即TvpDcoumentsSent
表中有一条记录,其中{{1} }映射回DocumentTransactions
中的记录,该记录的收件人有资格使用此文档。
到目前为止,我想的是这个(注意:我知道我在下面的查询中使用TransactionId
作为表而不是TVP。我这样做是为了简化说明)
RecipientEmail
请记住,可能有n位收件人可能接收该文档,我如何履行TvpDocumentsSent
子句的SELECT
SNT.DocumentId
FROM [dbo].[TvpDocumentsSent] AS SNT
INNER JOIN [dbo].[Recipients] AS RCP ON -- The recipient who recieved the document during this transaction.
RCP.RecipientId = SNT.RecipientId
LEFT JOIN [dbo].[Recipients] AS OTHR_RCP ON -- Other recipients who may have already received the document or could later.
RCP.GroupId = OTHR_RCP.GroupId
AND RCP.RecipientId != OTHR_RCP.RecipientId
WHERE OTHR_RCP.RecipientId IS NULL OR ??????
部分以确保每个人都收到了文档?
我尝试了以下操作,但无法正常工作:
OR
那是行不通的,因为只要收件人之一收到了文档,WHERE
子句的SELECT
SNT.DocumentId
FROM [dbo].[TvpDocumentsSent] AS SNT
INNER JOIN [dbo].[Recipients] AS RCP ON -- The recipient who recieved the document during this transaction.
RCP.RecipientId = SNT.RecipientId
LEFT JOIN [dbo].[Recipients] AS OTHR_RCP ON -- Other recipients who may have already received the document or could later.
RCP.GroupId = OTHR_RCP.GroupId
AND RCP.RecipientId != OTHR_RCP.RecipientId
LEFT JOIN [dbo].[DocumentTransactions] AS DT ON
SNT.TransactionId = DT.TransactionId
WHERE OTHR_RCP.RecipientId IS NULL OR DT.DocumentId IS NOT NULL
部分就会通过。假设应该有5位收件人收到了文档,但到目前为止只有1位收到了。 OR
将看到1条记录的匹配并通过WHERE
;错了...应该强制所有潜在收件人已收到文档。
答案 0 :(得分:1)
不确定下面的示例是否接近。
由于我不得不模拟样本数据并猜测预期结果。
但是在子查询中进行汇总,然后比较总计可能会在这里有所帮助。
(或通过HAVING子句)
示例代码段:
declare @Recipients table (RecipientId int primary key, GroupId int);
declare @DocumentTransactions table (TransactionId int primary key, DocumentId int);
declare @DocumentsSent table (DocumentId int, RecipientId int, TransactionId int);
declare @RecipientEmails table (RecipientId int, TransactionID int);
insert into @Recipients (RecipientId, GroupId) values
(201,1),(202,1),(203,1),(204,2),(205,2),(206,2);
insert into @DocumentTransactions (TransactionId, DocumentId) values
(301,101),(302,101),(303,101),(304,102),(305,102),(306,102);
insert into @DocumentsSent (DocumentId, RecipientId, TransactionId) values
(101,201,301),(101,202,302),(101,203,303)
,(102,204,304),(102,205,305),(102,206,306);
insert into @RecipientEmails (RecipientId, TransactionId) values
(201,301),(202,302),(203,303)
,(204,304);
SELECT DocumentId
FROM
(
SELECT
tr.DocumentId,
rcpt.GroupId,
count(distinct sent.RecipientId) AS TotalSent,
count(distinct rcptmail.RecipientId) AS TotalRcptEmail
FROM @DocumentsSent AS sent
LEFT JOIN @Recipients AS rcpt ON rcpt.RecipientId = sent.RecipientId
LEFT JOIN @DocumentTransactions AS tr
ON (tr.TransactionId = sent.TransactionId AND tr.DocumentId = sent.DocumentId)
LEFT JOIN @RecipientEmails AS rcptmail
ON (rcptmail.TransactionId = sent.TransactionId AND rcptmail.RecipientId = sent.RecipientId)
GROUP BY tr.DocumentId, rcpt.GroupId
) AS q
WHERE (TotalSent = TotalRcptEmail OR (TotalSent > 0 AND TotalRcptEmail = 0))
GROUP BY DocumentId;
/*
SELECT
tr.TransactionId,
sent.DocumentId,
sent.RecipientId AS RecipientIdSent,
rcpt.GroupId AS GroupIdRcpt,
rcpt.RecipientId AS RecipientIdRcpt,
rcptmail.RecipientId AS RecipientIdEmail
FROM @DocumentsSent AS sent
LEFT JOIN @Recipients AS rcpt ON rcpt.RecipientId = sent.RecipientId
LEFT JOIN @DocumentTransactions AS tr
ON (tr.TransactionId = sent.TransactionId AND tr.DocumentId = sent.DocumentId)
LEFT JOIN @RecipientEmails AS rcptmail
ON (rcptmail.TransactionId = sent.TransactionId AND rcptmail.RecipientId = sent.RecipientId);
*/
返回:
DocumentId
----------
101