복붙노트

[SQL] 는 SQL IN 절을 매개 변수화

SQL

는 SQL IN 절을 매개 변수화

어떻게하면이 같은 인수의 변수 번호 IN 절을 포함하는 쿼리를 매개 변수화합니까?

SELECT * FROM Tags 
WHERE Name IN ('ruby','rails','scruffy','rubyonrails')
ORDER BY Count DESC

이 쿼리에서는 인수의 수는 어디서나 1에서 5 수 있습니다.

나는이 (또는 XML)을위한 전용 저장 프로 시저를 사용하지 않는 것을 선호하지만, SQL Server 2008로 섬세한 방식으로 특정이있는 경우, 그 개방입니다.

해결법

  1. ==============================

    1.여기에 내가 사용한 빠른 앤 더러운 기술이다 :

    여기에 내가 사용한 빠른 앤 더러운 기술이다 :

    SELECT * FROM Tags
    WHERE '|ruby|rails|scruffy|rubyonrails|'
    LIKE '%|' + Name + '|%'
    

    그래서 여기에 C # 코드는 다음과 같습니다

    string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
    const string cmdText = "select * from tags where '|' + @tags + '|' like '%|' + Name + '|%'";
    
    using (SqlCommand cmd = new SqlCommand(cmdText)) {
       cmd.Parameters.AddWithValue("@tags", string.Join("|", tags);
    }
    

    두 가지주의 사항 :

    어떤 사람들은 이렇게 독서를 보관하십시오, 청소기를 고려할 수 있음이 작업을 수행 할 수있는 다른 방법이 있습니다.

  2. ==============================

    2.당신은 같은 수 있도록, 각 값을 매개 변수화 할 수 있습니다 :

    당신은 같은 수 있도록, 각 값을 매개 변수화 할 수 있습니다 :

    string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
    string cmdText = "SELECT * FROM Tags WHERE Name IN ({0})";
    
    string[] paramNames = tags.Select(
        (s, i) => "@tag" + i.ToString()
    ).ToArray();
    
    string inClause = string.Join(", ", paramNames);
    using (SqlCommand cmd = new SqlCommand(string.Format(cmdText, inClause))) {
        for(int i = 0; i < paramNames.Length; i++) {
           cmd.Parameters.AddWithValue(paramNames[i], tags[i]);
        }
    }
    

    당신을 줄 것이다 :

    cmd.CommandText = "SELECT * FROM Tags WHERE Name IN (@tag0, @tag1, @tag2, @tag3)"
    cmd.Parameters["@tag0"] = "ruby"
    cmd.Parameters["@tag1"] = "rails"
    cmd.Parameters["@tag2"] = "scruffy"
    cmd.Parameters["@tag3"] = "rubyonrails"
    

    아니,이 SQL 주입에 열려 있지 않습니다. 의 CommandText으로 만 분사 텍스트는 사용자 입력에 기초하지 않는다. 그것은 전적으로 하드 코딩 "@tag"접두사, 및 배열의 ​​인덱스를 기반으로. 인덱스는 항상 정수가됩니다, 사용자 생성하지 않으며, 안전합니다.

    사용자 입력 값은 여전히 ​​아무 취약점이없는 파라미터로 봉제되어있다.

    편집하다:

    캐시 된 쿼리 계획은 가치없는 아니,하지만 IMO이 쿼리는 거의 그것에서 많은 혜택을 볼 수있을만큼 복잡하지 않습니다. 컴파일 비용이 실행 비용 접근 (또는 초과) 수 있지만, 당신은 여전히 ​​밀리 초를 얘기.

    당신이 충분한 RAM이있는 경우, 나는 SQL 서버 아마뿐만 아니라 매개 변수의 일반적인 계산에 대한 계획을 캐시 것이라고 기대. 비록 (쿼리 계획이 동일해야하지만, 그것은 나에게 매우 추한 보인다 나는 확실히 그것을 가치가 마이크로 최적화 거라고 아니에요 - 난 당신이 항상 5 개 개의 매개 변수를 추가하고, 지정되지 않은 태그 NULL하자 수도있을 것 같군요 스택 오버플로에 - 그것은 매우 가치를) 할 수있다.

    또한, SQL 서버 7 이상 의지 자동 매개 변수화 쿼리, 그래서 매개 변수를 사용하여 성능의 관점에서 정말 필요하지 않습니다 - 그것은 보안 관점에서 중요한, 그러나,이다 - 특히이 같은 사용자 입력 데이터.

  3. ==============================

    3.SQL 서버 2008, 당신은 테이블 반환 매개 변수를 사용할 수 있습니다. 그것은 작품의 비트,하지만 내 다른 방법보다 청소기 틀림없이.

    SQL 서버 2008, 당신은 테이블 반환 매개 변수를 사용할 수 있습니다. 그것은 작품의 비트,하지만 내 다른 방법보다 청소기 틀림없이.

    첫째, 당신은 유형을 만들어야합니다

    CREATE TYPE dbo.TagNamesTableType AS TABLE ( Name nvarchar(50) )
    

    그런 다음, ADO.NET 코드는 다음과 같습니다 :

    string[] tags = new string[] { "ruby", "rails", "scruffy", "rubyonrails" };
    cmd.CommandText = "SELECT Tags.* FROM Tags JOIN @tagNames as P ON Tags.Name = P.Name";
    
    // value must be IEnumerable<SqlDataRecord>
    cmd.Parameters.AddWithValue("@tagNames", tags.AsSqlDataRecord("Name")).SqlDbType = SqlDbType.Structured;
    cmd.Parameters["@tagNames"].TypeName = "dbo.TagNamesTableType";
    
    // Extension method for converting IEnumerable<string> to IEnumerable<SqlDataRecord>
    public static IEnumerable<SqlDataRecord> AsSqlDataRecord(this IEnumerable<string> values, string columnName) {
        if (values == null || !values.Any()) return null; // Annoying, but SqlClient wants null instead of 0 rows
        var firstRecord = values.First();
        var metadata = SqlMetaData.InferFromValue(firstRecord, columnName);
        return values.Select(v => 
        {
           var r = new SqlDataRecord(metadata);
           r.SetValues(v);
           return r;
        });
    }
    
  4. ==============================

    4.원래 질문은 "... 어떻게 쿼리를 매개 변수화 않는다"이었다

    원래 질문은 "... 어떻게 쿼리를 매개 변수화 않는다"이었다

    날이 원래의 질문에 대한 답변이 아님을, 바로 여기 상태 보자. 다른 좋은 대답에서 그 중 일부 시위가 이미 있습니다.

    말했다, 바로 당신이 생각대로 할 ...없는 답변으로 표시, 그것을 downvote,이 답변을 가서 국기와 함께.

    I (231 등)이 upvoted 것을 선호하는 답변을 마크 Brackett에서 답변을 참조하십시오. 그의 대답에 주어진 접근 방식은 스 SARGable 있습니다 술어에 대한 효과적인 바인드 변수의 사용 및 2)에 대해 1) 할 수 있습니다.

    선정 대답

    내가 여기 주소로 원하는 것은 정답으로 "선택"Spolsky 조엘의 대답, 대답에 주어진 접근 방식입니다.

    Spolsky 조엘의 접근 방식은 영리하다. 그리고는 "정상"값 주어진 예측 가능한 행동과 예측 가능한 성능을 전시하는 것, 및 NULL과 빈 문자열과 규범 가장자리 사례에있어, 합리적으로 작동합니다. 그리고 그것은 특정 응용 프로그램에 대한 충분한 수있다.

    그러나이 방법을 일반화 측면에서, 이름 열은 와일드 카드 문자가 포함 된 경우처럼의도, 더 애매한 사례를 살펴 보자합니다 (LIKE 술어에 의해 인식한다.) 내가 가장 일반적으로 사용되는 참조 와일드 카드 문자 %이다 (퍼센트 기호). . 그래서 지금 여기에와의 거래를하자, 나중에 다른 경우로 이동합니다.

    % 문자와 몇 가지 문제

    '체육 %의 ter'의 이름 값을 고려한다. (여기 예를 들어, 내가 열 이름 대신 리터럴 문자열 값을 사용합니다.) 행을`의 이름 값 '체육 % TER'형식의 쿼리에 의해 반환 될 것이다 :

    select ...
     where '|peanut|butter|' like '%|' + 'pe%ter' + '|%'
    

    검색어의 순서가 반대로하지만 같은 행이 반환되지 않습니다 :

    select ...
     where '|butter|peanut|' like '%|' + 'pe%ter' + '|%'
    

    우리가 관찰 행동은 홀수의 일종이다. 목록에서 검색 용어의 순서를 변경하면 결과 집합을 변경합니다.

    그것은 거의 우리가 체육 % TER는 땅콩 버터, 그는 그것을 좋아 아무리 일치하지 않을 수 있습니다 것은 말할 필요도 없다.

    애매한 구석 케이스

    (예, 나는이 모호한 경우가 동의 할 것이다. 가능성 테스트 할되지 아마 하나. 우리는 열 값에 와일드 카드를 기대하지 않을 것이다. 우리는에서 응용 프로그램을 방지 같은 값이 저장되는 것으로 가정 할 수있다. 그러나이 내 경험에서, 나는 거의 특별히 허용되지 않는 문자 또는 패턴이 LIKE 비교 연산자의 오른쪽에 와일드 카드로 간주 될 수있는 데이터베이스 제약 조건을 보지했습니다.

    정공 패치

    이 구멍을 패치하는 한 가지 방법은 % 와일드 카드 문자를 탈출하는 것입니다. (운영자의 탈출 절에 익숙하지 않은 사람의 경우, 여기에 SQL Server 설명서에 대한 링크입니다.

    select ...
     where '|peanut|butter|'
      like '%|' + 'pe\%ter' + '|%' escape '\'
    

    이제 우리는 리터럴 %를 일치시킬 수 있습니다. 우리가 열 이름이있는 경우 물론, 우리는 동적으로 와일드 카드를 탈출해야 할 것입니다. 우리는 % 문자의 발생을 찾아 같이, 각각의 앞에 백 슬래시 문자를 삽입하는 기능을 REPLACE 사용할 수 있습니다 :

    select ...
     where '|pe%ter|'
      like '%|' + REPLACE( 'pe%ter' ,'%','\%') + '|%' escape '\'
    

    이 해결할 수있는 문제는 % 와일드 카드에 문제가 그래서. 거의.

    탈출 탈출

    우리는 우리의 솔루션은 또 다른 문제를 발표했다 인식하고 있습니다. 이스케이프 문자. 우리는 또한 이스케이프 문자 자체의 발생을 탈출 할 거라고 참조하십시오. 이 시간, 우리는 사용! 이스케이프 문자로 :

    select ...
     where '|pe%t!r|'
      like '%|' + REPLACE(REPLACE( 'pe%t!r' ,'!','!!'),'%','!%') + '|%' escape '!'
    

    밑줄도

    이제 우리는 롤에 걸, 우리는 또 다른 밑줄 와일드 카드를 처리 REPLACE 추가 할 수 있습니다. 그리고 그냥 재미,이 시간, 우리는 이스케이프 문자로 $를 사용합니다.

    select ...
     where '|p_%t!r|'
      like '%|' + REPLACE(REPLACE(REPLACE( 'p_%t!r' ,'$','$$'),'%','$%'),'_','$_') + '|%' escape '$'
    

    이 오라클와 MySQL뿐만 아니라 SQL 서버에서 작동하기 때문에 탈출이 접근 방식을 선호합니다. (나는 우리가 정규 표현식에서 사용하는 문자이기 때문에 일반적으로, 이스케이프 문자로 \ 백 슬래시를 사용합니다. 그런데 왜 규칙에 의해 제약을받을 수!

    그 성가신 브래킷

    와일드 카드 문자가 괄호로 묶어 리터럴로 취급하는 SQL 서버도 할 수 있습니다 []. 그래서 우리는 적어도 SQL Server에 대해, 아직 해결하지 있습니다. 괄호 쌍은 특별한 의미를 가지고 있기 때문에, 우리는뿐만 아니라 사람들을 탈출해야합니다. 괄호 내와 캐럿 ^ - 우리가 제대로 브래킷을 탈출하기 위해 관리하는 경우, 적어도 우리가 하이픈으로 귀찮게 할 필요가 없습니다. 우리는 기본적으로 브래킷의 특별한 의미를 비활성화 한 것이기 때문에 우리는 괄호 안의 문자 이스케이프 어떤 %와 _을 남길 수 있습니다.

    괄호의 일치 쌍을 찾는 것은 어려운 일이 아니다. 그것은 좀 더 어려운 싱글 톤 %와 _의 발생을 처리하는 것보다입니다. 싱글 톤 브래킷은 리터럴로 간주되며, 이스케이프 할 필요가 없기 때문에 그것이 단지 대괄호의 모든 항목을 탈출하기에 충분 아니라고 (주. 논리가 좀 더 테스트 케이스를 실행하지 않고 처리 할 수있는 것보다 약간 흐려을 받고있다 .)

    인라인 표현은 혼란을 얻는다

    는 SQL에서 그 인라인 표현은 더 이상하고 이보다지고 있습니다. 우리는 아마 그것이 작동되도록 할 수 있지만, 하늘의 도움 뒤에오고있다 가난한 영혼을 해독 할 수 있습니다. 내가 인라인 표현식 오전 팬의 많은로서, 나는 혼란에 대한 이유를 설명하는 코멘트를 남기시려면 싶지 않아 주로하기 때문에, 여기에서 사용하지 기울어있어, 그것을 위해 사과.

    함수 어디?

    우리는 SQL에서 인라인 표현으로 그것을 처리하지 않는 경우 좋아, 그래서, 우리가 가지고있는 가장 가까운 대안은 사용자 정의 함수입니다. 그리고 우리는 어떤까지 그하지 않습니다 속도 것을 알고 (우리가 오라클과 수처럼 우리는 그것에 인덱스를 정의 할 수 있습니다하지 않는 한합니다.) 우리는 함수를 만드는 가지고 있다면, 우리가 더 잘 할 수 있다는 SQL을 호출하는 코드에 성명서.

    그리고 그 기능은 DBMS 및 버전에 따라 행동에 약간의 차이가있을 수 있습니다. (A 때문에 상호 교환하는 데이터베이스 엔진을 사용 할 수있는 예리한 모든 당신 자바 개발자에게 소리.)

    도메인 지식

    우리는 즉, 열에 대한 강제 허용 값의 집합. 우리는 열에 저장된 값을 백분율 기호, 밑줄 또는 브래킷을 포함하지 않을 것이라는 점을 선험적으로 알 수 있습니다 (컬럼의 도메인의 전문 지식을 모른다 쌍.이 경우, 우리는 이러한 경우가 적용되어 빠른 주석을 포함한다.

    컬럼에 저장된 값은 % 또는 _ 문자를 허용 할 수 있지만, 그 값이 필요할 수 있습니다 제약은 아마도 값이 LIKE 비교 "안전"이되도록, 정의 된 문자를 사용하여 이스케이프. 다시 말하지만, 빠른 값의 허용 세트에 대한 의견, 어느 문자 특히 이스케이프 문자로 사용하고 Spolsky 조엘의 접근 방식과 함께 할 것입니다.

    그러나, 전문 지식과 보장, 그것은 우리를 위해 적어도 그 애매한 케이스를 취급 고려하는 것이 중요 결석, 그리고 행동 "의 사양에 따라,"합리적이고 여부를 고려한다.

    다른 문제는 효과적으로 요약

    나는 다른 사람들이 이미 충분히 우려의 다른 일반적으로 간주 지역의 일부 지적 믿습니다

    결론

    나는 Spolsky 조엘의 접근 방식을 좋아한다. 그것은 영리합니다. 그리고 그것은 작동합니다.

    그러나 곧 내가 그것을보고, 나는 즉시로 잠재적 인 문제를보고, 그것이 밀어 수 있도록 내 성격이 아니다. 나는 다른 사람의 노력의 중요 의미하지 않는다. 나는 그들이 그것으로 너무 많은 투자를하기 때문에 많은 개발자들이 매우 개인적으로 자신의 작품을 알고 그들은 그것에 대해 너무 많이 걱정. 그래서 이것은 개인적인 공격하지 않습니다, 양해 바랍니다. 내가 여기 파악하고있어 생산이 아닌 테스트에서 작물 문제의 유형입니다.

    네, 원래의 질문에서 멀리 멀리 갔어요. 그러나 다른 어디 내가 질문에 대해 "선택"대답과 함께 중요한 문제로 간주 무엇에 관한 메모를 떠나?

  5. ==============================

    5.당신은 문자열로 매개 변수를 전달할 수 있습니다

    당신은 문자열로 매개 변수를 전달할 수 있습니다

    당신은 문자열이 그래서

    DECLARE @tags
    
    SET @tags = ‘ruby|rails|scruffy|rubyonrails’
    
    select * from Tags 
    where Name in (SELECT item from fnSplit(@tags, ‘|’))
    order by Count desc
    

    그럼 당신이해야 할 일 개 매개 변수로 문자열을 전달합니다.

    여기 내가 사용하는 분할 기능입니다.

    CREATE FUNCTION [dbo].[fnSplit](
        @sInputList VARCHAR(8000) -- List of delimited items
      , @sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
    ) RETURNS @List TABLE (item VARCHAR(8000))
    
    BEGIN
    DECLARE @sItem VARCHAR(8000)
    WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
     BEGIN
     SELECT
      @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
      @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
    
     IF LEN(@sItem) > 0
      INSERT INTO @List SELECT @sItem
     END
    
    IF LEN(@sInputList) > 0
     INSERT INTO @List SELECT @sInputList -- Put the last item in
    RETURN
    END
    
  6. ==============================

    6.나는 팟 캐스트 오늘 (에피소드 34, 2008-12-16 (MP3 31 MB), 1 시간 03 분 38 초 - 1 시간 06 분 45 초)에이 약 제프 / 조엘의 이야기를 듣고 난 스택 오버플로를 회상 생각 SQL에 LINQ를 사용했다,하지만 어쩌면 그것은 도랑에 빠지게되었다. 여기에 SQL에 LINQ에서 같은 일이다.

    나는 팟 캐스트 오늘 (에피소드 34, 2008-12-16 (MP3 31 MB), 1 시간 03 분 38 초 - 1 시간 06 분 45 초)에이 약 제프 / 조엘의 이야기를 듣고 난 스택 오버플로를 회상 생각 SQL에 LINQ를 사용했다,하지만 어쩌면 그것은 도랑에 빠지게되었다. 여기에 SQL에 LINQ에서 같은 일이다.

    var inValues = new [] { "ruby","rails","scruffy","rubyonrails" };
    
    var results = from tag in Tags
                  where inValues.Contains(tag.Name)
                  select tag;
    

    이게 다예요. 그리고, 그래, LINQ는 이미 뒤로 충분히 보이지만 절은 나에게 여분의 뒤쪽으로 보인다 포함합니다. 나는 직장에서 프로젝트에 대한 유사한 쿼리를해야 할 일을했을 때, 나는 자연스럽게을 처리 할 수있는 스마트 충분하다 SQL 번역기에 LINQ를 계산이에게 로컬 배열과 SQL Server 테이블 간의 조인을 수행하여 잘못된 방법을 시도 어떻게 든 번역. 그것은하지 않았다, 그러나 그것은 설명이었다 포함하여쪽으로 나를 지적하는 오류 메시지를 제공했다.

    당신이 추천 LINQPad에서 이것을 실행하고이 쿼리를 실행하면 어쨌든, 당신은 SQL LINQ 공급자가 생성하는 실제 SQL을 볼 수 있습니다. 그것은 당신에게 각 값 IN 절에 파라미터하기를 보여줄 것이다.

  7. ==============================

    7.당신은 .NET에서 전화하는 경우, 당신은 말끔 순 점 사용할 수 있습니다 :

    당신은 .NET에서 전화하는 경우, 당신은 말끔 순 점 사용할 수 있습니다 :

    string[] names = new string[] {"ruby","rails","scruffy","rubyonrails"};
    var tags = dataContext.Query<Tags>(@"
    select * from Tags 
    where Name in @names
    order by Count desc", new {names});
    

    당신이하지 않아도 여기서 단정는 생각을한다. 비슷한 무언가가 SQL 물론에 LINQ 가능합니다 :

    string[] names = new string[] {"ruby","rails","scruffy","rubyonrails"};
    var tags = from tag in dataContext.Tags
               where names.Contains(tag.Name)
               orderby tag.Count descending
               select tag;
    
  8. ==============================

    8.이것은 아마도 그 일의 절반 불쾌한 방법입니다, 나는 그것이 한 번, 오히려 효과적 사용했다.

    이것은 아마도 그 일의 절반 불쾌한 방법입니다, 나는 그것이 한 번, 오히려 효과적 사용했다.

    당신의 목표에 따라 그 사용이 될 수 있습니다.

    이것은 당신이 무엇을 할 수있는 유연성을 조금 가지고 있지만, 그것은 당신이 좋은 인덱싱, 쿼리에 큰 테이블이 상황에 더 적합, 그리고 당신은 두 번 이상 매개 변수화 목록을 사용하고 싶습니다. 두 번 실행하고 모든 위생이 수동으로 수행해야 할 필요가 저장합니다.

    나는 그것이 정확히 얼마나 빨리 프로파일 링 주위에 없어,하지만 내 상황에서이 필요했다 않았다.

  9. ==============================

    9.SQL 서버에서 2016+는 STRING_SPLIT 기능을 사용할 수 있습니다 :

    SQL 서버에서 2016+는 STRING_SPLIT 기능을 사용할 수 있습니다 :

    DECLARE @names NVARCHAR(MAX) = 'ruby,rails,scruffy,rubyonrails';
    
    SELECT * 
    FROM Tags
    WHERE Name IN (SELECT [value] FROM STRING_SPLIT(@names, ','))
    ORDER BY [Count] DESC;
    

    또는:

    DECLARE @names NVARCHAR(MAX) = 'ruby,rails,scruffy,rubyonrails';
    
    SELECT t.*
    FROM Tags t
    JOIN STRING_SPLIT(@names,',')
      ON t.Name = [value]
    ORDER BY [Count] DESC;
    

    LiveDemo

    물론 작업의 허용 대답의 뜻과 길을 가야하는 것 중 하나이지만, 안티 패턴이다.

    추가:

    STRING_SPLIT 테이블 함수 행 추정을 개선하기 위해, 그것은 임시 테이블 / 테이블 변수로 분할 할 가치를 실현하는 것이 좋습니다 :

    DECLARE @names NVARCHAR(MAX) = 'ruby,rails,scruffy,rubyonrails,sql';
    
    CREATE TABLE #t(val NVARCHAR(120));
    INSERT INTO #t(val) SELECT s.[value] FROM STRING_SPLIT(@names, ',') s;
    
    SELECT *
    FROM Tags tg
    JOIN #t t
      ON t.val = tg.TagName
    ORDER BY [Count] DESC;
    

    SEDE - 라이브 데모

    관련 : 저장 프로 시저에 값의 목록을 전달하는 방법

    원래 질문이 질문은 종종 중복으로 사용되기 때문에 요구 사항 SQL Server 2008을 가지고, 나는 참고로이 답변을 추가했습니다.

  10. ==============================

    10.우리는 당신이에 가입 할 수있는 테이블 변수를 생성 기능을 가지고 :

    우리는 당신이에 가입 할 수있는 테이블 변수를 생성 기능을 가지고 :

    ALTER FUNCTION [dbo].[Fn_sqllist_to_table](@list  AS VARCHAR(8000),
                                               @delim AS VARCHAR(10))
    RETURNS @listTable TABLE(
      Position INT,
      Value    VARCHAR(8000))
    AS
      BEGIN
          DECLARE @myPos INT
    
          SET @myPos = 1
    
          WHILE Charindex(@delim, @list) > 0
            BEGIN
                INSERT INTO @listTable
                            (Position,Value)
                VALUES     (@myPos,LEFT(@list, Charindex(@delim, @list) - 1))
    
                SET @myPos = @myPos + 1
    
                IF Charindex(@delim, @list) = Len(@list)
                  INSERT INTO @listTable
                              (Position,Value)
                  VALUES     (@myPos,'')
    
                SET @list = RIGHT(@list, Len(@list) - Charindex(@delim, @list))
            END
    
          IF Len(@list) > 0
            INSERT INTO @listTable
                        (Position,Value)
            VALUES     (@myPos,@list)
    
          RETURN
      END 
    

    그래서:

    @Name varchar(8000) = null // parameter for search values    
    
    select * from Tags 
    where Name in (SELECT value From fn_sqllist_to_table(@Name,',')))
    order by Count desc
    
  11. ==============================

    11.이것은 총이지만, 적어도 하나가 보장하는 경우, 당신은 할 수 있습니다 :

    이것은 총이지만, 적어도 하나가 보장하는 경우, 당신은 할 수 있습니다 :

    SELECT ...
           ...
     WHERE tag IN( @tag1, ISNULL( @tag2, @tag1 ), ISNULL( @tag3, @tag1 ), etc. )
    

    IN 갖는 ( 'tag1로', 'tag2로', 'tag1로', 'tag1로를', 'tag1로')가 쉽게 SQL Server에서 멀리 최적화 될 것이다. 게다가, 당신은 직접 인덱스가 추구 얻을

  12. ==============================

    12.제 생각에는,이 문제를 해결하는 가장 좋은 소스는이 사이트에 게시 된 내용입니다 :

    제 생각에는,이 문제를 해결하는 가장 좋은 소스는이 사이트에 게시 된 내용입니다 :

    Siskomaiments. 아민 정책

    CREATE FUNCTION dbo.fnParseArray (@Array VARCHAR(1000),@separator CHAR(1))
    RETURNS @T Table (col1 varchar(50))
    AS 
    BEGIN
     --DECLARE @T Table (col1 varchar(50))  
     -- @Array is the array we wish to parse
     -- @Separator is the separator charactor such as a comma
     DECLARE @separator_position INT -- This is used to locate each separator character
     DECLARE @array_value VARCHAR(1000) -- this holds each array value as it is returned
     -- For my loop to work I need an extra separator at the end. I always look to the
     -- left of the separator character for each array value
    
     SET @array = @array + @separator
    
     -- Loop through the string searching for separtor characters
     WHILE PATINDEX('%' + @separator + '%', @array) <> 0 
     BEGIN
        -- patindex matches the a pattern against a string
        SELECT @separator_position = PATINDEX('%' + @separator + '%',@array)
        SELECT @array_value = LEFT(@array, @separator_position - 1)
        -- This is where you process the values passed.
        INSERT into @T VALUES (@array_value)    
        -- Replace this select statement with your processing
        -- @array_value holds the value of this element of the array
        -- This replaces what we just processed with and empty string
        SELECT @array = STUFF(@array, 1, @separator_position, '')
     END
     RETURN 
    END
    

    사용하다:

    SELECT * FROM dbo.fnParseArray('a,b,c,d,e,f', ',')
    

    용 대출 : 아민, 영원한

  13. ==============================

    13.나는 (그것을 SQL 서버 2008 이후) 테이블 형식의 매개 변수를 전달하고, 존재, 또는 내부 조인 어디 할 것입니다. 당신은 또한 다음 임시 테이블 심지어 인덱스를 sp_xml_preparedocument를 사용하여 XML을 사용하고 있습니다.

    나는 (그것을 SQL 서버 2008 이후) 테이블 형식의 매개 변수를 전달하고, 존재, 또는 내부 조인 어디 할 것입니다. 당신은 또한 다음 임시 테이블 심지어 인덱스를 sp_xml_preparedocument를 사용하여 XML을 사용하고 있습니다.

  14. ==============================

    14.적절한 방법 이럴 (어떤 DBMS 지원에 의해 길이 제한) 문자열의 목록을 저장하는 것입니다; 유일한 트릭 (단순화하기 위해 처리) I는 초기에 상기 문자열의 끝 부분에 세퍼레이터 (예 내에서 쉼표)를 가지고있다. 아이디어는 값 당 하나 개의 행을 포함하는 하나의 열 테이블에 목록을 선회, "즉시 정상화"이다. 이것은 당신이 끌 수 있습니다

    적절한 방법 이럴 (어떤 DBMS 지원에 의해 길이 제한) 문자열의 목록을 저장하는 것입니다; 유일한 트릭 (단순화하기 위해 처리) I는 초기에 상기 문자열의 끝 부분에 세퍼레이터 (예 내에서 쉼표)를 가지고있다. 아이디어는 값 당 하나 개의 행을 포함하는 하나의 열 테이블에 목록을 선회, "즉시 정상화"이다. 이것은 당신이 끌 수 있습니다

    아니면 그냥 목록에서 중복 값 문제를 피하기 위해 "구별"을 추가하는 경우, 일반 가입 (아마 원합니다 솔루션).

    불행하게도, 문자열을 슬라이스하는 기술은 상당히 제품 별입니다. 다음은 SQL Server 버전은 다음과 같습니다

     with qry(n, names) as
           (select len(list.names) - len(replace(list.names, ',', '')) - 1 as n,
                   substring(list.names, 2, len(list.names)) as names
            from (select ',Doc,Grumpy,Happy,Sneezy,Bashful,Sleepy,Dopey,' names) as list
            union all
            select (n - 1) as n,
                   substring(names, 1 + charindex(',', names), len(names)) as names
            from qry
            where n > 1)
     select n, substring(names, 1, charindex(',', names) - 1) dwarf
     from qry;
    

    오라클 버전 :

     select n, substr(name, 1, instr(name, ',') - 1) dwarf
     from (select n,
                 substr(val, 1 + instr(val, ',', 1, n)) name
          from (select rownum as n,
                       list.val
                from  (select ',Doc,Grumpy,Happy,Sneezy,Bashful,Sleepy,Dopey,' val
                       from dual) list
                connect by level < length(list.val) -
                                   length(replace(list.val, ',', ''))));
    

    그리고 MySQL 버전 :

    select pivot.n,
          substring_index(substring_index(list.val, ',', 1 + pivot.n), ',', -1) from (select 1 as n
         union all
         select 2 as n
         union all
         select 3 as n
         union all
         select 4 as n
         union all
         select 5 as n
         union all
         select 6 as n
         union all
         select 7 as n
         union all
         select 8 as n
         union all
         select 9 as n
         union all
         select 10 as n) pivot,    (select ',Doc,Grumpy,Happy,Sneezy,Bashful,Sleepy,Dopey,' val) as list where pivot.n <  length(list.val) -
                       length(replace(list.val, ',', ''));
    

    (물론, "피벗"의 최대 번호로 여러 행으로 반환해야 항목 우리는) ​​목록에서 찾을 수

  15. ==============================

    15.당신은 SQL 서버 2008을 가지고 또는 한 경우 나중에 내가 매개 변수 상당의 표를 사용하십시오.

    당신은 SQL 서버 2008을 가지고 또는 한 경우 나중에 내가 매개 변수 상당의 표를 사용하십시오.

    당신이 운이 충분가 SQL 서버 2005에 부착 할 경우이 같은 CLR 기능을 추가 할 수 있습니다,

    [SqlFunction(
        DataAccessKind.None,
        IsDeterministic = true,
        SystemDataAccess = SystemDataAccessKind.None,
        IsPrecise = true,
        FillRowMethodName = "SplitFillRow",
        TableDefinintion = "s NVARCHAR(MAX)"]
    public static IEnumerable Split(SqlChars seperator, SqlString s)
    {
        if (s.IsNull)
            return new string[0];
    
        return s.ToString().Split(seperator.Buffer);
    }
    
    public static void SplitFillRow(object row, out SqlString s)
    {
        s = new SqlString(row.ToString());
    }
    

    이처럼 사용할 수있는,

    declare @desiredTags nvarchar(MAX);
    set @desiredTags = 'ruby,rails,scruffy,rubyonrails';
    
    select * from Tags
    where Name in [dbo].[Split] (',', @desiredTags)
    order by Count desc
    
  16. ==============================

    16.나는이 정적 쿼리 그냥 갈 방법이없는 경우라고 생각합니다. 동적으로, 당신의 절에 대한 목록을 작성하여 작은 따옴표를 탈출, 동적 SQL을 구축 할 수 있습니다. 이 경우 당신은 아마도 작은 목록에 많은 어떤 방법으로 차이 볼 수 없습니다 만, 가장 효율적인 방법은 정말이 게시물에 기록 된대로 정확하게 SQL을 보낼 수 있습니다. 나는 예쁜 코드를 만드는 일을하거나 동적으로 빌드 SQL 나쁜 관행을 고려하기보다는, 그것을 가장 효율적인 방법을 쓸 수있는 좋은 습관이라고 생각합니다.

    나는이 정적 쿼리 그냥 갈 방법이없는 경우라고 생각합니다. 동적으로, 당신의 절에 대한 목록을 작성하여 작은 따옴표를 탈출, 동적 SQL을 구축 할 수 있습니다. 이 경우 당신은 아마도 작은 목록에 많은 어떤 방법으로 차이 볼 수 없습니다 만, 가장 효율적인 방법은 정말이 게시물에 기록 된대로 정확하게 SQL을 보낼 수 있습니다. 나는 예쁜 코드를 만드는 일을하거나 동적으로 빌드 SQL 나쁜 관행을 고려하기보다는, 그것을 가장 효율적인 방법을 쓸 수있는 좋은 습관이라고 생각합니다.

    나는 분할 기능 매개 변수가 커질 수 많은 경우에 쿼리 자체보다 실행하는 데 시간이 더 걸릴 보았다. 이것은 아마도 귀하의 경우 속도가 느려집니다하지만 SQL 2008에서 테이블 반환 매개 변수가있는 저장 프로 시저, 나는 생각 것이 유일한 옵션입니다. 당신이 TVP의 기본 키를 검색하는 경우 (목록이 큰 경우) SQL 어쨌든 목록에 대한 임시 테이블을 만들 것이기 ​​때문에 TVP는 아마 단지, 큰 목록에 대한 빨라집니다. 당신이 그것을 테스트하지 않는 한 당신은 확실히 알 수 없습니다.

    또한 널의 기본 값으로 500 개 매개 변수를 가지고 저장 프로 시저를 볼, 그리고 한 가지는 WHERE 열 1 IN (3 당겨 @과 Param2 @ Param1을 @,,, ..., @ Param500). 이것은 일종의 / 별개의 수행 SQL은 임시 테이블을 구축 발생하고 테이블 대신 인덱스의 추구 스캔 않습니다. 즉, 비록 그것이 눈에 띄는 차이를 만들하지 않습니다 충분히 작은 규모로, 해당 쿼리를 매개 변수화에 의해 일을 할 것입니다 무슨 본질적이다. 그는 변경하지 의도 한대로 작동하지 않습니다옵니다 것처럼 내가보기 엔 당신의 IN 목록에 NULL을 가지고에 좋습니다. 동적 매개 변수 목록을 만들 수 있지만, 당신이 얻을 것이 유일한 분명한 것은 개체가 당신을 위해 작은 따옴표를 벗어날 것입니다. 객체가 매개 변수를 찾기 위해 쿼리를 구문 분석해야하기 때문에 그 접근법은 또한 응용 프로그램의 끝에 약간 느립니다. 그것은 수도 있고 매개 변수가있는 쿼리가, sp_prepare 전화로 sp_execute 두 몇 번이나 당신이 sp_unprepare 다음에 쿼리를 실행을 위해, 빠른 SQL에하지 않을 수 있습니다.

    저장 프로 시저 또는 매개 변수화 된 쿼리에 대한 실행 계획의 재사용은 당신에게 성능 향상을 줄 수 있지만 하나 개의 실행 계획이 실행되는 첫 번째 쿼리에 의해 결정에 당신을 잠급니다. 즉 많은 경우에 후속 쿼리에 이상적보다 적을 수 있습니다. 귀하의 경우, 실행 계획의 재사용은 아마 플러스하지만, 예를 들어 정말 간단한 쿼리 그대로는 전혀 차이가 없을 수도 있습니다.

    클리프 노트 :

    귀하의 경우에는 아무것도 들어 당신은 많은 차이하지 않습니다 그것을 목록에있는 항목의 고정 된 수의 (사용하지 않는 경우는 null), 동적 매개 변수를 사용하거나 사용하지 않고 쿼리를 구축, 또는 테이블 반환 매개 변수와 저장 프로 시저를 사용으로 매개 변수화 될 않습니다 . 그러나 다음과 같이 내 일반적인 권장 사항은 다음과 같습니다 :

    귀하의 케이스 / 몇 가지 매개 변수를 사용하여 간단한 쿼리 :

    어쩌면 쇼에게 더 나은 성능을 테스트하는 경우 매개 변수를 사용하여 동적 SQL.

    단순히 매개 변수를 변경하거나 쿼리가 복잡하면 여러 번 호출 재사용 가능한 실행 계획과 쿼리 :

    동적 매개 변수를 사용하여 SQL.

    큰 목록 쿼리 :

    테이블 반환 매개 변수와 저장 프로 시저. 목록이 저장 프로 시저에 대한 RECOMPILE 함께 많은 양의 사용으로 변화, 또는 경우 단순히 각 쿼리에 대한 새로운 실행 계획을 생성 매개 변수없이 동적 SQL을 사용합니다.

  17. ==============================

    17.우리가 여기에 XML을 사용할 수 있습니다 될 수 있습니다 :

    우리가 여기에 XML을 사용할 수 있습니다 될 수 있습니다 :

        declare @x xml
        set @x='<items>
        <item myvalue="29790" />
        <item myvalue="31250" />
        </items>
        ';
        With CTE AS (
             SELECT 
                x.item.value('@myvalue[1]', 'decimal') AS myvalue
            FROM @x.nodes('//items/item') AS x(item) )
    
        select * from YourTable where tableColumnName in (select myvalue from cte)
    
  18. ==============================

    18.나는 IN 상태로 테이블 반환 함수 (즉, 반환 문자열에서 테이블을) 통과와 함께 기본적으로이 문제를 접근하는 것입니다.

    나는 IN 상태로 테이블 반환 함수 (즉, 반환 문자열에서 테이블을) 통과와 함께 기본적으로이 문제를 접근하는 것입니다.

    다음은 UDF 코드입니다 (내가 스택 오버플로 어딘가에서 그것을 가지고, 내가 지금 소스를 찾을 수 없습니다)

    CREATE FUNCTION [dbo].[Split] (@sep char(1), @s varchar(8000))
    RETURNS table
    AS
    RETURN (
        WITH Pieces(pn, start, stop) AS (
          SELECT 1, 1, CHARINDEX(@sep, @s)
          UNION ALL
          SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1)
          FROM Pieces
          WHERE stop > 0
        )
        SELECT 
          SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
        FROM Pieces
      )
    

    당신이있어 일단 당신의 코드는 단순하게 될 것이다 :

    select * from Tags 
    where Name in (select s from dbo.split(';','ruby;rails;scruffy;rubyonrails'))
    order by Count desc
    

    당신이 터무니없이 긴 문자열이 없다면,이 테이블 인덱스와 잘 작동합니다.

    당신이 임시 테이블에 삽입 할 수 있습니다 필요한 경우, 인덱스 그 다음 조인을 실행 ...

  19. ==============================

    19.또 다른 가능한 해결책은 대신 저장 프로 시저에 가변 인자를 전달하는, 후 당신 이름을 포함하는 단일 문자열을 전달하지만, '<>'와 그들을 둘러싼하여 그들을 특별하게 만드는 것입니다. 그런 다음 이름을 찾을 수 PATINDEX를 사용 :

    또 다른 가능한 해결책은 대신 저장 프로 시저에 가변 인자를 전달하는, 후 당신 이름을 포함하는 단일 문자열을 전달하지만, '<>'와 그들을 둘러싼하여 그들을 특별하게 만드는 것입니다. 그런 다음 이름을 찾을 수 PATINDEX를 사용 :

    SELECT * 
    FROM Tags 
    WHERE PATINDEX('%<' + Name + '>%','<jo>,<john>,<scruffy>,<rubyonrails>') > 0
    
  20. ==============================

    20.다음 저장 프로 시저를 사용합니다. 그것은 여기에서 찾을 수 있습니다 사용자 정의 분할 기능을 사용합니다.

    다음 저장 프로 시저를 사용합니다. 그것은 여기에서 찾을 수 있습니다 사용자 정의 분할 기능을 사용합니다.

     create stored procedure GetSearchMachingTagNames 
        @PipeDelimitedTagNames varchar(max), 
        @delimiter char(1) 
        as  
        begin
             select * from Tags 
             where Name in (select data from [dbo].[Split](@PipeDelimitedTagNames,@delimiter) 
        end
    
  21. ==============================

    21.우리는 쉼표 IN 절 내부에 저장된 문자열이있는 경우 (,) 우리가 값을 얻기 위해 charIndex의 기능을 사용할 수 있습니다 구분. 당신이 .NET을 사용하는 경우, 당신은 SqlParameters로 매핑 할 수 있습니다.

    우리는 쉼표 IN 절 내부에 저장된 문자열이있는 경우 (,) 우리가 값을 얻기 위해 charIndex의 기능을 사용할 수 있습니다 구분. 당신이 .NET을 사용하는 경우, 당신은 SqlParameters로 매핑 할 수 있습니다.

    DDL 스크립트 :

    CREATE TABLE Tags
        ([ID] int, [Name] varchar(20))
    ;
    
    INSERT INTO Tags
        ([ID], [Name])
    VALUES
        (1, 'ruby'),
        (2, 'rails'),
        (3, 'scruffy'),
        (4, 'rubyonrails')
    ;
    

    T-SQL :

    DECLARE @Param nvarchar(max)
    
    SET @Param = 'ruby,rails,scruffy,rubyonrails'
    
    SELECT * FROM Tags
    WHERE CharIndex(Name,@Param)>0
    

    당신은 당신의 .NET 코드에서 위의 문을 사용하여 SqlParameter에와 매개 변수를 매핑 할 수 있습니다.

    피들러 데모

    편집하다: 다음 스크립트를 사용하여 SelectedTags라는 테이블을 만듭니다.

    DDL 스크립트 :

    Create table SelectedTags
    (Name nvarchar(20));
    
    INSERT INTO SelectedTags values ('ruby'),('rails')
    

    T-SQL :

    DECLARE @list nvarchar(max)
    SELECT @list=coalesce(@list+',','')+st.Name FROM SelectedTags st
    
    SELECT * FROM Tags
    WHERE CharIndex(Name,@Param)>0
    
  22. ==============================

    22.이 유일한 방법처럼 가변 인자를 들어 내가하는 것입니다 알고 있어요 명시 적으로 SQL을 생성하거나 원하는 항목으로 임시 테이블을 채우고 임시 테이블에 합류 포함 뭔가.

    이 유일한 방법처럼 가변 인자를 들어 내가하는 것입니다 알고 있어요 명시 적으로 SQL을 생성하거나 원하는 항목으로 임시 테이블을 채우고 임시 테이블에 합류 포함 뭔가.

  23. ==============================

    23.ColdFusion에서 우리는 할 :

    ColdFusion에서 우리는 할 :

    <cfset myvalues = "ruby|rails|scruffy|rubyonrails">
        <cfquery name="q">
            select * from sometable where values in <cfqueryparam value="#myvalues#" list="true">
        </cfquery>
    
  24. ==============================

    24.다음은 쿼리 문자열에 사용되는 로컬 테이블을 재현하는 기술이다. 이런 식으로 이렇게하면 모든 구문 분석 문제가 없습니다.

    다음은 쿼리 문자열에 사용되는 로컬 테이블을 재현하는 기술이다. 이런 식으로 이렇게하면 모든 구문 분석 문제가 없습니다.

    문자열은 어떤 언어로 만들 수 있습니다. 그게 내가 해결하기 위해 노력했다 원래의 문제 이후이 예에서 나는 SQL을 사용했다. 나중에 실행되는 문자열에 즉석에서 테이블 데이터를 전달하기 위해 깨끗한 방법이 필요했습니다.

    사용자 정의 형식을 사용하는 것은 선택 사항입니다. 유형을 생성 한 번만 생성되고 사전에 수행 할 수 있습니다. 그렇지 않으면 단지 문자열의 선언에 전체 테이블 유형을 추가 할 수 있습니다.

    일반적인 패턴 확장이 용이하고보다 복잡한 테이블을 전달하는 데 사용될 수있다.

    -- Create a user defined type for the list.
    CREATE TYPE [dbo].[StringList] AS TABLE(
        [StringValue] [nvarchar](max) NOT NULL
    )
    
    -- Create a sample list using the list table type.
    DECLARE @list [dbo].[StringList]; 
    INSERT INTO @list VALUES ('one'), ('two'), ('three'), ('four')
    
    -- Build a string in which we recreate the list so we can pass it to exec
    -- This can be done in any language since we're just building a string.
    DECLARE @str nvarchar(max);
    SET @str = 'DECLARE @list [dbo].[StringList]; INSERT INTO @list VALUES '
    
    -- Add all the values we want to the string. This would be a loop in C++.
    SELECT @str = @str + '(''' + StringValue + '''),' FROM @list
    
    -- Remove the trailing comma so the query is valid sql.
    SET @str = substring(@str, 1, len(@str)-1)
    
    -- Add a select to test the string.
    SET @str = @str + '; SELECT * FROM @list;'
    
    -- Execute the string and see we've pass the table correctly.
    EXEC(@str)
    
  25. ==============================

    25.SQL 서버에서 2016+ 또 다른 가능성은 OPENJSON 기능을 사용하는 것입니다.

    SQL 서버에서 2016+ 또 다른 가능성은 OPENJSON 기능을 사용하는 것입니다.

    이 방법은 OPENJSON에 대한 블로그입니다 - 가장 좋은 방법 중 하나는 ID의 목록을 사용하여 행을 선택합니다.

    아래의 전체 일 예

    CREATE TABLE dbo.Tags
      (
         Name  VARCHAR(50),
         Count INT
      )
    
    INSERT INTO dbo.Tags
    VALUES      ('VB',982), ('ruby',1306), ('rails',1478), ('scruffy',1), ('C#',1784)
    
    GO
    
    CREATE PROC dbo.SomeProc
    @Tags VARCHAR(MAX)
    AS
    SELECT T.*
    FROM   dbo.Tags T
    WHERE  T.Name IN (SELECT J.Value COLLATE Latin1_General_CI_AS
                      FROM   OPENJSON(CONCAT('[', @Tags, ']')) J)
    ORDER  BY T.Count DESC
    
    GO
    
    EXEC dbo.SomeProc @Tags = '"ruby","rails","scruffy","rubyonrails"'
    
    DROP TABLE dbo.Tags 
    
  26. ==============================

    26.여기에 또 다른 대안이다. 그냥 저장 프로 시저 및에 문자열 매개 변수로 쉼표로 구분 된 목록을 전달합니다

    여기에 또 다른 대안이다. 그냥 저장 프로 시저 및에 문자열 매개 변수로 쉼표로 구분 된 목록을 전달합니다

    CREATE PROCEDURE [dbo].[sp_myproc]
        @UnitList varchar(MAX) = '1,2,3'
    AS
    select column from table
    where ph.UnitID in (select * from CsvToInt(@UnitList))
    

    그리고 기능 :

    CREATE Function [dbo].[CsvToInt] ( @Array varchar(MAX))
    returns @IntTable table
    (IntValue int)
    AS
    begin
        declare @separator char(1)
        set @separator = ','
        declare @separator_position int
        declare @array_value varchar(MAX)
    
        set @array = @array + ','
    
        while patindex('%,%' , @array) <> 0
        begin
    
            select @separator_position = patindex('%,%' , @array)
            select @array_value = left(@array, @separator_position - 1)
    
            Insert @IntTable
            Values (Cast(@array_value as int))
            select @array = stuff(@array, 1, @separator_position, '')
        end
        return
    end
    
  27. ==============================

    27.나는 UDF를 필요로하지 않는 대답을, XML IN은 SELECT 문을 허용하기 때문에 예를 들면 시험 SELECT * FROM 경우 데이터 IN (SELECT 값 테이블에서)

    나는 UDF를 필요로하지 않는 대답을, XML IN은 SELECT 문을 허용하기 때문에 예를 들면 시험 SELECT * FROM 경우 데이터 IN (SELECT 값 테이블에서)

    당신은 정말에만 테이블에 문자열을 변환하는 방법이 필요합니다.

    이것은 재귀 CTE 함께 할, 또는 숫자 테이블 쿼리 (또는 Master..spt_value) 할 수있다

    여기에 CTE 버전입니다.

    DECLARE @InputString varchar(8000) = 'ruby,rails,scruffy,rubyonrails'
    
    SELECT @InputString = @InputString + ','
    
    ;WITH RecursiveCSV(x,y) 
    AS 
    (
        SELECT 
            x = SUBSTRING(@InputString,0,CHARINDEX(',',@InputString,0)),
            y = SUBSTRING(@InputString,CHARINDEX(',',@InputString,0)+1,LEN(@InputString))
        UNION ALL
        SELECT 
            x = SUBSTRING(y,0,CHARINDEX(',',y,0)),
            y = SUBSTRING(y,CHARINDEX(',',y,0)+1,LEN(y))
        FROM 
            RecursiveCSV 
        WHERE
            SUBSTRING(y,CHARINDEX(',',y,0)+1,LEN(y)) <> '' OR 
            SUBSTRING(y,0,CHARINDEX(',',y,0)) <> ''
    )
    SELECT
        * 
    FROM 
        Tags
    WHERE 
        Name IN (select x FROM RecursiveCSV)
    OPTION (MAXRECURSION 32767);
    
  28. ==============================

    28.나는 정상보다 간결 버전이 대답을 투표를 사용 :

    나는 정상보다 간결 버전이 대답을 투표를 사용 :

    List<SqlParameter> parameters = tags.Select((s, i) => new SqlParameter("@tag" + i.ToString(), SqlDbType.NVarChar(50)) { Value = s}).ToList();
    
    var whereCondition = string.Format("tags in ({0})", String.Join(",",parameters.Select(s => s.ParameterName)));
    

    그것은 두 번 태그 매개 변수를 통해 루프를 수행; 하지만이 문제에 대부분의 시간을하지 않습니다 (그것은 당신의 병목되지 않습니다, 그것은 경우, 루프를 풀다).

    성능에 정말 관심이 두 번 루프를 반복하지 않으려면, 여기 덜 아름다운 버전입니다 :

    var parameters = new List<SqlParameter>();
    var paramNames = new List<string>();
    for (var i = 0; i < tags.Length; i++)  
    {
        var paramName = "@tag" + i;
    
        //Include size and set value explicitly (not AddWithValue)
        //Because SQL Server may use an implicit conversion if it doesn't know
        //the actual size.
        var p = new SqlParameter(paramName, SqlDbType.NVarChar(50) { Value = tags[i]; } 
        paramNames.Add(paramName);
        parameters.Add(p);
    }
    
    var inClause = string.Join(",", paramNames);
    
  29. ==============================

    29.다음은이 문제에 대한 다른 답변입니다.

    다음은이 문제에 대한 다른 답변입니다.

    (새로운 버전은 6/4/13에 게시).

        private static DataSet GetDataSet(SqlConnectionStringBuilder scsb, string strSql, params object[] pars)
        {
            var ds = new DataSet();
            using (var sqlConn = new SqlConnection(scsb.ConnectionString))
            {
                var sqlParameters = new List<SqlParameter>();
                var replacementStrings = new Dictionary<string, string>();
                if (pars != null)
                {
                    for (int i = 0; i < pars.Length; i++)
                    {
                        if (pars[i] is IEnumerable<object>)
                        {
                            List<object> enumerable = (pars[i] as IEnumerable<object>).ToList();
                            replacementStrings.Add("@" + i, String.Join(",", enumerable.Select((value, pos) => String.Format("@_{0}_{1}", i, pos))));
                            sqlParameters.AddRange(enumerable.Select((value, pos) => new SqlParameter(String.Format("@_{0}_{1}", i, pos), value ?? DBNull.Value)).ToArray());
                        }
                        else
                        {
                            sqlParameters.Add(new SqlParameter(String.Format("@{0}", i), pars[i] ?? DBNull.Value));
                        }
                    }
                }
                strSql = replacementStrings.Aggregate(strSql, (current, replacementString) => current.Replace(replacementString.Key, replacementString.Value));
                using (var sqlCommand = new SqlCommand(strSql, sqlConn))
                {
                    if (pars != null)
                    {
                        sqlCommand.Parameters.AddRange(sqlParameters.ToArray());
                    }
                    else
                    {
                        //Fail-safe, just in case a user intends to pass a single null parameter
                        sqlCommand.Parameters.Add(new SqlParameter("@0", DBNull.Value));
                    }
                    using (var sqlDataAdapter = new SqlDataAdapter(sqlCommand))
                    {
                        sqlDataAdapter.Fill(ds);
                    }
                }
            }
            return ds;
        }
    

    건배.

  30. ==============================

    30.유일한 승리 이동 재생에 없습니다.

    유일한 승리 이동 재생에 없습니다.

    당신에 대한 무한한 가변성이 없습니다. 만 유한 변화.

    는 SQL에서는이 같은 조항이있다 :

    and ( {1}==0 or b.CompanyId in ({2},{3},{4},{5},{6}) )
    

    C # 코드에서 당신은 같은 것을 할 :

      int origCount = idList.Count;
      if (origCount > 5) {
        throw new Exception("You may only specify up to five originators to filter on.");
      }
      while (idList.Count < 5) { idList.Add(-1); }  // -1 is an impossible value
      return ExecuteQuery<PublishDate>(getValuesInListSQL, 
                   origCount,   
                   idList[0], idList[1], idList[2], idList[3], idList[4]);
    

    그래서 기본적으로 카운트가 0 인 경우가 더 필터없는 모든 것을 통해 간다. 카운트가 0보다 큰 경우 값이 목록에 있어야하지만,리스트 (SQL은 여전히 ​​의미가 그래서) 불가능 값이 오에게 패딩 된

    때로는 절름발이 솔루션은 실제로 작동하는 유일한 하나입니다.

  31. from https://stackoverflow.com/questions/337704/parameterize-an-sql-in-clause by cc-by-sa and MIT license