SQL Получить ближайшую дату в обоих направлениях

Я пытаюсь найти эффективный способ запроса таблицы, мне нужно вывести строку, ближайшую к заданной дате, в обоих направлениях, заметьте.

У меня есть решение на ближайший день в будущем

SELECT  top 1 id
   FROM [dbo].[Shipments] 
   WHERE EstimatedArrivalDate < @date
   AND Complete = 0 
   AND (RegNoTrailer = @regNo OR RegNoTruck = @regNo) 
   ORDER BY EstimatedArrivalDate DESC

Это ближайшая дата в будущем, но мне также нужно проверить прошлые даты.

А как насчет добавления UNION ALL SELECT TOP 1 .... > @date ... ORDER BY EstimatedArrivalDate?

Pham X. Bach 02.05.2018 11:37
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
3
1
170
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Это сработает?

   SELECT  top 1 id
   FROM [dbo].[Shipments] 
   WHERE EstimatedArrivalDate > @date --change to >
   AND Complete = 0 
   AND (RegNoTrailer = @regNo OR RegNoTruck = @regNo) 
   ORDER BY EstimatedArrivalDate ASC --change to ASC

Или оба вместе, используя UNION

SELECT  top 1 id
   FROM [dbo].[Shipments] 
   WHERE EstimatedArrivalDate < @date
   AND Complete = 0 
   AND (RegNoTrailer = @regNo OR RegNoTruck = @regNo) 
   ORDER BY EstimatedArrivalDate DESC
UNION
   SELECT  top 1 id
   FROM [dbo].[Shipments] 
   WHERE EstimatedArrivalDate > @date --change to >
   AND Complete = 0 
   AND (RegNoTrailer = @regNo OR RegNoTruck = @regNo) 
   ORDER BY EstimatedArrivalDate ASC --change to ASC

Вы можете использовать Datediff и Abs в комбинации.

select abs(DATEDIFF(second,<dateColumn>,<dateParameter>)) result,<otherColumns> 
from <tableName> order by  result

Первая запись будет самой близкой.

Как я спросил Рафаэля, не будет ли это неэффективным для больших таблиц?

Jonas Olesen 02.05.2018 11:52

@JonasOlesen Конечно, производительность снизится, потому что вы будете сканировать таблицу все время (если в предложении where нет индекса по другим столбцам). Альтернативный вариант - использовать объединения, как и в другом ответе, но это потребует выполнения нескольких запросов. Вы можете сравнить их и оценить сами. Да и раньше Datediff вела себя плохо. Не уверен, что это изменилось \.

danish 02.05.2018 12:07

Попробуйте использовать функцию РАЗНДАТ, чтобы найти разницу между двумя датами. Вам также потребуется добавить функцию ABS (), чтобы обслуживать как прошлые, так и будущие даты.

SELECT  top 1 id
   FROM [dbo].[Shipments] 
   WHERE Complete = 0 
   AND (RegNoTrailer = @regNo OR RegNoTruck = @regNo) 
   ORDER BY ABS(DATEDIFF(D,EstimatedArrivalDate,@date)) ASC

Насколько эффективным было бы запускать dateiff на большом столе?

Jonas Olesen 02.05.2018 11:48

Используйте DATEDIFF () и ABS (), чтобы получить ближайшую разницу дат

SELECT  top 1 id
   FROM [dbo].[Shipments] 
   WHERE Complete = 0 
   AND (RegNoTrailer = @regNo OR RegNoTruck = @regNo) 
   ORDER BY ABS(DATEDIFF(SECOND, @date, EstimatedArrivalDate)) 
Ответ принят как подходящий

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

SELECT TOP 1 id
FROM ((SELECT TOP 1 id, EstimatedArrivalDate
       FROM [dbo].[Shipments] 
       WHERE EstimatedArrivalDate < @date AND
             Complete = 0 
             RegNoTrailer = @regNo
       ORDER BY EstimatedArrivalDate DESC
      ) UNION ALL
      (SELECT TOP 1 id, EstimatedArrivalDate
       FROM [dbo].[Shipments] 
       WHERE EstimatedArrivalDate < @date AND
             Complete = 0 
             RegNoTruck = @regNo 
       ORDER BY EstimatedArrivalDate DESC
      ) UNION ALL
      (SELECT TOP 1 id, EstimatedArrivalDate
       FROM [dbo].[Shipments] 
       WHERE EstimatedArrivalDate > @date AND
             Complete = 0 
             RegNoTrailer = @regNo
       ORDER BY EstimatedArrivalDate ASC
      ) UNION ALL
      (SELECT TOP 1 id, EstimatedArrivalDate
       FROM [dbo].[Shipments] 
       WHERE EstimatedArrivalDate > @date AND
             Complete = 0 
             RegNoTruck = @regNo 
       ORDER BY EstimatedArrivalDate ASC
      )
     )
ORDER BY ABS(DATEDIFF(second, EstimatedArrivalDate, @Date));

Для этого запроса вам нужны два индекса: Shipments(RegNoTruck, Complete, EstimatedArrivalDate) и Shipments(RegNoTrailer, Complete, EstimatedArrivalDate).

Разделив условия OR на два отдельных подзапроса, каждый подзапрос может использовать свой индекс.

Спасибо, это сработало отлично после нескольких исправлений синтаксиса :) спасибо

Jonas Olesen 02.05.2018 14:12

О.о. Интересно, так ли это неэффективно, как кажется, или же подготовка сводит это к чему-то более связному. Что-то мне подсказывает, что SQL не предназначен для использования.

Dmitry 03.05.2018 06:34

@ Дмитрий. . . Такая структура запроса позволяет использовать индексы для сокращения набора данных для четырех случаев, подразумеваемых исходным запросом. Есть более лаконичные способы выразить логику; эта версия позволяет оптимизатору легко использовать доступные индексы эффективно.

Gordon Linoff 04.05.2018 05:27

Другие вопросы по теме