我找不到以抽象和一般方式描述我的问题的方法,所以我只提供一个最小的例子:
我们说我有这三个简单的表格:
CREATE TABLE Document(
[Id] int IDENTITY(1, 1) NOT NULL PRIMARY KEY,
[Title] nvarchar(MAX),
[Patient] nvarchar(MAX)
);
CREATE TABLE Link(
DocumentId INT FOREIGN KEY REFERENCES Document(Id),
Text nvarchar(max)
);
CREATE TABLE ReadStatus(
DocumentId INT FOREIGN KEY REFERENCES Document(Id),
IsRead Bit NOT NULL,
UserId Int NOT NULL
);
ReadStatus
表跟踪,该表将用户与文档相关联,IsRead=1
表示该用户已读取文档{{1}这意味着它尚未被该用户阅读。IsRead=0
和用户X
,A
表中不存在行,我们假设用户ReadStatus
没有读取文档{ {1}}。现在,我需要运行一个查询来选择所有患者。对于每位患者,我需要可用文件的总数和已经阅读的文件数(即A
)。这就是我到目前为止所做的:
X
当文档(已经读取)具有多个链接时,会出现问题。如果该文档有3个链接,则INNER JOIN与Link表生成的笛卡尔积将导致IsRead=1
选择为3而不是1。
换句话说,鉴于此数据:
SELECT d.Patient,
COUNT(DISTINCT d.Id) AS DocumentCount,
COUNT(NULLIF(rs.IsRead,0)) AS ReadDocumentCount,
COUNT(*) OVER () AS TotalPatientCount
FROM Document d
LEFT OUTER JOIN ReadStatus AS rs ON d.Id = rs.DocumentId AND rs.UserId = 123
INNER JOIN Link AS l ON d.Id = l.DocumentId AND l.Text IN ('Link W', 'Link X', 'Link T', 'Link Z')
GROUP BY d.Patient
我得到了这个结果:
ReadDocumentCount
这是我想要的:
INSERT INTO Document(Title, Patient) VALUES('Doc A', 'Mike')
INSERT INTO Document(Title, Patient) VALUES('Doc B', 'Mike')
INSERT INTO Link(DocumentId, Text) VALUES(1, N'Link W')
INSERT INTO Link(DocumentId, Text) VALUES(1, N'Link X')
INSERT INTO Link(DocumentId, Text) VALUES(1, N'Link Y')
INSERT INTO Link(DocumentId, Text) VALUES(2, N'Link Z')
INSERT INTO ReadStatus(DocumentID, IsRead, UserId) VALUES(1, 1, 123)
INSERT INTO ReadStatus(DocumentID, IsRead, UserId) VALUES(2, 0, 123)
答案 0 :(得分:6)
您也可以有条件地使用COUNT(DISTINCT)
:
SELECT d.Patient,
COUNT(DISTINCT d.Id) AS DocumentCount,
COUNT(DISTINCT (CASE WHEN rs.IsRead <> 0 THEN d.id END)) AS ReadDocumentCount,
COUNT(*) OVER () AS TotalPatientCount
FROM Document d LEFT OUTER JOIN
ReadStatus rs
ON d.Id = rs.DocumentId AND rs.UserId = 123 INNER JOIN
Link l
ON d.Id = l.DocumentId AND l.Text IN ('Link W', 'Link X', 'Link T', 'Link Z')
GROUP BY d.Patient;