2017-11-16 11 views
0

분할 함수를 사용하여 쿼리에 값의 범위를 추가하려고합니다. 나는 또한 'OR'값을 함께하지만 첫 번째 일을 먼저하고 싶습니다. 분할 함수를 사용하는 훨씬 더 큰 쿼리에서 찾은 예제를 따르면서 어떻게 작동하는지 알아 내려고 작은 쿼리를 만들었습니다. 지금까지 내가 얻은 것은 오류 * "국가 이름 * Select * from sp as WHERE (sp.CountryID in (SELECT [값] FROM dbo.Split ('2,22,', ','))))입니다. '은 유효한 식별자가 아닙니다. * DynamicSQL을 알고 있었고이 분할 함수가 어떻게 작동하는지 잘 모르겠습니다. 동적 SQL 쉼표로 구분 된 문자열에서 조건을 추가하는 Split 함수가 작동하지 않습니다.

DECLARE @Countries varchar(MAX); 
DECLARE @FiltersOn bit; 
DECLARE @Country int; 
DECLARE @Query varchar(MAX); 

Set @FiltersOn = 0; 
Set @Query = 'Select * from Country As sp '; 
Set @Countries ='2,22,' 



     IF (@Countries IS NOT NULL) 
      BEGIN 
       IF (@FiltersOn = 1) 
        BEGIN 
         SET @Query = @Query + ' AND ' 
        END 
       ELSE 
        BEGIN 
         SET @Query = @Query + ' WHERE ' 
         SET @FiltersOn = 1 
        END 

       SET @Query = @Query 
        + '(sp.CountryID in (SELECT [Value] FROM dbo.Split(''' 
        + @Countries + ''', '','')))' 
      END 

      EXEC @Query 

은 국가 테이블의 정의입니다 :

CREATE TABLE [dbo].[Country](
    [CountryID] [int] IDENTITY(1,1) NOT NULL, 
    [AgentID] [int] NULL, 
    [Name] [varchar](50) NULL, 
    [CountryLookupID] [int] NOT NULL 

이것은 분할 기능 코드입니다 : 당신은 제대로 EXEC 문을 작성하지 않는

CREATE FUNCTION [dbo].[Split] 
(
    @String varchar(8000), 
    @Delimiter varchar(10) 
) 
RETURNS @ValueTable table ([Value] varchar(255)) 

BEGIN 
    DECLARE @NextString varchar(4000) 
    DECLARE @Pos int 
    DECLARE @NextPos int 
    DECLARE @DelimiterCheck varchar(1) 

    -- initialise 
    SET @NextString = '' 
    SET @DelimiterCheck = RIGHT(@String, 1) 

    -- add trailing delimiter 
    IF (@DelimiterCheck <> @Delimiter) 
     SET @String = @String + @Delimiter 

    -- find position of first delimiter 
    SET @Pos = CHARINDEX(@Delimiter, @String) 
    SET @NextPos = 1 

    -- loop while there is a delimiter in the string 
    WHILE (@Pos <> 0) 
    BEGIN 
     SET @NextString = SUBSTRING(@String, 1, @Pos - 1) 

     INSERT INTO @ValueTable ([Value]) VALUES (@NextString) 

     SET @String = SUBSTRING(@String, @Pos + 1, LEN(@String)) 

     SET @NextPos = @Pos 
     SET @Pos = CHARINDEX(@Delimiter, @String) 
    END 

    RETURN 
END 
+3

나는 휴지통에 그 스플리터를 던지기 건의 할 것입니다. 문자열을 분할하는 루프는 성능면에서 끔찍합니다. 나의 개인적인 마음에 드는 것은 이것이다. http://www.sqlservercentral.com/articles/Tally+Table/72993/ 몇 가지 다른 훌륭한 선택 사항을 여기에서 찾을 수 있습니다. http://sqlperformance.com/2012/07/t-sql-queries/split-strings –

+1

그리고 동적 SQL을 이미 사용하고 있다면 스플리터를 사용하여 쉼표로 구분 된 문자열을 쉼표로 되돌릴 필요가 없습니다. 구분 된 문자열. –

답변

0

.

사용 EXEC (@Query) 대신이 귀하의 질문에 직접 대답은 아니지만, 뭔가 내가 이러한 솔루션은 이전에 시스템에 문제를 야기 seend 한로를 통해 읽기 권 해드립니다 할 수

+0

감사합니다. 문제가 해결되었습니다. – MisterG

0

EXEC @Query의.

WHILE 루프를 사용하는 솔루션을 사용하지 않을 것을 제안합니다. While 루프는 SQL Server가 C# 엔진처럼 루프를 최적화하는 동일한 기능을 가지고 있지 않기 때문에 끊임없이 성능 문제를 만듭니다.

왜 동적 SQL을 사용하는지 잘 모르겠습니다. 만약 당신이 거기에 유해한 코드를 확인하지만 우리는 우리의 기본 데이터의 구조를 (따라서 동적 SQL에 대한 필요성을) 모르겠다 동적 SQL을 사용하지 않는 것 대신 sp_executesql을 사용하시기 바랍니다 SQL 주입이 있는지 확인하십시오.

성능을 유지하기 위해 cte를 사용하여 문자열 분할을 수행하는 함수를 작성했습니다.

CREATE SCHEMA Util; 

    GO 

    CREATE FUNCTION Util.String_Split (
     @Text varchar(MAX), 
     @SplitChar char 
    ) 
    RETURNS TABLE 
    AS 
    RETURN(
     WITH cte AS 
     (
      SELECT 
       1 AS [RowNumber], 
       X.Text, 
       X.RemainingText 
      FROM 
       (
        SELECT 
         SUBSTRING(@Text, 1, CHARINDEX(';', @Text) - 1) AS [Text], 
         SUBSTRING(@Text, CHARINDEX(';', @Text) + 1, LEN(@Text) - CHARINDEX(';', @Text)) AS [RemainingText] 
       ) X 
      UNION ALL 
      SELECT 
       cte.RowNumber + 1, 
       X.Text, 
       X.RemainingText 
      FROM 
       cte 
       CROSS APPLY (
        SELECT 
         SUBSTRING(cte.RemainingText, 1, ISNULL(NULLIF(CHARINDEX(';', cte.RemainingText) - 1, -1), LEN(cte.RemainingText))) AS [Text], 
         CASE 
          WHEN CHARINDEX(';', cte.RemainingText) = 0 THEN 
           '' 
          ELSE 
           SUBSTRING(cte.RemainingText, CHARINDEX(';', cte.RemainingText) + 1, LEN(cte.RemainingText)) 
         END AS [RemainingText] 
       ) X 
      WHERE 
       X.Text '' 
     ) 
     SELECT 
      cte.Text 
     FROM 
      cte 
     WHERE 
      cte.Text IS NOT NULL 
    ); 

그런 다음이 호출을 사용하여 동적 부분없이 귀하의 요청을 호출 할 수 있습니다

SELECT 
     * 
    FROM 
     Country sp 
    WHERE 
     @Countries IS NULL 
     OR 
     sp.CountryId IN (
      SELECT * FROM Util.String_Split(@Countries, ',') 
     )