Получение идентификаторов, созданных до определенной даты и на которые не ссылаются после этой даты

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

Я пытаюсь получить список идентификаторов обратно из запроса, который зависит от значения в столбце ссылки на идентификатор и столбце даты в другой строке.

В принципе, я пытаюсь получить ID для записей, которые были созданы до указанной даты ( Created столбец), если на эту запись не ссылается другая (по RefID столбцу), созданная после этой даты.

(Я планирую использовать это в sproc в какой-то момент, но пока просто использую переменную)

Очень простой пример таблицы ниже. Для простоты исключены несвязанные столбцы.

  -------- --------- --------------- 
|   ID   |  RefID  |    Created    |
 -------- --------- --------------- 
|  123   |  NULL   |  2016-10-18   |
|  456   |  123    |  2016-10-20   |
|  789   |  NULL   |  2016-10-18   |
|  111   |  789    |  2016-10-18   |
 -------- --------- --------------- 
  

Итак, в моем примере таблицы выше, если бы я указал 2016-10-19, я бы вернул идентификаторы 789 и 111. Я бы не получил 123, потому что, хотя он был создан до 2016-10-18, на него ссылается 456, чего не было (поэтому я бы также не вернул 456).

Я перебирал варианты присоединения, но SQL определенно не моя сильная сторона, поэтому я чувствую, что бегаю по кругу и гоняюсь за неправильным решением при этом!
Пока у меня есть это, что, я думаю, дает мне правильный список идентификаторов, на которые ссылаются после определенной даты. Я не совсем уверен, как исключить этот список из моего основного запроса…не говоря уже о том, каким был бы соответствующий основной запрос.

 DECLARE @myDate datetime
SET @myDate = '2016-10-19'

SELECT t1.id
FROM MyDB.dbo.[myTable] AS t1
JOIN MyDB.dbo.[myTable] AS t2
ON t1.id = t2.ref_id
WHERE t1.id = t2.ref_id AND t2.created > @myDate
  

Ответ №1:

Вы можете получить это с помощью not exists с условием проверить, есть ли в указанном идентификаторе строка после указанной даты.

 SELECT id
FROM MyDB.dbo.[myTable] t1
WHERE NOT EXISTS (SELECT 1 FROM MyDB.dbo.[myTable] 
                  WHERE t1.id = ref_id 
                  AND created > @myDate) 
AND created < @myDate
  

Sample Demo

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

1. Смогу ли я расширить это, чтобы рассмотреть 2 разные даты? Скажите, если бы я хотел, чтобы идентификаторы были до даты [X], и если на них были ссылки, ссылка должна быть создана до даты [Y]?

2. конечно.. вы можете это сделать.

3. Извините, просто удостоверяюсь, прежде чем начать слепо вводить значения для тестирования. Будет ли это просто переменной using [X] для @myDate в строке 6 и новой переменной [Y] в @myDate строке 5?

4. да, внутреннее условие проверяет, имеет ли какой-либо из ref_id более позднюю дату, а внешним условием является идентификатор, предшествующий заданной дате. вы можете соответствующим образом изменить его.

Ответ №2:

ОТРЕДАКТИРОВАНО: я понял (после принятого решения и повторного прочтения исходного запроса), что вы просили исключить записи t1, которые имели связанные записи t2 после создания t1, но после даты «mydate». Я соответствующим образом изменил свои запросы ниже (однако я предполагаю, что запрос vkp также работает лучше, чем мой пересмотренный ответ).

Я начал с вашего запроса и пришел к этому предложению:

  SELECT t1.id
   FROM MyDB.dbo.[myTable] AS t1
   LEFT JOIN MyDB.dbo.[myTable] AS t2
     ON t1.id = t2.ref_id and t2.created > @mydate
  WHERE t2.id is null AND t1.created < @mydate
  

Итак, для таблицы t1 (до указанной даты) я объединяю (если они существуют) все обращения с датой создания, большей, чем «mydate», а ref_id равен t1.id.
После этого я говорю, что мне не нужны строки, в которых я нашел совпадение (это использование t2.id is null ), таким образом, оставляя меня с желаемым набором результатов.

Что касается последнего добавления к запросу (имеющего другую «начальную дату» для ссылки в записях для исключения), вам просто нужно будет изменить запрос следующим образом:

  SELECT t1.id
   FROM MyDB.dbo.[myTable] AS t1
   LEFT JOIN MyDB.dbo.[myTable] AS t2
     ON t1.id = t2.ref_id 
     and t2.created > @exclusionstartdate
  WHERE t2.id is null AND t1.created < @mydate