找到在同一天访问过两位同一专业医生的病人。
示例数据库:Click here to view the sample data script in 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;
我如何重复相同的想法,但仅针对一个大问题? 另一个解决方案也不错,但请先尝试帮助我改进这个。
答案 0 :(得分:7)
您需要查找在某一天访问过两位同一专业的不同医生的患者名单。
在此要求中,您的Patient
表成为主表。我们先查询该表。
现在我们有患者名单。我们需要获得他们访问过的医生名单。我们不能简单地将Patients表与Doctors表一起加入,因为没有列来映射数据。我们必须使用Visits作为中间表
在患者和访问表之间添加LEFT OUTER JOIN
,并通过 pid 列加入。
我们有病人和他们的访问清单,但现在我们需要获取医生的信息。因此,在“访问次数”和“医生”表之间添加另一个LEFT OUTER JOIN
,然后按执行列加入。
我们有患者和医生访问的信息。但是,我们只需要患者的姓名,他们所访问的医生的专长以及他们访问的日期。因此,我们会将列p.pname
,d.speciality
和v.date
添加到 SELECT 子句以及 GROUP BY 子句中。除此之外,我们需要所有的访问次数,但有一个问题。我们只需要DISTINCT计数,换句话说,我们需要他们访问过的所有独特医生的数量。因此,如果患者在给定日期两次访问同一位医生,则应将其计为1.因此,添加 DISTINCT
将有助于此。此外,关键是使用正确的列名称,在这种情况下, d.did 代表医生。
我们拥有所需的所有数据,但我们只需要过滤同一天访问过两位不同医生的患者。要做到这一点,HAVING条款来解救我们。当您应用GROUP BY时,HAVING是合适的。我们将使用相同的COUNT(DISTINCT d.did)来检查计数是否仅匹配 2 的值。您可以在输出中看到结果。
您不必为插入表中的每个值指定INSERT INTO语句。您可以在括号内将它们组合在一起,并通过 commas
将它们分开。最后一个语句应以 semicolon
。
查询使用LEFT OUTER JOIN
。我使用这个联接找出每个患者的所有医生就诊 即使 他们从未去过医生。我只是想在我形成查询时看到输出。您可以将其更改为INNER JOIN
,我认为这更适合您的方案。
如果您不想显示访问次数,可以将其从SELECT子句中删除。
Click here to view the demo in 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' );
答案 1 :(得分: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
答案 2 :(得分: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查询完全相同。
答案 3 :(得分: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;
答案 4 :(得分: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
;