2013-07-16 3 views
0

У меня есть следующая переменная.Найти подстроку/charindex T-sql

DECLARE @TestConnectionString varchar(255) = 'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 

Я хочу выделить значения каждого свойства из этой строки соединения.

Уверен, что я должен использовать SUBSTRING и CHARINDEX, но не знаю, как. Я не хочу жестко кодировать длину для каждого свойства, поскольку user_id может быть "Comeonedude"

Может ли кто-нибудь показать мне, как я могу извлечь некоторые из этих свойств в качестве примера?

В то же время я попытаюсь посмотреть, смогу ли я что-нибудь выяснить.

Спасибо

+1

http://stackoverflow.com/questions/2647/split-string-in-sql –

ответ

1

Мне нравится использовать листинг XML для разделения строк в TSQL. Этот метод является предпочтительным, поскольку он не требует от вас создания функций разделения строк по всему месту и по моему опыту, который он выполняет и хорошо масштабируется. Вот пример SQLFiddle.

DECLARE @TestConnectionString varchar(255) = 'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 

SELECT 
    t.c.value('(property)[1]','VARCHAR(200)') AS [property] 
    ,t.c.value('(value)[1]','VARCHAR(200)') AS [value] 
FROM (
    SELECT CAST('<root><pair><property>' + REPLACE(REPLACE(LEFT(@TestConnectionString,LEN(@TestConnectionString)-1),';','</value></pair><pair><property>'),'=','</property><value>') + '</value></pair></root>' AS XML) AS properties_xml 
) AS i 
CROSS APPLY i.properties_xml.nodes('/root/pair') AS t(c) 

Объяснение:

@TestConnectionString отформатирован как документ XML с помощью этого оператора выбора:

SELECT CAST('<root><pair><property>' + REPLACE(REPLACE(LEFT(@TestConnectionString,LEN(@TestConnectionString)-1),';','</value></pair><pair><property>'),'=','</property><value>') + '</value></pair></root>' AS XML) AS properties_xml 

Строка XML начинается с <root><pair><property>, то функция REPLACE заменяет каждый из разграничивающих точка с запятой </value></pair><pair><property> и заменяет каждый из разделительных знаков равенства </property><value>. @TestConnectionString заканчивается точкой с запятой, так что точка с запятой должна быть сначала удалена функцией LEFT, иначе мы получим дополнительный </value></pair><pair><property> в конце нашей строки XML. Строка XML завершается добавлением </value></pair></root>, и мы в конечном итоге с этим:

<root> 
    <pair> 
    <property>Data Source</property> 
    <value>123.45.67.890</value> 
    </pair> 
    <pair> 
    <property>User ID</property> 
    <value>TestUser</value> 
    </pair> 
    <pair> 
    <property>Password</property> 
    <value>TestPassword</value> 
    </pair> 
    <pair> 
    <property>Initial Catalog</property> 
    <value>TestCatalogName</value> 
    </pair> 
    <pair> 
    <property>Provider</property> 
    <value>SQLNCLI11.1</value> 
    </pair> 
    <pair> 
    <property>Persist Security Info</property> 
    <value>True</value> 
    </pair> 
    <pair> 
    <property>Auto Translate</property> 
    <value>False</value> 
    </pair> 
</root> 

строка XML преобразуется в тип XML данных с функцией CAST. Оператор CROSS APPLY может использоваться для преобразования узлов XML-документа в объект, подобный таблице (с псевдонимом t) с строками и столбцами (с псевдонимом c).

CROSS APPLY i.properties_xml.nodes('/root/pair') AS t(c) 

Теперь у нас есть таблица со строками, представляющими каждый узел пары в документе XML. Эта таблица может быть выбрана с помощью функции value, чтобы назначить тип данных для каждого столбца, который мы хотим выбрать.

SELECT 
    t.c.value('(property)[1]','VARCHAR(200)') AS [property] 
    ,t.c.value('(value)[1]','VARCHAR(200)') AS [value] 
+0

это очень хороший подход. –

+0

Спасибо за это ... маленький код, но очень уникальный подход. :) – 007

+0

Попытка выяснить, что происходит ... очень смущенно, но очень любопытно .. Вспомните ваш метод немного больше? Это удивительно ... нет необходимости в других объектах (т. Е. Udf), что было бы очень удобно при работе в нескольких средах sql ... хотелось бы отметить несколько комментариев в качестве ответов. – 007

2

Сначала разделите строку на ';' .. Вы можете найти много функций Split онлайн. Используйте тот, который разбивает его на таблицу.

После кода от: How to split string using delimiter char using T-SQL?

