1

患者情報を取得するレポートがあります。その一部は患者テーブルに保存され、一部は観察テーブルに保存されます。生年月日を例にとると、DOB が提供されたすべてのレコードを数えると、観測テーブルへの結合により、患者の総数よりも大幅に多くなります。グループごとに 1 回だけ現在の合計を評価するにはどうすればよいですか?

編集: 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 を含む行が 1 つだけ含まれます。これを行うSUM(countableRow)と、データ内の適切な数のグループが得られます。

これで、各グループの最初の行で 1 のような定数スカラーの代わりに実際のフィールド値をダンプすることで、(必要に応じて) この機能を拡張できます。したがって、CASE rowRank WHEN 1 THEN dateOfBirth ELSE NULL END AS countableDOBたとえば、このデータセットだけを使用して、誕生日ごとに異なる人の総数を取得できます。

もちろん、とにかく @Russell のようなメソッドを SQL で使用してこれらすべてのことを実行できるため、これは状況に一致しない可能性がある特定のダウンストリーム要件に最も関連します。

編集

明らかに、 countableRow フィールドには、必要なクエリの種類に対する万能のソリューションはありません。別の SQL FiddlePARTITION 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 クエリを使用して特定の回答を得るための優れたソリューションではありません。これにより、消費するコード内のそのような質問にすべて 1 つの結果セットで簡単に答えることができるように、十分な情報をエンコードすることができます。それが便利になるところです。

2回目の編集

レースデータを複数の場所に保存している場合、これができるかどうか疑問に思っていたので、答えは絶対です。以前の 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 では、Race の数が 3 として適切にカウントされます。2 つは Obs テーブルにあり、3 番目は 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 を報告しない限り、これは患者ごとに 1 つのレコードのみを取得します。

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 に答える