Диапазоны дат в T / SQL - PullRequest
       64

Диапазоны дат в T / SQL

2 голосов
/ 13 октября 2008

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

У меня есть 3 типа отчетов, ежегодных, ежемесячных и ежедневных.

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

Так, например, если я, как и для всех дневных диапазонов между '2006-01-01 11:10:00' и '2006-01-05 08:00:00', я ожидаю следующих результатов.

select * 
from dbo.fnGetDateRanges('d', '2006-01-01 11:10:00', '2006-01-05 08:00:00')  

2006-01-01 11:10:00.000,    2006-01-02 00:00:00.000
2006-01-02 00:00:00.000,    2006-01-03 00:00:00.000
2006-01-03 00:00:00.000,    2006-01-04 00:00:00.000
2006-01-04 00:00:00.000,    2006-01-05 00:00:00.000
2006-01-05 00:00:00.000,    2006-01-05 08:00:00.000

Я бы ожидал, что за годовой диапазон значений «2006-01-01 11:10:00» - «2009-05-05 08:00:00».

select * 
from dbo.fnGetDateRanges('y', '2006-01-01 11:10:00', '2009-05-05 08:00:00') 

2006-01-01 11:10:00.000,    2007-01-01 00:00:00.000
2007-01-01 00:00:00.000,    2008-01-01 00:00:00.000
2008-01-01 00:00:00.000,    2009-01-01 00:00:00.000
2009-01-01 00:00:00.000,    2009-05-05 08:00:00.000

Как бы я реализовал эту функцию?

Ответы [ 4 ]

3 голосов
/ 13 октября 2008

Полезна таблица статических чисел, один столбец, скажем 8000 строк ОТ 0 ДО 7999

(не проверено)

DECLARE @Start smalldatetime, @End smalldatetime, @Diff int

SELECT @Start = '2006-01-01 11:10:00', @End = '2009-05-05 08:00:00', @diff = DATEDIFF(year,@start,@end)

SELECT
   DATEADD(year,N.Number,@Start)
FROM
   dbo.Number N
WHERE
   N.Number <= @diff
2 голосов
/ 13 октября 2008

Здесь довольно много трюков, надеюсь, вы найдете это полезным

create function dbo.fnGetDateRanges
(
    @type char(1),
    @start datetime,
    @finish datetime
)
returns @ranges table(start datetime, finish datetime)
as 
begin

    declare @from datetime 
    declare @to datetime 
    set @from = @start 

    if @type = 'd'
    begin 
        set @to = dateadd(day, 1,
                convert
                (   datetime,
                    cast(DatePart(d,@start) as varchar) + '/' + cast(DatePart(m,@start) as varchar) + '/' + cast(DatePart(yy,@start) as varchar),
                    103
                )
            )
    end

    if @type = 'm'
    begin
        set @to = dateadd(month, 1, 
            convert
            (   
                datetime,
                '1/' + cast(DatePart(m,@start) as varchar) + '/' + cast(DatePart(yy,@start) as varchar),
                103
            )
        )
    end 

    if @type = 'y'
    begin
        set @to = dateadd(year, 1, 
            convert
            (   
                datetime,
                '1/1/' + cast(DatePart(yy,@start) as varchar),
                103
            )
        )
    end 

    while @to < @finish
    begin 
        insert @ranges values (@from, @to)
        set @from = @to 
        if @type = 'd'
            set @to = dateadd(day, 1, @to)
        if @type = 'm'
            set @to = dateadd(month, 1, @to)
        if @type = 'y'
            set @to = dateadd(year, 1, @to)
    end

    insert @ranges values (@from, @finish)

    return 
end
1 голос
/ 13 октября 2008

С точки зрения производительности вы не захотите использовать функцию для генерации диапазонов дат. Для каждой оценки в запросе (@myDate > dbo.MyFunc()) функция должна будет выполняться полностью. Лучше всего построить таблицу статических чисел.

Теперь с таблицами чисел ....

Это быстрый способ создать таблицу целых чисел. (Реквизит Джеффу Модену для трюка с личностью)

 SELECT TOP 1000000
        IDENTITY(INT,1,1) as N
   INTO dbo.NumbersTable
   FROM Master.dbo.SysColumns 
        Master.dbo.SysColumns 

Менее 2 секунд для заполнения 1000000 чисел в таблице.

Теперь, чтобы решить вашу проблему, вам нужно использовать это для построения таблицы дат. В приведенном ниже примере будет создана таблица с нулевым часом (12:00) для каждого дня, начиная с @ startDate

DECLARE @DaysFromStart int
DECLARE @StartDate datetime
SET @StartDate = '10/01/2008'

SET @ DaysFromStart  = (SELECT (DATEDIFF(dd,@StartDate,GETDATE()) + 1))

CREATE TABLE [dbo].[TableOfDates](
    [fld_date] [datetime] NOT NULL,
 CONSTRAINT [PK_TableOfDates] PRIMARY KEY CLUSTERED 
(
    [fld_date] ASC
)WITH FILLFACTOR = 99 ON [PRIMARY]
) ON [PRIMARY]


INSERT INTO
     dbo.TableOfDates
SELECT 
      DATEADD(dd,nums.n - @DaysFromStart ,CAST(FLOOR(CAST(GETDATE() as FLOAT)) as DateTime)) as FLD_Date
FROM #NumbersTable nums

SELECT MIN(FLD_Date) FROM dbo.TableOfDates
SELECT MAX(FLD_Date) FROM dbo.TableOfDates

Теперь с различными комбинациями DATEADD / DIFF вы сможете создавать статические таблицы, которые вам понадобятся для эффективного выполнения множества запросов в диапазоне дат.

1 голос
/ 13 октября 2008

Если вы предпочитаете решение на основе множеств, используйте тактику, подобную показанной в следующей ссылке, чтобы получить диапазон числовых значений от x до y. Затем просто присоединитесь к нему с помощью DATEADD () и ваших собственных пользовательских пределов, чтобы создать диапазоны дней, месяцев, кварталов, лет или чего-либо еще. Я считаю полезным иметь этот диапазон запроса в качестве представления.

Создание диапазонов в SQL

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