4

同じ日に同じ専門分野の 2 人の異なる医師を訪れた患者を見つけます。

サンプル データベース:ここをクリックして、SQL Fiddle のサンプル データ スクリプトを表示します。

CREATE VIEW DistinctVisits AS
SELECT v.vid,v.pid,d.speciality,v.date
FROM Visits v ,Doctors d
WHERE d.did=v.did
GROUP BY v.pid,v.did,v.date;

CREATE VIEW DistinctVisits2 AS
SELECT dv.pid,dv.speciality,dv.date, COUNT(dv.vid) as countv
FROM DistinctVisits dv
GROUP BY dv.pid,dv.speciality,dv.date;

SELECT dv2.pid,dv2.speciality
FROM DistinctVisits2 dv2
WHERE dv2.countv=2;

DROP VIEW DistinctVisits;
DROP VIEW DistinctVisits2;

同じアイデアを 1 つの大きなクエリで繰り返すにはどうすればよいですか? 別の解決策もいいでしょうが、最初にこれを改善するのを手伝ってください.

4

5 に答える 5

7

説明:

  • 特定の日に同じ専門分野の 2 人の異なる医師を訪れた患者のリストを検索する必要があります。

  • この要件では、Patientテーブルがメイン テーブルになります。最初にそのテーブルをクエリしましょう。

  • これで、患者のリストができました。彼らが訪れた医師のリストを取得する必要があります。データをマップする列がないため、Patients テーブルと Doctors テーブルを単純に結合することはできません。Visits を中間テーブルとして使用する必要があります

  • LEFT OUTER JOIN患者テーブルと訪問テーブルの間に追加し、pid列で結合します。

  • 患者とその訪問のリストはありますが、今度は医師の情報を取得する必要があります。LEFT OUTER JOINそのため、 Visits テーブルと Doctors テーブルの間に別のテーブルを追加し、 did列で結合します。

  • 患者様とご来院の情報を掲載しております。ただし、必要なのは、患者の名前、訪問した医師の専門分野、および訪問した日付だけです。したがって、列を追加p.pnamed.specialityv.dateSELECTGROUP BY句にも追加します。これに加えて、すべての訪問数が必要ですが、落とし穴があります。DISTINCT カウントのみが必要です。つまり、訪問したすべての一意の医師のカウントが必要です。したがって、患者が特定の日に同じ医者を 2 回訪れた場合、1 としてカウントする必要がありDISTINCTます。また、重要なのは正しい列名を使用することです。この場合、d.didは医師を表します。

  • 必要なデータはすべて揃っていますが、同じ日に 2 人の異なる医師を訪れた患者のみをフィルター処理する必要があります。これを行うには、HAVING 句が役に立ちます。GROUP BY を適用する場合は、HAVING が適切です。同じ COUNT(DISTINCT d.did) を使用して、カウントが2の値のみと一致するかどうかを確認します。出力で結果を確認できます。

提案:

  • テーブルに挿入されるすべての値に対して INSERT INTO ステートメントを指定する必要はありません。それらを括弧内にグループ化し、 で区切ることができますcommas。最後のステートメントは で終わる必要がありsemicolonます。

  • クエリはLEFT OUTER JOIN. この結合を使用して、各患者が一度も医者にかかったことがない場合でも、すべての医者の訪問を調べました。クエリを作成したときの出力を見たかっただけです。これを に変更できます。これINNER JOINは、シナリオにより適していると思います。

  • 訪問数を表示したくない場合は、SELECT 句から削除できます。

デモ:

SQL Fiddle でデモを表示するには、ここをクリックしてください。

説明に使用するスクリプト:

SELECT          p.pname
            ,   d.speciality 
            ,   v.date
            ,   COUNT(DISTINCT d.did) AS visitcount
FROM            Patient p
LEFT OUTER JOIN Visits v
ON              v.pid = p.pid
LEFT OUTER JOIN Doctors d
ON              d.did = v.did
GROUP BY        p.pname
            ,   d.speciality
            ,   v.date
