2017-11-16 18 views
0

分割機能を使用してクエリに値の範囲を追加しようとしています。私はまた、値を一緒に 'OR'したいが、最初のものを最初にする。私は分割関数を使用するはるかに大きなクエリで見つかった例に従っているので、小さなクエリを使ってその動作を理解しようとしました。これまでのところ、私が得られるのはエラーです。* "The name 'Select Country from sp WHERE(sp.CountryID in(SELECT [値] FROM dbo.Split(' 2,22、 '、'、 '))) 'は有効な識別子ではありません。」* DynamicSQLを知っていて、この分割機能がどのように動作するはずです。DynamicSQL分割機能がコンマ区切り文字列の条件を追加できません。

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 

、これはsplit関数のコードです:

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文を書いていません。代わりにEXEC @Query

+0

ありがとう、それは私の問題を解決しました。 – MisterG

0

使用EXEC (@Query)これは、あなたの質問に直接答えではないが、私はこれらのソリューションは、前のシステムで問題を作成seendてきたように、何か私が通じ読んでお勧めすることができます。

WHILEループを使用したソリューションを使用しないことをお勧めします。 Whileループは、パフォーマンスの問題を常に発生させます.SQL Serverには、たとえばC#エンジンほどループを最適化する能力がありません。

なぜ動的SQLを使用するのかわかりません。 SQLインジェクションがないことを確認したい場合は、代わりにsp_executesqlを使用してください。有害なコードをチェックしますが、動的SQLを使用しないようにします(動的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, ',') 
     )
関連する問題