嵌套查询的时间重叠
Time overlaps from Nesting queries
根据要求我查找的当前架构
-- 未经检测并接触过某种传染病的人
-- 不要列出任何人两次,也不要列出已知的病人
-- 暴露 = 在同一个地方,时间重叠(为简单起见,不需要重叠时间)
从下面的查询中我找到了我的答案,除了我不能删除 'postive' 的人,因为我的查询的第二部分,即时间流逝取决于第一部分,即积极的人去的时间相同的位置。
select * from (
select DISTINCT person.PersonID, Register.LocID, Register.Checkin, Register.CheckOut
from person
join Register on Person.PersonID = Register.PersonID
join testing on person.PersonID = testing.PersonID
where testing.Results is 'Positive' ) a
join (
SELECT DISTINCT Person.PersonID, Register.LocID , Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID
where person.PersonID
not in (SELECT DISTINCT testing.PersonID from testing)) b on a.LocID = b.LocID
and b.checkin >= a.CheckIn and b.CheckIn <= a.CheckOut
所以我的问题是,这个查询需要做什么修改才能只显示第二部分的结果?
我认为第一部分是
select * from (
select DISTINCT person.PersonID, Register.LocID, Register.Checkin, Register.CheckOut
from person
join Register on Person.PersonID = Register.PersonID
join testing on person.PersonID = testing.PersonID
where testing.Results is 'Positive' ) a
第二部分是
join (
SELECT DISTINCT Person.PersonID, Register.LocID , Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID
where person.PersonID
not in (SELECT DISTINCT testing.PersonID from testing)) b on a.LocID = b.LocID
and b.checkin >= a.CheckIn and b.CheckIn <= a.CheckOut
这是一个复杂的查询。因为您不想要重复项,所以我建议 exists
仅使用 persons
.
进行外部查询
让人们同时出现在同一地点的想法是 self-join 在 register
上使用位置和时间重叠。我认为这是查询中最复杂的部分。剩下的就是检查一个人是否是积极的:
select p.*
from person p
where not exists (select 1
from testing t
where t.personid = p.personId and t.results = 'positive'
) and
exists (select 1
from register r1 join
register r2
on r1.locid = r2.locid and
r1.checkin < r2.checkout and
r2.checkout > r1.checkin join
testing t2
on r2.personid = t2.personid and
t2.results = 'positive' and
t2.timestamp < r2.checkout
where r1.personid = p.personid
);
时机有点棘手,但我认为时机是有道理的。在 他们在同一个地方之前,有人需要检测呈阳性 。当然,如果没有时间限制,你可以去掉t2.timestamp < r2.checkout
。
为了便于阅读,您可以像这样创建 CTE
s:
with
-- returns all the untested persons
untested as (select p.* from person p left join testing t on t.personid = p.personid where t.testingid is null),
-- returns all the infected persons
infected as (select * from testing where results = 'Positive'),
-- returns all the locids that infected persons visited and the start and dates of these visits
loc_positive as (
select r.locid, i.timestamp startdate, r.checkout enddate
from register r inner join infected i
on i.personid = r.personid and i.timestamp between r.checkin and r.checkout
)
-- returns the distinct untested persons that visited the same locids with persons tested positive at the same time after they were tested
select distinct u.*
from untested u
inner join register r on r.personid = u.personid
inner join loc_positive lp on lp.locid = r.locid
where lp.startdate <= r.checkout and lp.enddate >= r.checkin
这个答案的解决方案是在第一行的星号上添加一个不同的列名。
select DISTINCT unt.PersonID from (
select person.PersonID, Register.LocID, Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID join testing on person.PersonID = testing.PersonID
where testing.Results is 'Positive' ) pos
join (
SELECT Person.PersonID, Register.LocID , Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID where person.PersonID
not in (SELECT testing.PersonID from testing)) unt on pos.LocID = unt.LocID
and unt.checkin >= pos.CheckIn and unt.CheckIn <= pos.CheckOut;
根据要求我查找的当前架构
从下面的查询中我找到了我的答案,除了我不能删除 'postive' 的人,因为我的查询的第二部分,即时间流逝取决于第一部分,即积极的人去的时间相同的位置。
select * from (
select DISTINCT person.PersonID, Register.LocID, Register.Checkin, Register.CheckOut
from person
join Register on Person.PersonID = Register.PersonID
join testing on person.PersonID = testing.PersonID
where testing.Results is 'Positive' ) a
join (
SELECT DISTINCT Person.PersonID, Register.LocID , Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID
where person.PersonID
not in (SELECT DISTINCT testing.PersonID from testing)) b on a.LocID = b.LocID
and b.checkin >= a.CheckIn and b.CheckIn <= a.CheckOut
所以我的问题是,这个查询需要做什么修改才能只显示第二部分的结果?
我认为第一部分是
select * from (
select DISTINCT person.PersonID, Register.LocID, Register.Checkin, Register.CheckOut
from person
join Register on Person.PersonID = Register.PersonID
join testing on person.PersonID = testing.PersonID
where testing.Results is 'Positive' ) a
第二部分是
join (
SELECT DISTINCT Person.PersonID, Register.LocID , Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID
where person.PersonID
not in (SELECT DISTINCT testing.PersonID from testing)) b on a.LocID = b.LocID
and b.checkin >= a.CheckIn and b.CheckIn <= a.CheckOut
这是一个复杂的查询。因为您不想要重复项,所以我建议 exists
仅使用 persons
.
让人们同时出现在同一地点的想法是 self-join 在 register
上使用位置和时间重叠。我认为这是查询中最复杂的部分。剩下的就是检查一个人是否是积极的:
select p.*
from person p
where not exists (select 1
from testing t
where t.personid = p.personId and t.results = 'positive'
) and
exists (select 1
from register r1 join
register r2
on r1.locid = r2.locid and
r1.checkin < r2.checkout and
r2.checkout > r1.checkin join
testing t2
on r2.personid = t2.personid and
t2.results = 'positive' and
t2.timestamp < r2.checkout
where r1.personid = p.personid
);
时机有点棘手,但我认为时机是有道理的。在 他们在同一个地方之前,有人需要检测呈阳性 。当然,如果没有时间限制,你可以去掉t2.timestamp < r2.checkout
。
为了便于阅读,您可以像这样创建 CTE
s:
with
-- returns all the untested persons
untested as (select p.* from person p left join testing t on t.personid = p.personid where t.testingid is null),
-- returns all the infected persons
infected as (select * from testing where results = 'Positive'),
-- returns all the locids that infected persons visited and the start and dates of these visits
loc_positive as (
select r.locid, i.timestamp startdate, r.checkout enddate
from register r inner join infected i
on i.personid = r.personid and i.timestamp between r.checkin and r.checkout
)
-- returns the distinct untested persons that visited the same locids with persons tested positive at the same time after they were tested
select distinct u.*
from untested u
inner join register r on r.personid = u.personid
inner join loc_positive lp on lp.locid = r.locid
where lp.startdate <= r.checkout and lp.enddate >= r.checkin
这个答案的解决方案是在第一行的星号上添加一个不同的列名。
select DISTINCT unt.PersonID from (
select person.PersonID, Register.LocID, Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID join testing on person.PersonID = testing.PersonID
where testing.Results is 'Positive' ) pos
join (
SELECT Person.PersonID, Register.LocID , Register.Checkin, Register.CheckOut
from person join Register on Person.PersonID = Register.PersonID where person.PersonID
not in (SELECT testing.PersonID from testing)) unt on pos.LocID = unt.LocID
and unt.checkin >= pos.CheckIn and unt.CheckIn <= pos.CheckOut;