2013-02-26 7 views
24

Sono giunto alla conclusione che alcune versioni di Microsoft OLE DB Provider per SQL Server (principalmente su Windows XP) non supportano l'istruzione WITH. Così, ho deciso di spostare la mia istruzione SQL in una funzione valutata a livello di tabella e di chiamarla dalla mia applicazione. Ora, sono bloccato. Come dovrei usare la dichiarazione INSERT INTO con WITH? Ecco il codice che ho venire con finora, ma SQL Server non piace ... :-(Come utilizzare un'istruzione CTE in una funzione con valori di tabella in SQL Server

CREATE FUNCTION GetDistributionTable 
(
    @IntID int, 
    @TestID int, 
    @DateFrom datetime, 
    @DateTo datetime 
) 
RETURNS 
@Table_Var TABLE 
(
    [Count] int, 
    Result float 
) 
AS 
BEGIN 
INSERT INTO @Table_Var ([Count], Result) WITH T(Result) 
    AS (SELECT ROUND(Result - AVG(Result) OVER(), 1) 
     FROM RawResults WHERE IntID = @IntID AND DBTestID = @TestID AND Time >= @DateFrom AND Time <= @DateTo) 
SELECT COUNT(*) AS [Count], 
     Result 
FROM T 
GROUP BY Result 

    RETURN 
END 
GO 

risposta

33

È possibile omettere il CTE (WITH dichiarazione), e invece creare una tabella inline funzione con valori che utilizza subquery:

CREATE FUNCTION GetDistributionTable 
(
    @IntID int, 
    @TestID int, 
    @DateFrom datetime, 
    @DateTo datetime 
) 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT COUNT(*) AS [Count], 
      Result 
    FROM (
       SELECT ROUND(Result - AVG(Result) OVER(), 1) Result 
       FROM RawResults 
       WHERE IntID = @IntID 
       AND DBTestID = @TestID 
       AND Time >= @DateFrom 
       AND Time <= @DateTo  
    ) t 
    GROUP BY 
      Result 
) 
GO 

Sintassi per il CTE in valori di tabella funzione sarebbe:

CREATE FUNCTION GetDistributionTable 
(
    @IntID int, 
    @TestID int, 
    @DateFrom datetime, 
    @DateTo datetime 
) 
RETURNS TABLE 
AS 
RETURN 
(
    WITH cte AS 
    (
     SELECT ROUND(Result - AVG(Result) OVER(), 1) Result 
     FROM RawResults 
     WHERE IntID = @IntID 
     AND DBTestID = @TestID 
     AND Time >= @DateFrom 
     AND Time <= @DateTo  
    ) 

    SELECT COUNT(*) AS [Count], 
      Result 
    FROM cte 
    GROUP BY 
      Result 
) 
GO 

il vostro esempio sembra utilizzare un TVF multi-economico (inserto e selezionare), quando si dispone di una scelta provare utilizzando il TVF in linea perché il multi-dichiarazione TVF può impedire di query optimizer nella scelta di un migliore piano di esecuzione (differenza di prestazioni spiegato here)

+0

Se il CTE è ricorsiva probabilmente vinto essere in grado di riscriverlo nel modulo subquery, quindi il modulo CTE potrebbe essere più di una semplice questione di gusto. Naturalmente, le CTE ricorsive possono eliminare l'ottimizzatore se non si presta attenzione: MattW

+0

così usato per usare un ';' davanti alla parte di cte. – JJS

14

COME QUESTO .. ​​

CREATE FUNCTION GetDistributionTable 
(
    @IntID int, 
    @TestID int, 
    @DateFrom datetime, 
    @DateTo datetime 
) 
RETURNS 
@Table_Var TABLE 
(
    [Count] int, 
    Result float 
) 
AS 
BEGIN 
    WITH T 
    AS ( 
     select Ticket_Id,COUNT(1) Result from 
     Customer_Survey 
     group by MemberID,SiteId,Ticket_Id 
    ) 
    INSERT INTO @Table_Var ([Count], Result) 
    SELECT COUNT(*) AS [Count], 
     Result 
    FROM T 
    GROUP BY Result 
    RETURN 
END 
GO 
+1

Se possibile, si dovrebbe testare sia la funzione multi-statement come si è mostrato, sia la funzione 'RETURNS TABLE' di istruzione singola in quanto quest'ultima può essere inline e quindi avere prestazioni molto migliori (vedere il link in fondo a Risposta di Ivan G). Tuttavia, come al solito, tutto dipende - * a volte *, anche se raramente, è più veloce usare la funzione multi-statement. – ErikE

Problemi correlati