#sql #sqlite #db-browser-sqlite
#sql #sqlite #db-browser-sqlite
Вопрос:
На основе текущей схемы меня попросили найти
— люди, которые не были проверены и подверглись воздействию какой-либо одной инфекции — Не перечисляйте никого дважды и не перечисляйте известных больных людей — Подвержены = в одном и том же месте и перекрываются во времени (для простоты не требуется время перекрытия)
Из приведенного ниже запроса я нахожу свой ответ, за исключением того, что я не могу удалить людей, которые являются «положительными», потому что вторая часть моего запроса, т. Е. промежуток времени, зависит от первой части, т. Е. Времени, когда положительные люди отправились в одни и те же места.
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
Ответ №1:
Для удобства чтения вы можете создавать CTE
такие запросы:
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
Комментарии:
1. Спасибо. То, что я не упомянул, и моя ошибка, то есть непроверенный пользователь, — это те, которых нет в таблице тестирования.
2. Это то, что
untested
возвращает cte.3. Да, извините, вы правы. Я использую db browser для sql lite. Если я помещаю запрос с
untested as
, он возвращается с ошибками, и я ввожу запрос самостоятельно, он приходит.
Ответ №2:
Это сложный запрос. Поскольку вам не нужны дубликаты, я собираюсь предложить exists
просто использовать внешний запрос persons
.
Идея собрать людей в одном и том же месте в одно и то же время заключается в самосоединении 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
, если нет ограничений по времени.
Комментарии:
1. Спасибо. Запрос вернулся с нулевыми результатами (может быть, моя база данных). Я не уверен, почему результат был таким, но я не очень понимаю идею самостоятельного объединения и существования, поэтому я использовал «не в». Я согласен, что это очень сложный запрос. Что касается меня, я, кажется, не могу выбросить из головы, что невозможно получить ответ, не показывая положительных людей, потому что временные перекрытия зависят от времени положительных людей. Я ценю вашу помощь, хотя, поскольку я знаю, что трудно дать ответ без встроенной базы данных. Но поскольку я использую облегченную версию sql, у меня возникают проблемы с ее созданием в Интернете. Спасибо
2. @Vij . . . Можете ли вы настроить db<>fiddle? Проблема может заключаться в времени получения положительного результата относительно нахождения в том же местоположении.
3. Привет, Гордон, спасибо за ваш вклад. Мне удалось это решить, я склонен все усложнять, и вопрос, возможно, получился неправильным из-за того, что я пытался решить. Что касается db<>fiddle, я никогда не знал, что это существует. Я рассмотрю это, чтобы в будущих вопросах я мог лучше объяснить это для вас, ребята.
Ответ №3:
Решение этого ответа состояло в том, чтобы добавить distinct и имя столбца к звезде в первой строке.
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;
Комментарии:
1.
unt.checkin >= pos.CheckIn and unt.CheckIn <= pos.CheckOut
это неправильный способ проверить, находился ли непроверенный пользователь в одно и то же время в одном и том же месте с зараженным человеком. Непроверенный пользователь, возможно, зарегистрировался до того, как зараженный человек зарегистрировался, и выписался после прибытия зараженного человека.2. Вы правы. Я попытался настроить запрос на ` и unt.checkin >= pos. Проверка и пересдача. Проверка <= поз. Проверка и unt. Проверка<= поз. Проверка и пересдача. Оформить заказ <= поз. Оформить заказ `. Но это привело к нулевым результатам. Это из-за слишком большого количества ands?
3. Вы пробовали запрос в моем ответе? Условие таково:
where lp.startdate <= r.checkout and lp.enddate >= r.checkin
ноstartdate
— это дата, когда у зараженного человека был положительный результат теста.4. Да, спасибо. Я пытался добавить несколько предложений, но у вас проще.