Строгое-Brocot Дерево вызывает довольно естественный способ приблизить вещественные числа частями с простыми знаменателями.
Почему все так категорически против использования стола для такого рода вещей? Таблица чисел или календарная таблица занимает так мало места и, вероятно, находится в памяти, если на нее в любом случае ссылаются. Вы также можете легко получить таблицу чисел на лету, используя ROW_NUMBER (). Использование таблицы чисел может помочь в понимании запроса. Но вот не такой простой пример, трюк, который я недавно перенял у Пламена Ратчева, надеюсь, он поможет.
DECLARE @wtns TABLE
(
WTN CHAR(12),
[Date] SMALLDATETIME
);
INSERT @wtns(WTN, [Date])
SELECT '555-111-1212','2009-01-01'
UNION ALL SELECT '555-111-1212','2009-01-02'
UNION ALL SELECT '555-111-1212','2009-01-03'
UNION ALL SELECT '555-111-1212','2009-01-15'
UNION ALL SELECT '555-111-1212','2009-01-16'
UNION ALL SELECT '212-999-5555','2009-01-01'
UNION ALL SELECT '212-999-5555','2009-01-10'
UNION ALL SELECT '212-999-5555','2009-01-11';
WITH x AS
(
SELECT
[Date],
wtn,
part = DATEDIFF(DAY, 0, [Date])
+ DENSE_RANK() OVER
(
PARTITION BY wtn
ORDER BY [Date] DESC
)
FROM @wtns
)
SELECT
WTN,
MinDate = MIN([Date]),
MaxDate = MAX([Date])
FROM
x
GROUP BY
part,
WTN
ORDER BY
WTN DESC,
MaxDate;
Ваша проблема связана с ТИПАМИ ИНТЕРВАЛОВ и вещью под названием ПАКЕТНАЯ НОРМАЛЬНАЯ ФОРМА отношения.
Эти вопросы подробно обсуждаются в разделе " Временные данные и реляционная модель ».
Не ожидайте, что какая-либо система SQL действительно поможет вам с такими проблемами.
Несмотря на некоторые учебные системы, единственная СУБД, которая предлагает достойную поддержку для таких проблем, и о которой я знаю , мой собственный. Нет ссылки, потому что я не хочу делать здесь слишком много "затыкания".
Вы можете сделать это с помощью GROUP BY
, определив границы:
WITH Boundaries
AS (
SELECT m.WTN
,m.Date
,CASE WHEN p.Date IS NULL THEN 1
ELSE 0
END AS IsStart
,CASE WHEN n.Date IS NULL THEN 1
ELSE 0
END AS IsEnd
FROM so1590166 AS m
LEFT JOIN so1590166 AS p
ON p.WTN = m.WTN
AND p.Date = DATEADD(d, -1, m.Date)
LEFT JOIN so1590166 AS n
ON n.WTN = m.WTN
AND n.Date = DATEADD(d, 1, m.Date)
WHERE p.Date IS NULL
OR n.Date IS NULL
)
SELECT l.WTN
,l.Date AS MinDate
,MIN(r.Date) AS MaxDate
FROM Boundaries l
INNER JOIN Boundaries r
ON r.WTN = l.WTN
AND r.Date >= l.Date
AND l.IsStart = 1
AND r.IsEnd = 1
GROUP BY l.WTN
,l.Date