CREATE FUNCTION [dbo].[Split] 
( 
@String varchar(max) 
,@Delimiter char =';' -- default value 
) 
RETURNS @Results table 
(
Ordinal int 
,StringValue varchar(max) 
) 
as 
begin 

    set @String = isnull(@String,'') 
    set @Delimiter = isnull(@Delimiter,'') 

    declare 
    @TempString varchar(max) = @String 
    ,@Ordinal int = 0 
    ,@CharIndex int = 0 

    set @CharIndex = charindex(@Delimiter, @TempString) 
    while @CharIndex != 0 begin  
     set @Ordinal += 1  
     insert @Results values 
     (
     @Ordinal 
     ,substring(@TempString, 0, @CharIndex) 
     )  
     set @TempString = substring(@TempString, @CharIndex + 1, len(@TempString) - @CharIndex)  
     set @CharIndex = charindex(@Delimiter, @TempString) 
    end 

    if @TempString != '' begin 
     set @Ordinal += 1 
     insert @Results values 
     (
     @Ordinal 
     ,@TempString 
     ) 
    end 

    return 
end 

предполагая порядок всегда одинакова, разделить каждый из resutls на «=». принять правильную часть каждой строки (длина оставшейся строки после «=»).

et voilà, у вас есть все имущество с его стоимостью.

- EDIT: С расщепленной функции сверху:

DECLARE @TestConnectionString varchar(255) = 'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 

create table #result 
(
property varchar(255), 
Value varchar(255) 
) 

create table #tmp 
(
Property varchar(255) 
) 

create table #tmp2 
(
Value varchar(255) 
) 

insert into #tmp 
select * from split(@TestConnectionString, ';') 


--select * from #tmp 

/* Sclaufe */ 
declare @id varchar(255) 

DECLARE a_coursor CURSOR FOR 
select property from #tmp 
OPEN a_coursor; 
FETCH NEXT FROM a_coursor into  @id; 
WHILE @@FETCH_STATUS = 0 
BEGIN 

    -- select @id 
    insert into #tmp2 
    select * from Split(@id, '=') 

FETCH NEXT FROM a_coursor 
INTO  @id 
END; 
CLOSE a_coursor; 
DEALLOCATE a_coursor; 


select * from #tmp2 

/* Sclaufe */ 
declare @id2 varchar(255) 
declare @oldid varchar(255) 
declare @count int 
set @count = 1 

DECLARE a_coursor CURSOR FOR 
select value from #tmp2 
OPEN a_coursor; 
FETCH NEXT FROM a_coursor into  @id2; 
WHILE @@FETCH_STATUS = 0 
BEGIN 

    print @id2 

    if @count % 2 <> 0 
    begin 
     insert into #result 
     select @id2, '' 

     set @oldid = @id2 
    end 
    else 
    begin 
     update #result 
     set Value = @id2 
     where property = @oldid 
    end 

    set @count = @count + 1 

FETCH NEXT FROM a_coursor 
INTO  @id2 
END; 
CLOSE a_coursor; 
DEALLOCATE a_coursor; 

select * from #result 


drop table #tmp 
drop table #tmp2 
drop table #result 

Результат будет в #ressult таблице:

╔═══════════════════════╦═════════════════╗ 
║  property  ║  Value  ║ 
╠═══════════════════════╬═════════════════╣ 
║ Data Source   ║ 123.45.67.890 ║ 
║ User ID    ║ TestUser  ║ 
║ Password    ║ TestPassword ║ 
║ Initial Catalog  ║ TestCatalogName ║ 
║ Provider    ║ SQLNCLI11.1  ║ 
║ Persist Security Info ║ True   ║ 
║ Auto Translate  ║ False   ║ 
╚═══════════════════════╩═════════════════╝ 

EDIT: Или вы можете создать хранимую процедуру:

if exists (select 1 from sysobjects where name = 'getvalue2' and type = 'P') 
begin 
    drop procedure getvalue2 
    print 'Procedure: getvalue2 deleted ...' 
end 
go 

/* 
exec getvalue2 'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 
*/ 
create procedure [dbo].[getvalue2] 
( @TestConnectionString varchar(255)) 
as 
begin 

    --= 'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 

    create table #result 
    (
    property varchar(255), 
    Value varchar(255) 
    ) 

    create table #tmp 
    (
    firstrun varchar(255) 
    ) 

    create table #tmp2 
    (
    secondrun varchar(255) 
    ) 

    insert into #tmp 
    select * from split(@TestConnectionString, ';') 


    --select * from #tmp 

    declare @id varchar(255) 

    DECLARE a_coursor CURSOR FOR 
    select firstrun from #tmp 
    OPEN a_coursor; 
    FETCH NEXT FROM a_coursor into  @id; 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     insert into #tmp2 
     select * from Split(@id, '=') 

    FETCH NEXT FROM a_coursor 
    INTO  @id 
    END; 
    CLOSE a_coursor; 
    DEALLOCATE a_coursor; 

    declare @id2 varchar(255) 
    declare @oldid varchar(255) 
    declare @count int 
    set @count = 1 

    DECLARE a_coursor CURSOR FOR 
    select secondrun from #tmp2 
    OPEN a_coursor; 
    FETCH NEXT FROM a_coursor into  @id2; 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     print @id2 

     if @count % 2 <> 0 
     begin 
      insert into #result 
      select @id2, '' 

      set @oldid = @id2 
     end 
     else 
     begin 
      update #result 
      set Value = @id2 
      where property = @oldid 
     end 

     set @count = @count + 1 

    FETCH NEXT FROM a_coursor 
    INTO  @id2 
    END; 
    CLOSE a_coursor; 
    DEALLOCATE a_coursor; 

    select * from #result 
