SQL-запрос - убедитесь, что данные в таблице охватывают год без наложения даты - PullRequest
0 голосов
/ 01 ноября 2009

У меня есть таблица tblRentalRates со следующими столбцами:

rate_id (int)    
rate_startdate (datetime) 
rate_enddate (datetime) 
weekday_rate (money) 
weekend_rate (money)

Я хочу достичь следующей цели:

  • Напишите запрос, который проверит содержимое таблицы и убедится, что за текущий год данные охватывают весь год без перекрытия. Это может быть ОДНА строка, с указанием начальной и конечной даты, или 366 строк (по одной на каждый день високосного года) или любая комбинация между ними.

У меня есть инструмент администратора, который позволяет администратору сайта контролировать цены, но я хотел бы показать какое-то сообщение об ошибке в верхней части, если они пропускают день из года, или совпадают даты и т. Д.

У кого-нибудь есть идеи?

1 Ответ

2 голосов
/ 01 ноября 2009

Перекрытия относительно просты (но вам может потребоваться беспокоиться о временах '<=' vs '<' и '> =' vs '>'):

SELECT x1.*, x2.*, "Overlap"
  FROM tblRentalRates AS x1, tblRentalRates AS x2
 WHERE x1.rate_startdate < x2.rate_enddate
   AND x1.rate_enddate   > x2.rate_startdate
   AND x1.rate_id < x2.date_id   -- Avoid repeats with x1, x2 interchanged

Определить полный охват значительно сложнее. Этому не помогает причудливость каждой СУБД, имеющей собственную (несовместимую) систему функций обработки даты или представления даты.

Я собираюсь начать с обозначения СУБД, с которым я больше всего знаком (IBM Informix Dynamic Server), и затем попытаюсь перевести его на MS SQL Server.

Нам нужно установить набор строк, которые перекрывают целевой год (строки, которые заканчиваются 1 января или позднее и начинаются 31 декабря или раньше):

SELECT * FROM tblRentalRates AS rr
 WHERE rr.rate_enddate   >= MDY( 1, 1,YEAR(TODAY))
   AND rr.rate_startdate <= MDY(12,31,YEAR(TODAY))

Далее нам нужно определить гранулярность значений даты. Название DATETIME предполагает, что значения могут хранить как компонент времени, так и компонент даты, но было бы намного проще, если бы мы могли предположить, что гранулярность составляет «1 день». В качестве альтернативы нам нужно знать, включена ли дата окончания в диапазон или нет - это диапазон открытый-закрытый или открытый-открытый (или закрытый-открытый, или закрытый-закрытый).

Теперь нам нужно найти пары записей в вышеприведенном списке, для которых конечная дата более ранней является более чем на один день раньше начальной даты более поздней и для которой нет строки между ними - они образуют пробелы в охват. Я предполагаю, что открыто-открытое представление с гранулярностью 1 день (поэтому строка с началом '2009-06-01' и концом '2009-06-01' представляет собой информацию за один день, а строка с начало / конец '2009-06-02' / '2009-06-03' содержит информацию за два дня и т. д., и между этими двумя строками не может быть никакой даты, не перекрывая нас).

SELECT r1.*, r2.*, "Gap"
  FROM (SELECT * FROM tblRentalRates AS rr
         WHERE rr.rate_enddate   >= MDY( 1, 1,YEAR(TODAY)) 
           AND rr.rate_startdate <= MDY(12,31,YEAR(TODAY))
       ) AS r1
       CROSS JOIN
       (SELECT * FROM tblRentalRates AS rr
         WHERE rr.rate_enddate   >= MDY( 1, 1,YEAR(TODAY)) 
           AND rr.rate_startdate <= MDY(12,31,YEAR(TODAY))
       ) AS r2
 WHERE r1.rate_enddate < r2.rate_startdate - INTERVAL(1) DAY TO DAY
   AND NOT EXISTS
          (SELECT * FROM tblRentalRates AS r3
            WHERE r3.rate_enddate   > r1.rate_enddate) 
              AND r3.rate_startdate < r2.rate_startdate)
          )

Учитывая данные этого примера:

INSERT INTO tblRentalRates VALUES(1, '2008-12-19', '2009-01-03', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(2, '2009-01-09', '2009-01-13', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(3, '2009-02-19', '2009-02-23', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(4, '2009-02-24', '2009-02-28', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(5, '2009-03-01', '2009-03-23', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(6, '2009-03-29', '2009-11-03', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(7, '2009-11-29', '2009-12-13', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(8, '2009-12-15', '2009-12-28', 1.23, 2.23);
INSERT INTO tblRentalRates VALUES(9, '2009-12-29', '2010-01-03', 1.23, 2.23);

Запрос дает:

1  2008-12-19  2009-01-03  1.23  2.23  2  2009-01-09  2009-01-13  1.23  2.23  Gap
2  2009-01-09  2009-01-13  1.23  2.23  3  2009-02-19  2009-02-23  1.23  2.23  Gap
5  2009-03-01  2009-03-23  1.23  2.23  6  2009-03-29  2009-11-03  1.23  2.23  Gap
6  2009-03-29  2009-11-03  1.23  2.23  7  2009-11-29  2009-12-13  1.23  2.23  Gap
7  2009-11-29  2009-12-13  1.23  2.23  8  2009-12-15  2009-12-28  1.23  2.23  Gap

Очевидно, это все еще не нотация MS SQL Server. Однако я собираюсь постулировать, что те, кто знаком с обозначениями, используемыми в MS SQL Server, могут адаптировать материал, описанный выше, чтобы он работал - так же как упражнение для читателя .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...