HAVING          COUNT(DISTINCT d.did) = 2

より適切なスクリプト:

SELECT      p.pname
        ,   d.speciality 
        ,   v.date
FROM        Patient p
INNER JOIN Visits v
ON          v.pid = p.pid
INNER JOIN Doctors d
ON          d.did = v.did
GROUP BY    p.pname
        ,   d.speciality
        ,   v.date
HAVING      COUNT(DISTINCT d.did) = 2

出力:

PNAME      SPECIALITY    DATE       VISITCOUNT
---------  ------------  ---------  -----------
Loch Ness  Assholes      17/9/2012      2
Loch Ness  Orthopedist   13/1/2011      2

テーブルを作成し、スクリプトを挿入します。

create table InsuranceCompanies  (
    cid         int,
    cname       varchar(20),
    primary key (cid)
);

create table Patient (
    pid         int,
    pname       varchar(20),
    age         int,
    cid         int,
    gender      char,
    primary     key (pid),
    constraint foreign key (cid) 
        references InsuranceCompanies (cid) 
);

create table Doctors (
    did         int ,
    dname       varchar(20),
    speciality  varchar(20),
    age         int,
    cid         int,
    primary key (did),
    constraint foreign key (cid) 
        references InsuranceCompanies (cid) 
);

create table Visits(
    vid         int,
    pid         int,
    did         int,
    date        varchar(20),
    primary key (vid),
    constraint foreign key (pid) 
        references Patient (pid) ,
    constraint foreign key (did) 
        references Doctors (did)
);

INSERT INTO InsuranceCompanies(cid, cname) VALUES
    ( 1111, 'Harel Inc' ),
    ( 2222, 'Clalit Inc' );

INSERT INTO Doctors ( did, dname, speciality, age, cid) VALUES 
    ( 100, 'Jhonny Depp',       'Heart',        42, 1111 ),
    ( 101, 'Tom Tolan',         'Assholes',     62, 1111 ),
    ( 105, 'Yom Tov',           'Assholes',     52, 1111 ),
    ( 102, 'Lauren Jaime',      'Throat',       27, 2222 ),
    ( 103, 'Gomez Flaurence',   'Legs',         37, 2222 ),
    ( 106, 'David Harpaz',      'Orthopedist',  37, 2222 ),
    ( 107, 'David Schwimmer',   'Orthopedist',  37, 2222 ),
    ( 108, 'Sammy Salut',       'Orthopedist',  37, 1111 );

INSERT INTO Patient ( pid, pname, age, cid,gender) VALUES 
    ( 200, 'Jon Gilmour',       25, 2222, 'm' ),
    ( 206, 'Bon Gilmour',       30, 2222, 'm' ),
    ( 205, 'Jon Gilmour',       22, 2222, 'm' ),
    ( 201, 'Bon Jovy',          21, 2222, 'm' ),
    ( 202, 'Loch Ness',         17, 2222, 'f' ),
    ( 203, 'Lilach Sonin',      12, 1111, 'f' ),
    ( 209, 'Lilach Dba',        34, 1111, 'f' ),
    ( 210, 'Paulina Daf',       32, 1111, 'f' ),
    ( 204, 'Gerry Jalor',       23, 1111, 'm' ),
    ( 208, 'Jerrushalem Jalor', 23, 1111, 'm' );

INSERT INTO Visits ( vid, pid, did, date) VALUES 
    ( 300, 204, 100,    '12/12/2012' ),
    ( 301, 204, 101,    '12/12/2012' ),
    ( 302, 204, 101,    '02/01/2012' ),
    ( 303, 202, 101,    '17/09/2012' ),
    ( 311, 202, 105,    '17/09/2012' ),
    ( 304, 203, 102,    '12/12/2011' ),
    ( 312, 202, 106,    '13/06/2012' ),
    ( 314, 202, 107,    '13/01/2011' ),
    ( 313, 202, 108,    '13/01/2011' ),
    ( 305, 204, 102,    '10/10/2011' ),
    ( 306, 201, 100,    '12/01/2012' ),
    ( 316, 204, 108,    '18/05/2012' ),
    ( 307, 202, 100,    '12/07/2012' ),
    ( 315, 203, 108,    '12/07/2012' ),
    ( 310, 204, 103,    '10/04/2012' ),
    ( 308, 203, 102,    '12/12/2011' ),
    ( 309, 200, 101,    '12/12/2012' );
