2013-08-21 3 views
0

Execute 문으로 명령 문자열을 사용하는 함수에서 결과 집합을 반환하려고합니다. 이 코드를 실행하면동적 쿼리 함수에서 결과를 반환

것은, 그것은 오류 다음 반환

create function GetLogApiCalls 
(
@displayStart int, 
@displayLength int, 
@searchString nvarchar(1000), 
@orderBy nvarchar(100), 
@orderByDirection varchar(50) 
) 
returns @logs table(
[Id]    INT  NOT NULL, 
[Provider]   NVARCHAR (10) NULL, 
[RequestIdentifier] UNIQUEIDENTIFIER NULL, 
[RequestData]  NVARCHAR (MAX) NULL, 
[ResponseData]  NVARCHAR (MAX) NULL, 
[UserName]   NVARCHAR (50) NULL, 
[AccountName]  NVARCHAR (100) NULL, 
[AccountId]   INT    NULL, 
[CreatedUserId]  INT    NULL, 
[CreatedDate]  DATETIME   NULL, 
[MethodName]  NVARCHAR (100) NULL 
) 
AS 
BEGIN 


DECLARE @sqlScript NVARCHAR(1000) 


IF(@searchString IS NOT NULL AND LEN(@searchString) > 0) 
BEGIN 
SET @sqlScript = N'SELECT * FROM 
       (
       SELECT ROW_NUMBER() OVER (ORDER BY '[email protected]+' '[email protected]+') AS rn , * from LogAPICall where Provider like ''%'[email protected]+'%'' or MethodName like ''%'[email protected]+'%'' 
       ) as result where result.rn between '+ CONVERT(varchar,@displayStart) + ' and ' + CONVERT(varchar,@displayLength) 
END 
ELSE 
BEGIN 
SET @sqlScript = N'SELECT * FROM 
       (
       SELECT ROW_NUMBER() OVER (ORDER BY '[email protected]+' '[email protected]+') AS RN , * FROM LogAPICall 
       ) AS result WHERE result.rn between ' + CONVERT(varchar,@displayStart) + ' and ' + CONVERT(varchar,@displayLength) 
END 

insert @logs 
Execute(@sqlScript) 
return 

END :

Invalid use of a side-effecting operator 'INSERT EXEC' within a function. 

이 문제를 해결하기 위해 도와주세요. 감사합니다.

+2

[또한 길이가없는'varchar' 선언을 중단하십시오] (http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/bad-habits-to-kick-declaring-varchar-without- length.aspx) 및 [개체를 만들거나 참조 할 때 항상 스키마 접두사를 사용합니다.] (http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/11/bad-habits-to-kick-avoiding-the- schema-prefix.aspx). –

+0

알겠습니다.이 사실을 명심하십시오. 덕분에 – sanjeev

답변

5

죄송합니다. 함수, 기간에 동적 SQL을 수행 할 수 없습니다. 동적 SQL을 필요로하지 않는 함수를 다시 작성할 수는 있지만 근본적인 문제를 실제로 해결할 수 있습니까? 절차가 필요하고 반환 유형과 관련된 전혀 관련이없는 Entity Framework 문제로 인해 여전히 손수갑 일 때 무엇을 할 것입니까? 분명히 EF를 구성했거나 프로 시저를 연결 한 방식이 잘못되었거나 그렇지 않은 경우 lot 사람이 결과 집합을 반환하는 절차에서 EF가 작동하지 않는다고 불평 할 것입니다. 그럴 것 같니?

