Функция Microsoft SQL Server 2005, список времени начала и окончания - PullRequest
1 голос
/ 14 апреля 2010

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

CREATE FUNCTION [dbo].[GetData]
(
    @StartTime datetime,
    @EndTime datetime
)
RETURNS int
AS
BEGIN
    SELECT @EndTime = CASE WHEN @EndTime > CURRENT_TIMESTAMP THEN CURRENT_TIMESTAMP ELSE @EndTime END

    DECLARE @TempStates TABLE
        (StartTime datetime NOT NULL
        , EndTime datetime NOT NULL
        , StateIdentity int NOT NULL
        )

    INSERT INTO @TempStates
    SELECT StartTime
        , EndTime
        , StateIdentity
    FROM State
    WHERE StartTime <= @EndTime AND EndTime >= @StartTime

    RETURN 0
END

Ответы [ 3 ]

1 голос
/ 14 апреля 2010

Прочитайте превосходную (и длинную!) Статью Эрланда Соммарского о Массивы и списки в SQL Server 2005 и более поздних версиях - когда TVP не обрезают его . Могу поспорить, что это более чем покрыть ваш вопрос (ы): -)

1 голос
/ 14 апреля 2010

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

«Массивы и списки в SQL Server 2005 и более поздних версиях, когда параметры табличных значений не обрезают его» Эрланда Соммарского

Вам необходимо создать функцию разделения. Вот как можно использовать функцию разделения:

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value

Я предпочитаю подход с использованием таблиц чисел для разделения строки в TSQL , но существует множество способов разделения строк в SQL Server, см. Предыдущую ссылку, которая объясняет за и против каждого из них.

Чтобы метод таблицы чисел сработал, необходимо выполнить настройку единой таблицы, которая создаст таблицу Numbers, содержащую строки от 1 до 10000:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

После настройки таблицы Numbers создайте функцию разделения:

CREATE FUNCTION [dbo].[FN_ListToTableRows]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(
    ----------------
    --SINGLE QUERY-- --this will return empty rows, and row numbers
    ----------------
    SELECT
        ROW_NUMBER() OVER(ORDER BY number) AS RowNumber
            ,LTRIM(RTRIM(SUBSTRING(ListValue, number+1, CHARINDEX(@SplitOn, ListValue, number+1)-number - 1))) AS ListValue
        FROM (
                 SELECT @SplitOn + @List + @SplitOn AS ListValue
             ) AS InnerQuery
            INNER JOIN Numbers n ON n.Number < LEN(InnerQuery.ListValue)
        WHERE SUBSTRING(ListValue, number, 1) = @SplitOn
);
GO 

проверить разбиение:

SELECT
    RowNumber, CONVERT(datetime,ListValue) AS ListValue 
    FROM  dbo.FN_ListToTableRows(',','1/1/2010 12:45am,,2/2/2010 1:23pm,3/3/2010 12:45')

ВЫВОД:

RowNumber            ListValue
-------------------- -----------------------
1                    2010-01-01 00:45:00.000
2                    1900-01-01 00:00:00.000
3                    2010-02-02 13:23:00.000
4                    2010-03-03 12:45:00.000

(4 row(s) affected)

обратите внимание, что пропущенное значение во входной строке:

'1/1/2010 12:45am,,2/2/2010 1:23pm,3/3/2010 12:45'
                 ^^

создал пустое строковое значение в наборе результатов функции, который CONVERT изменил на 1900-01-01 00: 00: 00.000, вы можете использовать оператор CASE для обработки их другим способом.

затем создайте свою функцию. Это основано на коде в вопросе. Я не уверен, что он делает, потому что он возвращает int, который всегда равен нулю, и ничего не делает с запросом. Но это из функции OP, поэтому это должна быть простая форма того, что они делают:

CREATE FUNCTION [dbo].[GetData]
(
    @StartTime varchar(8000),  --CSV string of dates: '1/1/2010 12:45am,,2/2/2010 1:23pm,3/3/2010 12:45'
    @EndTime varchar(8000)     --CSV string of dates: '1/1/2010 12:45am,,2/2/2010 1:23pm,3/3/2010 12:45'
)
RETURNS int
AS
BEGIN
    DECLARE @TempStates TABLE
        (StartTime datetime NOT NULL
        , EndTime datetime NOT NULL
        , StateIdentity int NOT NULL
        )

    INSERT INTO @TempStates
    SELECT s.StartTime
        , s.EndTime
        , s.StateIdentity
    FROM State s
        CROSS JOIN (SELECT
                        a1.RowNumber
                            ,CONVERT(datetime,a1.ListValue) AS StartTime
                            ,CASE
                                WHEN a2.ListValue > GETDATE() THEN GETDATE()
                                ELSE CONVERT(datetime,a2.ListValue)
                            END AS EndTime
                        FROM dbo.FN_ListToTableRows(',',@StartTime)          a1
                            INNER JOIN dbo.FN_ListToTableRows(',',@EndTime)  a2 ON a1.RowNumber=a2.RowNumber
                   ) dt
    WHERE s.StartTime <= dt.EndTime AND s.EndTime >= dt.StartTime
    RETURN 0
END
GO
0 голосов
/ 14 апреля 2010

Вероятно, я бы использовал OpenXML. Я написал статью в блоге об этом, если вы хотите увидеть представление о том, как это работает.

...