于 2012-05-05T13:49:44.587 に答える
2

必要なのは、日付と専門分野でグループ化した後HAVINGに検索する句です。COUNT(*) = 2実際、入れ子にする必要さえありません。(また、コンマ区切りFROM句による暗黙的な結合JOINを、より好ましい最新の構文である明示的な に置き換えました)。

SELECT 
  v.pid,
  d.speciality,
  v.date,
  COUNT(COUNT DISTINCT d.did) AS numvisits
FROM 
  visits v
  JOIN Doctors d ON v.did = d.did
GROUP BY v.pid, d.speciality, v.date
HAVING COUNT(COUNT DISTINCT d.did) = 2
/* Note - depending on your RDBMS, you may
   be able to use the count alias as
HAVING numvisits = 2 
   MySQL allows this, for ex, but MS SQL Server doesn't and I think Oracle doesn't */

ここのSELECTリストGROUP BYは、患者 ID、専門分野、日付、およびこれらの 3 つの列の集計の組み合わせの訪問数を生成する必要があります。このHAVING句は、グループの 2 回の訪問がある人のみに制限します。

これから患者のみを取得するには、サブクエリでラップします。

SELECT Patients.* 
FROM Patients JOIN (
  SELECT 
    v.pid,
    d.speciality,
    v.date,
    COUNT(COUNT DISTINCT d.did) AS numvisits
  FROM 
    visits v
    JOIN Doctors d ON v.did = d.did
  GROUP BY v.pid, d.speciality, v.date
  HAVING COUNT(COUNT DISTINCT d.did) = 2
) subq ON Patients.pid = subq.pid
于 2012-05-05T13:06:59.433 に答える
1

Sivaの回答から少し遅れましたが、私の質問は次のとおりです。

SELECT v.pid, d.speciality, count(DISTINCT d.did) as cnt
  FROM Visits v
  JOIN Doctors d ON v.did = d.did
 GROUP BY v.pid, d.speciality, v.date
HAVING count(DISTINCT d.did) = 2;

ビューのない最初の OP のクエリとまったく同じ出力が生成されます。

于 2012-05-05T14:04:17.130 に答える
0
WITH
dv1 as
(
    SELECT v.vid, v.pid, d.speciality, v.date
    FROM Visits v, Doctors d
    WHERE d.did=v.did
    GROUP BY v.pid,v.did,v.date;
),
dv2 as
(
    SELECT dv.pid,dv.speciality,dv.date, COUNT(dv.vid) as countv
    FROM dv1
    GROUP BY dv.pid,dv.speciality,dv.date;
)
SELECT dv2.pid, dv2.speciality
FROM dv2
WHERE dv2.countv=2;
于 2012-05-05T13:07:24.730 に答える
0

ネストされた CTE を使用できます (mysql を使用していない場合、つまり...) CTE は、ステートメントの期間中のみ存在する即時ビューと見なすことができます。(注: 未テスト)

WITH DistinctVisits2 AS (
    WITH DistinctVisits AS (
        SELECT v.vid,v.pid,d.speciality,v.date
        FROM Visits v
        JOIN Doctors d ON d.did=v.did
        GROUP BY v.pid,v.did,v.date
        )
    SELECT dv.pid,dv.speciality,dv.date, COUNT(dv.vid) as countv
    FROM DistinctVisits dv
    GROUP BY dv.pid,dv.speciality,dv.date
    )
SELECT dv2.pid,dv2.speciality
FROM DistinctVisits2 dv2
WHERE dv2.countv=2
    ;
于 2012-05-05T13:09:56.213 に答える