end 

развлекаются, Вы Wellcome =)

+0

К сожалению, вы не можете предположить порядок одно и то же. – Anon

+0

Тем не менее у вас будет одна таблица со свойствами как «property = value, property = value ...», поэтому вы можете легко принять участие до «» »в качестве имени переменной для следующего разделения. –

+0

Теперь все, что вы нужно сделать немного, так что будут приняты пустые значения и другие специальные вещи. –

1

Вот общий подход можно использовать, если вы действительно хотите использовать SUBSTRING без жестко закодированных чисел:

DECLARE @TestConnectionString varchar(255) = 'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 
SELECT SUBSTRING(@TestConnectionString,CHARINDEX('ID=',@TestConnectionString)+3,CHARINDEX(';Password',@TestConnectionString)-CHARINDEX('ID=',@TestConnectionString)-3) 'User ID' 
     ,SUBSTRING(@TestConnectionString,CHARINDEX(';Password=',@TestConnectionString)+10,CHARINDEX(';Initial',@TestConnectionString)-CHARINDEX(';Password=',@TestConnectionString)-10) 'Password' 

подход, как это может потерпеть неудачу, если есть несоответствия в ваших строк, это может быть стоит Расщепление строка в поля на основе разделителя ;.

+0

Да, спасибо за вашу помощь в этом и указав некоторые улучшения . – 007

1

Если вы заботитесь о рекурсии, SQL-сервер может справиться с этим. Я переписал РКТО запрос (еще раз) я использую в другом проекте, чтобы извлечь значения:

DECLARE @Test varchar(255) = 
'Data Source=123.45.67.890;User ID=TestUser;Password=TestPassword;Initial Catalog=TestCatalogName;Provider=SQLNCLI11.1;Persist Security Info=True;Auto Translate=False;' 

;WITH T AS (
    SELECT 
    StartIdx = CAST(0 as int), 
    EndIdx = CAST(0 as int), 
    Result = CAST('' as nvarchar(max)) 
    UNION ALL 
    SELECT 
    StartIdx = CAST(newstartidx AS int), 
    EndIdx = CAST(EndIdx + newendidx as int), 
    Result = CAST(newtoken as nvarchar(max)) 
    FROM 
    T 
    CROSS APPLY(
     SELECT newstartidx = EndIdx + 1 
    ) calc1 
    CROSS APPLY(
     SELECT newtxt = substring(@Test, newstartidx, len(@Test)) 
    ) calc2 
    CROSS APPLY(
     SELECT patidx = charindex(';', newtxt) 
    ) calc3 
    CROSS APPLY(
     SELECT newendidx = CASE 
     WHEN patidx = 0 THEN len(newtxt) 
     ELSE patidx END 
    ) calc4 
    CROSS APPLY(
     SELECT newtoken = substring(@Test, newstartidx, newendidx) 
    ) calc5 
    WHERE newendidx > 0 
) 
SELECT 
    --Result, 
    Name = left(Result, idx - 1), 
    Value = substring(Result, idx + 1, len(Result) - idx - 1) 
FROM 
    T 
    CROSS APPLY (
    SELECT idx = charindex('=', Result) 
) calc6 
WHERE StartIdx != 0 
+0

Это также работает ВЕЛИКИЙ!!! Спасибо – 007

1

Использование обобщенной функции строки расщепления дважды (см. Ниже) Вызовите его один раз, чтобы разделить пары имя-значение и снова, чтобы отделить имена от значений.

в действии: http://sqlfiddle.com/#!3/3cce5/1/0

SELECT 
    t3.[1] AS name, 
    t3.[2] AS value 
FROM dbo.strsplit(@TestConnectionString,';') t1 
CROSS APPLY dbo.strsplit(t1.col,'=') t2 
PIVOT(MAX(t2.col) FOR t2.n IN ([1],[2])) t3 

Моя строка-сплит функции.

CREATE FUNCTION [dbo].[strsplit](
    @str varchar(max), --String to be split 
    @dlm char(1)  --Delimiting character 
) 
RETURNS TABLE 
RETURN (
WITH [cols] AS (
    SELECT 
    1 AS [n], 
    CAST(1 AS bigint) AS [idx], 
    CHARINDEX(@dlm,@str,1) AS [ndx] 
    UNION ALL 
    SELECT 
    [n] + 1, 
    CHARINDEX(@dlm,@str,[idx]) + 1, 
    CHARINDEX(@dlm,@str,[ndx] + 1) 
    FROM [cols] 
    WHERE CHARINDEX(@dlm,@str,[idx]) > 0 
) 
SELECT 
    [n], 
    CASE [ndx] 
    WHEN 0 THEN SUBSTRING(@str,[idx],LEN(@str)-[idx]+1) 
    ELSE SUBSTRING(@str,[idx],[ndx]-[idx]) 
    END AS [col] 
FROM [cols]) 
+0

Спасибо, что поделились этим методом, я отдам его. :) – 007

Смежные вопросы