in

UGISS Community

Il sito della community dello User Group Italiano di SQL Server

Query su date con intervalli temporali

Last post 08-06-2008 15.16 by peperomero. 2 replies.
Page 1 of 1 (3 items)
Sort Posts: Previous Next
  • 08-06-2008 12.36

    • peperomero
    • Top 150 Contributor
      Male
    • Joined on 05-20-2008
    • Roma
    • Posts 2
    • Points 25

    Query su date con intervalli temporali

    Salve a tutti, mi sto imbattendo con un problema che non riesco proprio a risolvere.

    Ho una tabella che memorizza i dati di una centralina metereologica ogni minuto. Mi è stato chiesto di poter interrogare tale tabella utilizzando diversi filtri.

    Ho relaizzato una super procedura t-sql che tira fuori le informazioni richieste, ma non riesco ad applicarci uno step temporale. Chiarisco subito con un esempio.

    Creo una tabella del genere:

    CREATE TABLE dbo.myData(
    DataID int NOT NULL IDENTITY PRIMARY KEY,
    Date datetime NOT NULL
    );

    INSERT dbo.myData VALUES('20070601 10:00:00');
    INSERT dbo.myData VALUES('20070601 10:01:00');
    INSERT dbo.myData VALUES('20070601 10:02:00');
    INSERT dbo.myData VALUES('20070601 10:03:00');
    INSERT dbo.myData VALUES('20070601 10:04:00');
    INSERT dbo.myData VALUES('20070601 10:05:00');
    INSERT dbo.myData VALUES('20070601 10:06:00');
    INSERT dbo.myData VALUES('20070601 10:07:00');
    INSERT dbo.myData VALUES('20070601 10:08:00');
    INSERT dbo.myData VALUES('20070601 10:09:00');
    INSERT dbo.myData VALUES('20070601 10:10:00');
    INSERT dbo.myData VALUES('20070601 10:11:00');
    INSERT dbo.myData VALUES('20070601 10:12:00');
    INSERT dbo.myData VALUES('20070601 10:13:00');
    INSERT dbo.myData VALUES('20070601 10:14:00');
    INSERT dbo.myData VALUES('20070601 10:15:00');
    INSERT dbo.myData VALUES('20070601 10:16:00');
    INSERT dbo.myData VALUES('20070601 10:17:00');
    INSERT dbo.myData VALUES('20070602 10:00:00');
    INSERT dbo.myData VALUES('20070602 10:01:00');
    INSERT dbo.myData VALUES('20070602 10:02:00');
    INSERT dbo.myData VALUES('20070602 10:03:00');
    INSERT dbo.myData VALUES('20070602 10:04:00');
    INSERT dbo.myData VALUES('20070602 10:05:00');
    INSERT dbo.myData VALUES('20070602 10:06:00');
    INSERT dbo.myData VALUES('20070602 10:07:00');
    INSERT dbo.myData VALUES('20070602 10:08:00');
    INSERT dbo.myData VALUES('20070602 10:09:00');
    INSERT dbo.myData VALUES('20070602 10:10:00');
    INSERT dbo.myData VALUES('20070602 10:11:00');
    INSERT dbo.myData VALUES('20070602 10:12:00');
    INSERT dbo.myData VALUES('20070602 10:13:00');
    INSERT dbo.myData VALUES('20070602 10:14:00');
    INSERT dbo.myData VALUES('20070602 10:15:00');
    INSERT dbo.myData VALUES('20070602 10:16:00');
    INSERT dbo.myData VALUES('20070602 10:17:00');

    Allora supponiamo di voler prendere tutti irecord che vanno dal 1-6-07 al 2-6-07 dalle 10:01 alle 10:13 non ci sono poblemi, utilizzo il
    CAST(CONVERT(varchar, Date, 114) AS datetime) BETWEEN '10:01' AND '10:13:59.997' nella query di selezione

    Se io pero voglio gli stessi dati ma utilizzando uno "step" del tipo come sopra ma con step di 2 minuti, dovrei ottenere:

    2007-06-01 10:01:00.000
    2007-06-01 10:03:00.000
    2007-06-01 10:05:00.000
    2007-06-01 10:07:00.000
    2007-06-01 10:09:00.000
    2007-06-01 10:11:00.000
    2007-06-01 10:13:00.000
    2007-06-02 10:01:00.000
    2007-06-02 10:03:00.000
    2007-06-02 10:05:00.000
    2007-06-02 10:07:00.000
    2007-06-02 10:09:00.000
    2007-06-02 10:11:00.000
    2007-06-02 10:13:00.000

    Potrei voler cambiare step e mettere ad esempio 4 minuti e quindi ottenere:
    2007-06-01 10:01:00.000
    2007-06-01 10:05:00.000
    2007-06-01 10:09:00.000
    2007-06-01 10:07:00.000
    2007-06-01 10:09:00.000
    2007-06-01 10:13:00.000
    2007-06-02 10:01:00.000
    2007-06-02 10:05:00.000
    2007-06-02 10:09:00.000
    2007-06-02 10:07:00.000
    2007-06-02 10:09:00.000
    2007-06-02 10:13:00.000

    Oppure 5 minuti:
    2007-06-01 10:01:00.000
    2007-06-01 10:06:00.000
    2007-06-01 10:11:00.000
    2007-06-02 10:01:00.000
    2007-06-02 10:06:00.000
    2007-06-02 10:11:00.000

    Pensavo di aver risolto dividendo l'operazione tra una procedura in t-sql e un metodo relaizzato in vb incluso nella web application ma la procedura ha avuto scarso successo sia dal punto di vista delle performance sia perche i dati che prendo dalla query sono paginati per cui mi risulta quasi impossibile capire quale sarà il primo record della pagina x da programma. In un post che avevo aperto qui http://www.dotnethell.it/Forum/messages.aspx?ThreadID=18065 mi è stata suggerita una funzione ricorsiva che devo dire funziona perfettamente, ma quando i dati rischiesti cominciano ad essere tanti allora mi dice che non puo effettuare piu di 100 ricorsioni nidificate. Dato che i dati che devo poter estrarre possono riguardare anche lunghi periodi temporali ho dovuto scartare questa soluzione.

    Questa è la query che ho realizzato che mi riesce a prendere tutti i dati che voglio paginati senza includere il famoso step che dovrei implementare

    SET @PAGEINDEX = @PAGEINDEX -1;

    SET @RowStart = @PAGESIZE * @PAGEINDEX + 1;

    SET @RowEnd = @RowStart + @PAGESIZE - 1 ;

    SELECT
    * INTO #TBL FROM dbo.fn_UTIL_Split(@IDRADIOMETRI,'#');

    With InfoRad AS

    (

    SELECT NomeSede AS Sede, dbo.DammiData(Giorno) AS Giorno, dbo.DammiOrario(Giorno) AS Ora

    , UvbMedia, UvaMedia, RsolMedia, UrMedia,

    ROW_NUMBER() OVER (order by Nomesede, Giorno) as RowNumber

    FROM SediRadiometro INNER JOIN QuickDat_DatFile ON ID=IDRadiometro

    INNER JOIN #TBL AS R ON QuickDat_DatFile.IDRadiometro=R.Value

    AND Giorno BETWEEN dbo.DammiData(@DATADA) AND dbo.DammiData(DATEADD(dd, 1, @DATAAL))

    AND CAST(CONVERT(varchar, Giorno, 114) AS datetime) BETWEEN @ORADAL AND @ORAAL

    )

     

    SELECT * FROM InfoRad WHERE RowNumber >= @RowStart and RowNumber <= @RowEnd;

     

    SET @RECORDS=0;

     


    Cosa posso fare?

    Grazie 1000,

    Luca.

    • Post Points: 20
  • 08-06-2008 13.49 In reply to

    • lbenaglia
    • Top 25 Contributor
      Male
    • Joined on 05-14-2007
    • Vimercate (Milano)
    • Posts 88
    • Points 1.335

    Re: Query su date con intervalli temporali

    peperomero:

     In un post che avevo aperto qui http://www.dotnethell.it/Forum/messages.aspx?ThreadID=18065 mi è stata suggerita una funzione ricorsiva che devo dire funziona perfettamente, ma quando i dati rischiesti cominciano ad essere tanti allora mi dice che non puo effettuare piu di 100 ricorsioni nidificate. Dato che i dati che devo poter estrarre possono riguardare anche lunghi periodi temporali ho dovuto scartare questa soluzione.

    Ciao Luca,

    Mi sembra di conoscere la persona che ti ha suggerito l'utilizzo delle CTE Cool

    E' vero, di default le CTE ricorsive permettono al più 100 ricorsioni, ma nulla ti vieta di specificare l'hint MAXRECURSION che permette di raggiungere 32767 ricorsioni.

    I Books Online riportano:

    MAXRECURSION number
    Specifies the maximum number of recursions allowed for this query. number is a nonnegative integer between 0 and 32767. When 0 is specified, no limit is applied. If this option is not specified, the default limit for the server is 100.

    When the specified or default number for MAXRECURSION limit is reached during query execution, the query is ended and an error is returned.

    Because of this error, all effects of the statement are rolled back. If the statement is a SELECT statement, partial results or no results may be returned. Any partial results returned may not include all rows on recursion levels beyond the specified maximum recursion level.

    Ho provato a modificare l'UDF che ti avevo suggerito, ma SQL rilancia un errore di compilazione:

    CREATE FUNCTION dbo.udf_GetInterval(
    @Interval smallint 
    1
    )
    RETURNS TABLE
    AS

    RETURN 
    (
        
    WITH CTE_GetInterval 
    AS
        
    (
            
    /* Anchor Member */
            
    SELECT 
    *
            
    FROM 
    dbo.myData
            
    WHERE DataID 
    1

            
    UNION 
    ALL

            
    /* Recursive Member */
            
    SELECT D.
    *
            
    FROM dbo.myData AS 
    D
            
    JOIN CTE_GetInterval AS 
    CTE
            
    ON D.Date DATEADD(minute@IntervalCTE.Date
    )
        )
        
    SELECT 
    *
        
    FROM 
    CTE_GetInterval
        
    OPTION (MAXRECURSION 0
    )
    );
    GO

    /* Output:

    Msg 156, Level 15, State 1, Procedure udf_GetInterval, Line 25
    Incorrect syntax near the keyword 'OPTION'.

    */
      

    Sinceramente non ti so spiegare la causa (la CTE non ha problemi), così ho pensato di incapsularla in una stored procedure:

    CREATE PROCEDURE dbo.up_GetInterval(
    @Interval smallint 
    1
    )
    AS
    WITH 
    CTE_GetInterval 
    AS
    (
        
    /* Anchor Member */
        
    SELECT 
    *
        
    FROM 
    dbo.myData
        
    WHERE DataID 
    1

        
    UNION 
    ALL

        
    /* Recursive Member */
        
    SELECT D.
    *
        
    FROM dbo.myData AS 
    D
        
    JOIN CTE_GetInterval AS 
    CTE
        
    ON D.Date DATEADD(minute@IntervalCTE.Date
    )
    )
    SELECT 
    *
    FROM 
    CTE_GetInterval
    OPTION (MAXRECURSION 0
    );
    GO

    EXEC dbo.up_GetInterval 5
    ;

    /* Output:

    DataID      Date
    ----------- -----------------------
    1           2007-06-01 10:00:00.000
    6           2007-06-01 10:05:00.000
    11          2007-06-01 10:10:00.000
    16          2007-06-01 10:15:00.000

    (4 row(s) affected)

    */
      

    Per quanto riguarda i problemi di performance, definisci un indice clustered sulla colonna Date.

    Ciao!

    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://italy.mvps.org
    • Post Points: 5
  • 08-06-2008 15.16 In reply to

    • peperomero
    • Top 150 Contributor
      Male
    • Joined on 05-20-2008
    • Roma
    • Posts 2
    • Points 25

    Re: Query su date con intervalli temporali

    Grazie Lorenzo, come sempre il tuo sapere è fondamentale :P.

    • Post Points: 5
Page 1 of 1 (3 items)
(C) 2007 User Group Italiano di SQL Server