Строка SQL с разделителями-запятыми - PullRequest
5 голосов
/ 22 февраля 2010

У меня есть эта строка, которую я получаю из приложения .net А, В, С, D, Е, F,

Я хотел написать оператор выбора sql, например

set @string = 'A,B,C,D,E,F'

select * from tbl_test 
where tbl_test.code in (@string)

Это не будет работать в t-SQL, потому что он использует @string как одну строку, но не разделяет значения. Есть ли способы, которыми я могу сделать это?

Ответы [ 11 ]

2 голосов
/ 22 февраля 2010

Очень часто задаваемый вопрос! То, что вы хотите - это табличная функция.

Но не изобретай велосипед, написав свой собственный, я нашел десятки только по Гуглингу sql split. Вот один из Microsoft:

http://code.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=StringArrayInput

Я использовал для этого динамический SQL, но это означало, что мне приходилось копать код и копировать его в каждое новое приложение. Теперь мне даже не нужно об этом думать.

2 голосов
/ 22 февраля 2010

3 варианта

  1. Используйте регулярное выражение для замены "," на "", ", чтобы он стал правильным ('A', 'B' ...) списком
  2. Преобразуйте список в XML, а затем проанализируйте XML в вашем SELECT
  3. Напишите функцию SPLIT для преобразования списков, разделенных запятыми, в таблицы
1 голос
/ 22 февраля 2010

Вы можете сделать это действительно просто с помощью встроенных функций sql:

set @string = 'A,B,C,D,E,F'

select * from tbl_test 
where CHARINDEX(ISNULL(tbl_test.code, 'X'), @string) > 0

PATINDEX можно использовать, если вам нужно более одного символа.

1 голос
/ 22 февраля 2010

У вас есть несколько вариантов:

  • Если вы согласны с этим, просто составьте оператор SQL динамически перед вызовом SQL. Существует ограничение на количество значений в операторе IN
  • Использовать Табличный UDF , который разбивает строку и возвращает таблицу. Тогда ваш запрос будет использовать IN или лучше просто JOIN оператор (среди других реализаций я предпочитаю пользовательскую функцию SQL для анализа строки с разделителями ).

Ваш код будет:

select     tbl_test.*
from       tbl_test 
inner join fn_ParseText2Table(@string) x
       on  tbl_test.code = x.txt_value 
  • Поскольку вы используете SQL Server 2005, вы можете написать CLR Табличный UDF , который будет выполнять ту же работу, что и предыдущий UDF, что было бы намного меньше и быстрее, поскольку строковые операции в CLR намного лучше обрабатывал это в SQL.
1 голос
/ 22 февраля 2010

Вот функция, которая возвращает разделенную строку как набор строк

set @string = 'A,B,C,D,E,F'      

