我有一份报告,我在其中捕获患者信息,其中一些信息存储在患者表中,其中一些信息存储在观察表中。以出生日期为例,如果我计算了提供DOB的所有记录,由于加入观察表,我得到的患者总数远远超过患者总数。如何为每个组仅评估一次运行总计?
编辑:http://sqlfiddle.com/#!3/27b91/1/0处的一些示例数据。如果我从该查询中计算出生日期,我想要2作为答案;同样适合种族和民族。
答案 0 :(得分:2)
以下对于您的具体情况可能是也可能不是正确的方法,但它可以是您可以使用的有用技术。
您可以在select语句中添加一些代码,以帮助自己回答诸如“下游”之类的问题(通过添加的标准或通过SSRS)。见this modification of your SQL Fiddle:
select pid, firstName, lastName, dateOfBirth, obsName, obsValue, obsDate,
rowRank, CASE rowRank WHEN 1 THEN 1 ELSE 0 END AS countableRow
from
(
select Person.pid, Person.firstName, Person.lastName, Person.dateOfBirth
, Obs.obsName, Obs.obsValue, Obs.obsDate,
ROW_NUMBER() OVER (PARTITION BY Person.pid, Person.firstName, Person.lastName, Person.dateOfBirth ORDER BY Obs.obsDate) AS rowRank
from Person
join Obs on Person.pId = Obs.pId
) rankedData
rowRank
字段将创建一个与组相关的排名编号,这对您下游可能有用,也可能没用。 countableRow
字段将为1或0,这样每个组将只有一行,其中只有一行。执行SUM(countableRow)
将为您提供数据中适当数量的组。
现在,您可以通过在每个组的第一行中转出实际字段值而不是像1这样的常量标量来扩展此功能(如果您愿意)。因此,如果您有CASE rowRank WHEN 1 THEN dateOfBirth ELSE NULL END AS countableDOB
,那么您可以使用此数据集获取每个不同生日的总人数。
当然,你可以使用像@ Russell的SQL这样的方法来做所有这些事情,所以这与可能与你的情况不符的特定下游要求最相关。
修改强>
显然,countableRow字段并不是您想要的查询类型的万能解决方案。我已向another SQL Fiddle添加了一些PARTITION BY
策略示例:
select pid, firstName, lastName, dateOfBirth, obsName, obsValue, obsDate,
rowRank, CASE rowRank WHEN 1 THEN 1 ELSE 0 END AS countableRow,
valueRank, CASE valueRank WHEN 1 THEN 1 ELSE 0 END AS valueCount,
dobRank, CASE WHEN dobRank = 1 AND dateOfBirth IS NOT NULL THEN 1 ELSE 0 END AS dobCount
from
(
select Person.pid, Person.firstName, Person.lastName, Person.dateOfBirth
, Obs.obsName, Obs.obsValue, Obs.obsDate,
ROW_NUMBER() OVER (PARTITION BY Person.pid, Person.firstName, Person.lastName, Person.dateOfBirth ORDER BY Obs.obsDate) AS rowRank,
ROW_NUMBER() OVER (PARTITION BY Obs.obsName, Obs.obsValue ORDER BY Obs.obsDate) AS valueRank,
ROW_Number() OVER (PARTITION BY Person.dateOfBirth ORDER BY Person.pid) AS dobRank
from Person
join Obs on Person.pId = Obs.pId
) rankedData
以免任何人误解我,认为这总是合适的,显然不是。这不是使用其他SQL查询获取特定答案的更好解决方案。它允许您做的是编码足够的信息,以便在单个结果集中的消费代码中简单地回答这些问题。这就是它可以派上用场的地方。
第二次编辑
由于您想知道如果比赛数据存储在多个地方是否可以这样做,答案绝对是。我修改了之前的SQL Fiddle中的代码,现在是available in a new one:
select pid, firstName, lastName, dateOfBirth, obsName, obsValue, obsDate,
rowRank, CASE rowRank WHEN 1 THEN 1 ELSE 0 END AS countableRow,
valueRank, CASE valueRank WHEN 1 THEN 1 ELSE 0 END AS valueCount,
dobRank, CASE WHEN dobRank = 1 AND dateOfBirth IS NOT NULL THEN 1 ELSE 0 END AS dobCount,
raceRank, CASE WHEN raceRank = 1 AND (race IS NOT NULL OR obsName = 'RACE') THEN 1 ELSE 0 END AS raceCount
from
(
select Person.pid, Person.firstName, Person.lastName, Person.dateOfBirth, Person.[race]
, Obs.obsName, Obs.obsValue, Obs.obsDate,
ROW_NUMBER() OVER (PARTITION BY Person.pid, Person.firstName, Person.lastName, Person.dateOfBirth ORDER BY Obs.obsDate) AS rowRank,
ROW_NUMBER() OVER (PARTITION BY Obs.obsName, Obs.obsValue ORDER BY Obs.obsDate) AS valueRank,
ROW_NUMBER() OVER (PARTITION BY Person.dateOfBirth ORDER BY Person.pid) AS dobRank,
ROW_NUMBER() OVER (PARTITION BY ISNULL(Person.race, CASE Obs.obsName WHEN 'RACE' THEN Obs.obsValue ELSE NULL END) ORDER BY Person.pid) AS raceRank
from Person
left join Obs on Person.pId = Obs.pId
) rankedData
正如您所看到的,在新的小提琴中,这恰当地将Races的数量计为3,其中2在Obs表中,第三个在Person表中。诀窍是PARTITION BY
可以包含表达式,而不仅仅是原始列输出。请注意,我在这里将连接更改为左连接,并且我们需要使用CASE仅包含obsValue WHERE obsName是'RACE'。它有点复杂,但并非如此复杂,它可以优雅地处理相当复杂的情况。
答案 1 :(得分:1)
事实证明,Jeroen指向RunningValue的指针比我想象的更具针对性。我能够通过以下代码获得我想要的结果:
=RunningValue(Iif(Not IsNothing(Fields!DATEOFBIRTH.Value)
, Fields!PATIENTID.Value
, Nothing)
, CountDistinct
, Nothing
)
特别感谢Dominic P,我将在下次记住他的技术。
答案 2 :(得分:0)
除非他们报告不同的DOB,否则每位患者只会记录一条记录:
SELECT P.FOO,
P.BAR,
(etc.),
O.DOB
FROM Patients P
INNER JOIN Observations O
ON P.PatientID = O.PatientID
GROUP BY P.FOO, P.BAR, (P.etc), O.DOB