CREATE FUNCTION dbo.GetLogApiCalls -- dbo prefix, always 
(
    @displayStart  INT, 
    @displayLength INT, -- is this a page size, like 20, or @displayEnd? 
    @searchString  NVARCHAR(1000), 
    @orderBy   NVARCHAR(100), 
    @orderByDirection VARCHAR(4) 
) 
RETURNS TABLE 
AS -- make it an inline TVF. Multi-statement TVFs can be a perf nightmare. 
RETURN 
(
    SELECT * FROM 
    (
    SELECT rn = ROW_NUMBER() OVER (ORDER BY 
    CASE @orderByDirection WHEN 'ASC' THEN 
     CASE @orderBy WHEN N'Provider'  THEN Provider 
        WHEN N'RequestData' THEN RequestData 
        WHEN N'ResponseData' THEN ResponseData 
        WHEN N'UserName'  THEN UserName 
        WHEN N'AccountName' THEN AccountName 
        WHEN N'MethodName' THEN MethodName 
        WHEN N'RequestIdentifier' 
             THEN CONVERT(CHAR(36), RequestIdentifier) 
        WHEN N'CreatedDate' THEN CONVERT(CHAR(23), CreatedDate, 126) 
     END 
    END, 
    CASE @orderByDirection WHEN 'ASC' THEN 
     CASE @orderBy WHEN N'Id'   THEN Id 
        WHEN N'AccountId'  THEN AccountId 
        WHEN N'CreatedUserId' THEN CreatedUserId 
     END 
    END, 
    CASE @orderByDirection WHEN 'DESC' THEN 
     CASE @orderBy WHEN N'Provider'  THEN Provider 
        WHEN N'RequestData' THEN RequestData 
        WHEN N'ResponseData' THEN ResponseData 
        WHEN N'UserName'  THEN UserName 
        WHEN N'AccountName' THEN AccountName 
        WHEN N'MethodName' THEN MethodName 
        WHEN N'RequestIdentifier' 
             THEN CONVERT(CHAR(36), RequestIdentifier) 
        WHEN N'CreatedDate' THEN CONVERT(CHAR(23), CreatedDate, 126) 
     END 
    END DESC, 
    CASE @orderByDirection WHEN 'DESC' THEN 
     CASE @orderBy WHEN N'Id'   THEN Id 
        WHEN N'AccountId'  THEN AccountId 
        WHEN N'CreatedUserId' THEN CreatedUserId 
     END 
    END DESC), [Id],[Provider],[RequestIdentifier],[RequestData], 
    [ResponseData],[UserName],[AccountName],[AccountId], 
    [CreatedUserId],[CreatedDate],[MethodName] 
    FROM dbo.LogAPICall 
    WHERE LEN(@searchString) = 0 OR 
    (
    @searchString > '' AND 
    ( 
     Provider LIKE '%' + @searchString + '%' 
     OR MethodName LIKE '%' + @searchString + '%' 
    ) 
) 
) AS x 
WHERE rn BETWEEN @displayStart AND @displayStart + @displayLength - 1 -- assumption 
); 

이 동적 인 ORDER BY은 악마입니다. 인라인 TVF인데도 조회를 수행하고 OPTION (RECOMPILE)을 추가하여 다른 매개 변수에 대해서만 잘 수행됩니다. 해결책? 동적 SQL과 함께 저장 프로 시저를 사용하고 Entity Framework 구성 문제를 별도로 파악하십시오.

CREATE PROCEDURE dbo.GetLogApiCalls -- dbo prefix, always 
    @displayStart  INT, 
    @displayLength INT, -- is this a page size, like 20, or @displayEnd? 
    @searchString  NVARCHAR(1000), 
    @orderBy   NVARCHAR(100), 
    @orderByDirection VARCHAR(4) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM (
    SELECT rn = ROW_NUMBER() OVER (ORDER BY ' 
     + @orderBy + ' ' + @orderByDirection + '), 
     [Id],[Provider],[RequestIdentifier],[RequestData], 
     [ResponseData],[UserName],[AccountName],[AccountId], 
     [CreatedUserId],[CreatedDate],[MethodName] 
    FROM dbo.LogAPICall' 
    + CASE WHEN LEN(@searchString) > 0 THEN 
    ' WHERE Provider LIKE ''%'' + @searchString + ''%'' 
     OR MethodName LIKE ''%'' + @searchString + ''%''' 
     ELSE '' END 
    + ') AS x 
     WHERE rn BETWEEN @displayStart 
     AND @displayStart + @displayLength - 1;'; 

    DECLARE @params NVARCHAR(MAX) = N'@searchString NVARCHAR(1000),' 
    + '@displayStart INT, @displayLength INT'; 

    EXEC sp_executesql @sql, @params, @searchString, @displayStart, @displayLength; 
END 
GO 

당신이 설정 optimize for ad hoc workloads가 활성화 한 경우에 특히 : 저장 프로 시저로이 훨씬 더 같은 것입니다. 이제는 매개 변수화 할 수없는 동적 ORDER BY로 인해 SQL 인젝션이 발생하기 쉽기 때문에이 매개 변수에 유효한 값만 포함되어 있는지 확인을 추가 할 수 있습니다.

+0

저장소 프로 시저를 만들었지 만 Entity Framework에 해당 저장 프로 시저를 추가하면 정수가 반환되는 형식의 코드가 생성되었지만 결과 집합이 필요합니다. 어떤 제안? – sanjeev

+0

@sanjeev 반환 값과 결과 집합은 서로 다른 두 가지입니다. Entity Framework를 어떻게 도와 줄지 모르겠지만 함수를 사용하면이 문제를 해결할 수 없습니다. –

+0

나는 이것을 보았다. http://stackoverflow.com/questions/17635069/entity-framework-generated-representation-of-a-stored-procedure-signature-is-an 그들은 사용자 정의 함수를 사용하도록 제안하고있다. – sanjeev

관련 문제