SQL-запрос для возврата набора, который не попадает между двумя датами

#sql #oracle

Вопрос:

У меня есть таблица «заемщик», которая соединена с таблицей «кредит». Я пытаюсь вернуть всех заемщиков, у которых НЕТ кредита в определенный день. Это код, который у меня есть до сих пор, и я немного наткнулся на стену, так как, похоже, это правильный способ решения этой проблемы, по общему признанию, я совсем новичок в SQL и, возможно, я далек, но любая помощь была бы очень признательна. Я возвращаю всех заемщиков, используя этот код, а не 60 или около того, как следовало бы. Спасибо Тебе!

 SELECT DISTINCT b.cardno, b.fname ||' '|| b.lname AS "BORROWER NAME"
FROM borrower b
JOIN loan l ON b.cardno = l.cardno
WHERE '01/SEP/05' NOT BETWEEN l.dateout AND l.datein
ORDER BY b.cardno;
 

Используя ссылку, предоставленную на некоторую информацию, мне удалось немного снизить свою доходность, но все равно вернуть слишком много заемщиков:

 SELECT DISTINCT b.cardno, b.fname ||' '|| b.lname AS "BORROWER NAME"
FROM borrower b
JOIN loan l ON b.cardno = l.cardno
where l.dateout < '01/SEP/05'
and l.datein > '01/SEP/05'
ORDER BY b.cardno;
 

Комментарии:

1. Можете ли вы проверить, действует ли ваше положение «ГДЕ»? Что делать, если вы удалите предложение «ГДЕ»? Правильный ли формат даты?

Ответ №1:

Ваш запрос будет искать все кредиты в любой другой день; поэтому он исключит только тех, у кого была книга только в этот день. Если вы изменили первую строку на:

 SELECT b.cardno, b.fname ||' '|| b.lname AS "BORROWER NAME", l.dateout, l.datein
 

вы бы увидели все кредиты не в тот день; так что все (или почти все) заемщики, но не все кредиты.

Но «01/СЕНТЯБРЬ/05» — это не дата; вы полагаетесь на неявное преобразование с использованием настроек сеанса, что не очень хорошая идея, и вы можете получить значения, которых не ожидаете, что может означать, что сопоставление дат в любом случае работает не так, как вы ожидаете. Его лучше использовать to_date() с подходящей маской формата и предпочтительно с 4-значными годами; или буквой даты, например DATE '2005-09-01' .

Вы могли бы использовать not exists , с чем-то вроде:

 SELECT b.cardno, b.fname ||' '|| b.lname AS "BORROWER NAME"
FROM borrower b
WHERE NOT EXISTS (
  SELECT null
  FROM loan l
  WHERE l.cardno = b.cardno
  AND DATE '2005-09-01' BETWEEN l.dateout AND l.datein
)
ORDER BY b.cardno;
 

Даже там совпадение даты может не совсем сработать, если у вашей даты входа/выхода есть фактическое время, а не полночь. Любые кредиты, выданные после полуночи в вашу целевую дату, будут исключены. Так что вместо этого вы могли бы сделать это:

   AND l.dateout < DATE '2005-09-01'   1
  AND l_datein >= DATE '2005-09-01'
 

Комментарии:

1. Большое Вам спасибо, очень информативно. Да, я новичок во всем этом, как вы можете сказать, и много борюсь с датами, еще раз спасибо!