select * from tbl_test       
where tbl_test.code in (select r from ftDelimitedAsTable(',',@string )    


  --/*----------------------------------------------------------------
    Create     FUNCTION [dbo].[ftDelimitedAsTable](@dlm char, @string varchar(8000))
    RETURNS 
    --------------------------------------------------------------------------*/
    /*------------------------------------------------------------------------
    declare @dlm  char, @string varchar(1000)
    set @dlm=','; set @string='t1,t2,t3';
    -- tHIS FUNCION RETUNRS IN THE ASCENDING ORDER
    -- 19TH Apr 06
    ------------------------------------------------------------------------*/
    --declare
        @table_var TABLE 
        (id int identity(1,1),
            r varchar(1000) 
         )
    AS
    BEGIN
    -- a.p --
    --Modified  18th Nov. 04

        declare @n int,@i int
        set @n=dbo.fnCountChars(@dlm,@string)+1
        SET @I =1
        while @I <= @N
            begin

                --print '@i='+convert(varchar,@i)+ ' AND INSERTING'
                insert @table_var
                    select dbo.fsDelimitedString(@dlm,@string,@i)
                set @I= @I+1

            end
    --PRINT '*************** ALL DONE'
        if @n =1 insert @TABLE_VAR VALUES(@STRING)
    --select * from @table_var
        delete  from @table_var where r=''
        return
    END


USE [QuickPickDBStaging]
GO
/****** Object:  UserDefinedFunction [dbo].[fsDelimitedString]    Script Date: 02/22/2010 12:31:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

Create function [dbo].[fsDelimitedString](
            @DelimiterStr varchar(100)
            ,@str varchar(4000)
            ,@pos int=1)
 returns varchar(4000)
as
/*
AP -- Dec 2003
Declare @DelimiterStr varchar(4000),@str varchar(4000) ,@pos int
set @delimiterStr = '-'
set @pos=10
set @str ='wd-1-22-333-4444-55555-666666-q-9'
*/
Begin
declare @rx varchar(4000)
set @rx=''; set @pos=@pos-1
IF DBO.fnCountChars(@DelimiterStr,@str) > 0 
    Begin
        if dbo.fnCountChars(@delimiterStr,@str) < @pos
        begin
            set @rx= null
            goto nulls
        end
        declare @i1 int,@tPos int,@ix int

        set @ix=1
        set @tPos=0
        while @tpos <> @pos
        Begin
            set @ix=charindex(@DelimiterStr,@str,@ix+1)
            if @ix > 0 set @tpos=@tpos+1
        end
        set @i1= charindex(@DelimiterStr,@str,@ix+1)
        if @i1=0 
                set @rx=substring(@str,@ix+1,len(@str)-@ix)
        else
            begin
                if @ix=1  
                    set @rx=substring(@str,@ix,@i1-@ix)
                else
                    set @rx= substring(@str,    @ix+1,@i1-@ix-1)        
            end
    --  'print 'ix='+convert(varchar,@ix)+' @i1='+convert(varchar,@i1)+' @rx='+@rx
        RETURN @RX
    end
nulls:  
    RETURN  @rx
end
1 голос
/ 22 февраля 2010

Думаю, что самый простой способ сделать это - динамическое генерирование SQL:

// assuming select is a SqlCommand
string[] values = "A,B,C,D,E,F".Split(',');
StringBuilder query = new StringBuilder();
query.Append("select * from tbl_test where tbl_test.code in (");
int i = 0;
foreach (string value in values) {
    string paramName = "@p" + i++;
    query.Append(paramName);
    select.Parameters.AddWithValue(paramName, value);
}
query.Append(")");
select.CommandText = query.ToString();

// and then execute the select Command
1 голос
/ 22 февраля 2010

Создайте пользовательскую функцию, которая принимает строку в качестве ввода и возвращает таблицу:

create function [dbo].[f_SplitString] (@str as varchar (1000))
returns @t table (value varchar (50))
etc...

Затем настройте оператор Select:

select * from tbl_test 
where tbl_test.code in (select value from f_SplitString(@string))
1 голос
/ 22 февраля 2010

Динамическое предложение IN означает либо:

  1. Преобразование списка через запятую во временную таблицу для присоединения к
  2. Использование динамического SQL (EXEC или EXEC sp_executesql)

Пример динамического SQL


DECLARE @SQL NVARCHAR(4000)

    SET @SQL = 'SELECT * FROM tbl_test t
                 WHERE t.code IN (@string_param)

BEGIN

  EXEC sp_executesql @SQL N'@string_param VARCHAR(100)', @string

END

Имейте в виду, что sp_executesql 2005+ и предпочтительнее, потому что он будет кэшировать план запроса. Прочитайте Проклятие и благословения динамического SQL для более подробной информации, но помните о атаках SQL-инъекций .

0 голосов
/ 30 марта 2015

Я думаю, самый простой способ, как показано ниже,

  • Option1:

    set @string = '''A','B','C','D','E','F'''
    
    Exec ('select * from tbl_test 
    where tbl_test.code in ('+@string+')')
    
  • Option2:

    set @string = '''A','B','C','D','E','F'''
    
    DECLARE @SQL NVARCHAR(MAX)
    
    SET @SQL='select * from tbl_test 
    where tbl_test.code in ('+@string+')'
    
    exec sp_executesql @SQL;
    
0 голосов
/ 28 марта 2013

Я знаю, что это старый вопрос, но я думал, что все равно отправлю ответ. Мне никогда не нравилось передавать строковые значения, разделенные запятыми, поэтому в прошлом я использовал XML и использовал оператор соединения в xml следующим образом:

declare @xml as xml
set @xml = '<v id="key1" /><v id="key2" /><v id="key3" />'
select
    t.*
from
    mytable t join @xml.nodes('/*') x(n)
    on n.value('@id','varchar(50)') = t.mykey
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...