1

Je voudrais faire un nombre dynamique de paires de temps de début/fin passées à une fonction en tant que paramètre d'entrée. La fonction utiliserait alors la liste au lieu d'un seul début, et une heure de fin dans une instruction select.Microsoft SQL Server 2005 Fonction, transmission de la liste des heures de début et de fin

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

Quelle est la question? – RedFilter

Répondre

1

Vous avez besoin d'un moyen de diviser et de traiter la chaîne dans TSQL, il y a plusieurs façons de le faire. Cet article porte sur les avantages et les inconvénients de chaque méthode à peu près:

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

Vous devez créer une fonction split. Voici comment une fonction split peut être utilisé:

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 mais il existe de nombreuses façons de diviser les chaînes dans SQL Server, voir le lien précédent, ce qui explique les avantages et les inconvénients de chacun.

Pour la méthode de table de nombres au travail, vous devez faire une configuration de table de temps, ce qui va créer une table Numbers qui contient des lignes de 1 à 10 000:

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) 

Une fois la table des numéros est mis en place , créer cette fonction split:

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 

tester le fractionnement:

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

SORTIE:

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) 

Notez que la valeur manquante dans la chaîne d'entrée:

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

a créé une valeur de chaîne vide dans le jeu de résultats de la fonction, que le CONVERT a changé 1900-01-01 00: 00: 00.000, vous pouvez utiliser une instruction CASE pour les gérer d'une manière différente.

puis créez votre fonction. Ceci est basé sur le code int la question. Je ne suis pas sûr de ce qu'il fait, car il renvoie un int, qui est toujours zéro, et ne fait rien avec la requête. Mais à partir de la fonction OPs, donc il doit être une forme simple de quelque chose qu'ils font:

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

La façon dont je le ferais probablement est d'utiliser OpenXML. J'ai écrit a blog article à ce sujet si vous voulez voir une intro sur la façon dont cela fonctionne.