1

我有一个报告,我在其中捕获患者信息,其中一些存储在患者表中,其中一些存储在观察表中。以出生日期为例,如果我计算所有提供 DOB 的记录,我得到的结果明显多于患者总数,因为加入了观察表。如何对每组仅评估一次运行总数?

编辑: http ://sqlfiddle.com/#! 3/27b91/1/0 上的一些示例数据。如果我从该查询中计算生日,我想要 2 作为答案;种族和民族也是如此。

4

3 回答 3

2

对于您的具体情况,以下方法可能是正确的方法,也可能不是正确的方法,但它可能是一种有用的技术,可供您使用。

您可以在您的 select 语句中添加一些代码,以帮助您自己回答诸如“下游”之类的问题(通过添加的标准或通过 SSRS)。请参阅您的 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,这样每个组将有一个且只有一行包含 1。这样做SUM(countableRow)将为您提供数据中适当数量的组。

现在,您可以通过在每组的第一行中转储实际字段值而不是像 1 这样的常量标量来扩展此功能(如果您愿意)。因此,如果您有CASE rowRank WHEN 1 THEN dateOfBirth ELSE NULL END AS countableDOB,例如,您可以仅使用此数据集获取每个不同生日的总人数。

当然,无论如何,您都可以使用 @Russell 之类的 SQL 方法来完成所有这些事情,因此这与可能与您的情况不匹配的特定下游需求最为相关。

编辑

显然 countableRow 字段对于您想要的查询类型没有一刀切的解决方案。我在另一个 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 中的代码,现在可以在新的代码中使用:

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

如您所见,在新的 Fiddle 中,这正确地将 Races 的数量计为 3,其中 2 在 Obs 表中,第三个在 Person 表中。诀窍是PARTITION BY可以包含表达式,而不仅仅是原始列输出。请注意,我在这里将连接更改为左连接,并且我们需要使用 CASE 来仅包含 obsValue WHERE obsName is 'RACE'。它有点复杂,但不是非常复杂,它甚至可以优雅地处理相当复杂的情况。

于 2012-06-11T21:21:46.103 回答
1

事实证明,Jeroen 指向 RunningValue 的指针比我想象的更准确。我能够使用以下代码获得我想要的结果:

=RunningValue(Iif(Not IsNothing(Fields!DATEOFBIRTH.Value)
        , Fields!PATIENTID.Value
        , Nothing)
    , CountDistinct
    , Nothing
    )

特别感谢 Dominic P,下次我会记住他的技术。

于 2012-06-12T20:53:04.057 回答
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
于 2012-06-11T18:37:00.103 回答