1

我想要做一个动态数量的一个开始/结束时间对传递给一个函数作为输入参数。该函数然后将使用列表而不是仅仅一个开始,并且在select语句中使用一个结束时间。Microsoft SQL Server 2005函数,通过开始和结束时间列表

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 
+0

问题是什么? – RedFilter 2010-04-14 16:04:09

回答

1

您需要一种方法来分割和处理TSQL中的字符串,有很多方法可以做到这一点。本文介绍了几乎每一个方法的优点和缺点:

"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog

你需要创建一个分裂的功能。这是一个分裂的功能如何使用:

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

I prefer the number table approach to split a string in TSQL但也有许多方法来拆分在SQL Server中的字符串,见前面的链接,这说明各的优点和缺点。

对于数字表的方法来工作,你需要做的这一次表的设置,这将创建一个包含从1到10000行的表Numbers

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') 

OUTPUT:

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

我可能会这样做的方式是使用OpenXML。我写了a blog article关于它,如果你想看看它如何工作的介绍视图。

相关问题