如何改进此查询以避免使用嵌套视图?

时间:2012-05-05 14:35:36

标签: mysql sql

查找访问过与保险公司相关的所有骨科医生(专科)的患者。

数据库:Click here to view the sample data script in SQL Fiddle.

CREATE VIEW Orthos AS
SELECT  d.cid,d.did
FROM    Doctors d
WHERE d.speciality='Orthopedist';

CREATE VIEW OrthosPerInc AS
SELECT  o.cid, COUNT(o.did) as countd4i
FROM Orthos o
GROUP BY o.cid;

CREATE VIEW OrthoVisitsPerPat AS
SELECT v.pid,COUNT(o.did) as countv4d
FROM Orthos o,Visits v,Doctors d
WHERE o.did=v.did and d.did=o.did
GROUP BY v.pid,d.cid;

SELECT  p.pname,p.pid,p.cid
FROM  OrthoVisitsPerPat v, OrthosPerInc i,Patient p
WHERE i.countd4i = v.countv4d and p.pid=v.pid and p.cid=i.cid;

DROP VIEW IF EXISTS Orthos,OrthosPerInc,OrthoVisitsPerPat;

如何在一个查询中编写它?

尝试:

到目前为止,我试图解决这个问题。

SELECT  p.pid,p.pname,p.cid,COUNT(v.did)
FROM Visits v 
JOIN Doctors d ON v.did=d.did
JOIN Patient p ON p.pid=v.pid
WHERE d.cid=p.cid and d.speciality="Orthopedist"
GROUP BY p.pid,p.cid;

INTERSECT 

SELECT  p.pid,d.cid,COUNT(d.did)
FROM Doctors d 
JOIN Patient p ON p.cid=d.cid
WHERE d.speciality='Orthopedist'
GROUP BY d.cid;

3 个答案:

答案 0 :(得分:11)

熟悉您拥有的数据:

第一个关键是了解您拥有的数据。在这种情况下,您有四个表

  • InsuranceCompanies
  • 患者
  • 医生
  • 访问

您的目标:

查看所有访问过与保险公司相关的所有骨科医生(专科)的患者名单。

让我们退后一步,分析一下:

一般来说,当你整体看它们时,要求可能有点压倒性。让我们将需求分成更小的组件,以了解您需要做什么。

  1. A部分:您需要找到医生名单,其专长是'骨科医生
  2. b部分:查找访问#1中确定的医生的患者名单。
  3. C部分:过滤结果#2,找到共享同一家保险公司的患者和医生名单。
  4. D部分:了解访问与患者属于同一保险公司的每一位骨科医生的患者。
  5. 如何处理:

    1. 您需要确定您的主要目标,在这种情况下,以确定患者列表。因此,首先查询Patient表。

    2. 你有患者,实际上所有患者,但我们需要找到哪些患者去看医生。让我们不要担心医生是否是骨科医生。我们只需要患者名单和他们访问过的医生。患者和医生表之间没有映射。要了解这些信息,

      使用正确的关键字段的Visits表加入Patient表。

      然后将输出与Doctors表连接到正确的关键字段。

    3. 如果您已正确完成加入,您现在应该拥有所有患者和他们访问过的医生的清单。如果您使用LEFT OUTER JOIN,您甚至会发现从未去过医生的患者。如果您使用RIGHT OUTER JOIN,您将只找到去看医生的患者。

    4. 现在,您有所有患者和他们访问过的医生。但是,要求只找到骨科医生的医生。因此,应用条件来过滤结果,只给出所需的结果。

    5. 您现在已经在 part a part b 中拆分为更小的组件。您仍然需要由保险公司过滤它。这是一个棘手的部分,要求并不是说你需要展示保险公司,所以我们不必使用保险公司表。您的下一个问题是'How am I going to filter the results?'。有效点。找出三个表PatientDoctorVisits中的任何一个是否包含保险公司信息。 PatientDoctors有一个共同的字段。加入该公共字段以过滤结果。

    6. 查找每位患者访问过的唯一骨科医生的计数。

    7. 以下是可以通过多种方式完成的部分,其中一种方法是添加一个子查询,该查询将是输出中的第四列。该子查询将查询表医生并按特殊情况过滤='骨科医生'。除了该过滤器之外,您还必须通过将内部表上的保险公司与主查询上的患者表上的保险公司ID进行匹配来进行过滤。该子查询将返回与患者数据匹配的保险公司ID的所有骨科医生的计数。

    8. 您现在应该拥有来自子查询的字段patient idpatient namepatients visits counttotal number of Orthopedists in same insurance company。然后,您可以添加外部联接,该联接将在patients visits counttotal number of Orthopedists in same insurance company匹配的字段中过滤此派生表的结果。我不是说这是最好的方法。这是我能想到的一种方法。

    9. 如果你遵循上面的逻辑,你应该有这个。

    10. 访问过所有医生的病人名单

      仅由医生进行过滤,他们是骨科医生

      由患者和医生过滤共享相同的保险公司信息。

      然后,整个输出将被派生表输出中的两个计数字段过滤。

      球在你的球场上:

      • 一旦找到答案,一步一步尝试。将其作为单独的答案发布在此处。我会用它来补偿你在这个问题上得到的所有挫折。

      我相信你可以轻松地做到这一点。

      如果你绊倒......

      不要犹豫,将您的问题发布为comments to this answer,其他人和我将很乐意为您提供帮助。

      声明

      我已经提供了如何实现这种逻辑的众多方法之一。我确信有很多方法可以更好地实现这一点。

      结果:

      请参阅@Ofek Ron的答案,以获得产生所需输出的正确查询。我没有写任何查询部分。这是OP的全部努力。

答案 1 :(得分:4)

@Siva的解释:

这是第1-5部分的结果代码:

SELECT *
FROM Patient p
JOIN Visits v ON v.pid=p.pid
JOIN Doctors d ON d.did=v.did and d.cid=p.cid
WHERE d.speciality="Orthopedist"

应用第6部分:

SELECT p.pid,COUNT(d.did)
FROM Patient p
JOIN Visits v ON v.pid=p.pid
JOIN Doctors d ON d.did=v.did and d.cid=p.cid
WHERE d.speciality="Orthopedist"
GROUP BY p.pid

应用其余部分:Click here to view the demo in SQL Fiddle.

SELECT p.pid,p.cid,COUNT(DISTINCT d.did) as c
FROM Patient p
JOIN Visits v ON v.pid=p.pid
JOIN Doctors d ON d.did=v.did and d.cid=p.cid
WHERE d.speciality="Orthopedist"
GROUP BY p.pid
HAVING (p.cid,c) IN 
  (SELECT d.cid,COUNT(DISTINCT d.did)
  FROM Doctors d
  WHERE d.speciality="Orthopedist"
  GROUP BY d.cid);

答案 2 :(得分:0)

也许是这样的:

SELECT
    p.pname,
    p.pid,
    p.cid
FROM
    Patient AS p
    JOIN
    (
        SELECT v.pid,COUNT(o.did) as countv4d
        FROM    Doctors d
        JOIN    Visits v ON o.did=v.did
        WHERE d.speciality='Orthopedist'
        GROUP BY v.pid,d.cid;
    ) AS v
    ON p.pid=v.pid
    JOIN 
    (
        SELECT  o.cid, COUNT(o.did) as countd4i
        FROM    Doctors d
        WHERE d.speciality='Orthopedist'
        GROUP BY o.cid;
    ) AS i
    ON p.cid=i.cid
WHERE
    i.countd4i = v.countv4d