Для того, чтобы правила приоритета работали, сам терминал должен появиться в неоднозначном произведении. Таким образом, вы не можете группировать терминалы в не-терминалы и сохранять возможность использовать правила приоритета.
Можно найти, что решение в SQL Определяемая пользователем Функция Анализирует Разграниченную Строку полезный (от Проект Кода).
можно использовать эту простую логику:
Declare @products varchar(200) = '1|20|3|343|44|6|8765'
Declare @individual varchar(20) = null
WHILE LEN(@products) > 0
BEGIN
IF PATINDEX('%|%', @products) > 0
BEGIN
SET @individual = SUBSTRING(@products,
0,
PATINDEX('%|%', @products))
SELECT @individual
SET @products = SUBSTRING(@products,
LEN(@individual + '|') + 1,
LEN(@products))
END
ELSE
BEGIN
SET @individual = @products
SET @products = NULL
SELECT @individual
END
END
Ну, мой не все, что более простой, но вот код, который я использую, чтобы разделить разграниченную запятой входную переменную на отдельные значения и поместить ее в табличную переменную. Я уверен, что Вы могли изменить это немного, чтобы разделить на основе пространства и затем сделать основной Запрос Select против той табличной переменной для получения результатов.
-- Create temporary table to parse the list of accounting cycles.
DECLARE @tblAccountingCycles table
(
AccountingCycle varchar(10)
)
DECLARE @vchAccountingCycle varchar(10)
DECLARE @intPosition int
SET @vchAccountingCycleIDs = LTRIM(RTRIM(@vchAccountingCycleIDs)) + ','
SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)
IF REPLACE(@vchAccountingCycleIDs, ',', '') <> ''
BEGIN
WHILE @intPosition > 0
BEGIN
SET @vchAccountingCycle = LTRIM(RTRIM(LEFT(@vchAccountingCycleIDs, @intPosition - 1)))
IF @vchAccountingCycle <> ''
BEGIN
INSERT INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle)
END
SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition)
SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)
END
END
понятие является в значительной степени тем же. Еще одна альтернатива должна усилить совместимость.NET в SQL Server сам 2005. Можно по существу записать себе простой метод в.NET, которая разделила бы строку и затем представила бы это как хранимую процедуру / функция.
Попробуйте это:
CREATE function [SplitWordList]
(
@list varchar(8000)
)
returns @t table
(
Word varchar(50) not null,
Position int identity(1,1) not null
)
as begin
declare
@pos int,
@lpos int,
@item varchar(100),
@ignore varchar(100),
@dl int,
@a1 int,
@a2 int,
@z1 int,
@z2 int,
@n1 int,
@n2 int,
@c varchar(1),
@a smallint
select
@a1 = ascii('a'),
@a2 = ascii('A'),
@z1 = ascii('z'),
@z2 = ascii('Z'),
@n1 = ascii('0'),
@n2 = ascii('9')
set @ignore = '''"'
set @pos = 1
set @dl = datalength(@list)
set @lpos = 1
set @item = ''
while (@pos <= @dl) begin
set @c = substring(@list, @pos, 1)
if (@ignore not like '%' + @c + '%') begin
set @a = ascii(@c)
if ((@a >= @a1) and (@a <= @z1))
or ((@a >= @a2) and (@a <= @z2))
or ((@a >= @n1) and (@a <= @n2))
begin
set @item = @item + @c
end else if (@item > '') begin
insert into @t values (@item)
set @item = ''
end
end
set @pos = @pos + 1
end
if (@item > '') begin
insert into @t values (@item)
end
return
end
Тест это как это:
select * from SplitWordList('Hello John Smith')
Во-первых, создайте функцию (использующий CTE, общее выражение таблицы покончило с потребностью во временной таблице)
create function dbo.SplitString
(
@str nvarchar(4000),
@separator char(1)
)
returns table
AS
return (
with tokens(p, a, b) AS (
select
1,
1,
charindex(@separator, @str)
union all
select
p + 1,
b + 1,
charindex(@separator, @str, b + 1)
from tokens
where b > 0
)
select
p-1 zeroBasedOccurance,
substring(
@str,
a,
case when b > 0 then b-a ELSE 4000 end)
AS s
from tokens
)
GO
Затем используйте его в качестве любой таблицы (или измените, это для установки в существующем сохранило proc) как это.
select s
from dbo.SplitString('Hello John Smith', ' ')
where zeroBasedOccurance=1
Обновление
Предыдущая версия перестала бы работать для входной строки дольше, чем 4 000 символов. Эта версия заботится об ограничении:
create function dbo.SplitString
(
@str nvarchar(max),
@separator char(1)
)
returns table
AS
return (
with tokens(p, a, b) AS (
select
cast(1 as bigint),
cast(1 as bigint),
charindex(@separator, @str)
union all
select
p + 1,
b + 1,
charindex(@separator, @str, b + 1)
from tokens
where b > 0
)
select
p-1 ItemIndex,
substring(
@str,
a,
case when b > 0 then b-a ELSE LEN(@str) end)
AS s
from tokens
);
GO
Использование остается тем же.
Я не полагаю, что SQL Server имеет встроенную функцию разделения, таким образом, кроме UDF, единственный другой ответ, который я знаю, должен угнать функцию PARSENAME:
SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 2)
PARSENAME берет строку и разделяет ее на символе точки. Это берет число в качестве своего второго аргумента, и то число определяет который сегмент строки возвратиться (работающий из наоборот).
SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 3) --return Hello
Очевидная проблема состоит в том, когда строка уже содержит период. Я все еще думаю с помощью UDF, лучший способ... какие-либо другие предложения?
Вот UDF, который сделает это. Это возвратит таблицу разграниченных значений, не попробовали все сценарии на нем, но Ваш пример хорошо работает.
CREATE FUNCTION SplitString
(
-- Add the parameters for the function here
@myString varchar(500),
@deliminator varchar(10)
)
RETURNS
@ReturnTable TABLE
(
-- Add the column definitions for the TABLE variable here
[id] [int] IDENTITY(1,1) NOT NULL,
[part] [varchar](50) NULL
)
AS
BEGIN
Declare @iSpaces int
Declare @part varchar(50)
--initialize spaces
Select @iSpaces = charindex(@deliminator,@myString,0)
While @iSpaces > 0
Begin
Select @part = substring(@myString,0,charindex(@deliminator,@myString,0))
Insert Into @ReturnTable(part)
Select @part
Select @myString = substring(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0))
Select @iSpaces = charindex(@deliminator,@myString,0)
end
If len(@myString) > 0
Insert Into @ReturnTable
Select @myString
RETURN
END
GO
Вы назвали бы его как это:
Select * From SplitString('Hello John Smith',' ')
Редактирование: Обновленное решение обработать delimters с len> 1 как в:
select * From SplitString('Hello**John**Smith','**')
Можно усилить таблицу Number, чтобы сделать строковый парсинг.
Составляют физическую таблицу чисел:
create table dbo.Numbers (N int primary key);
insert into dbo.Numbers
select top 1000 row_number() over(order by number) from master..spt_values
go
Составляют тестовую таблицу с 1 000 000 строк
create table #yak (i int identity(1,1) primary key, array varchar(50))
insert into #yak(array)
select 'a,b,c' from dbo.Numbers n cross join dbo.Numbers nn
go
, Создают функцию
create function [dbo].[ufn_ParseArray]
( @Input nvarchar(4000),
@Delimiter char(1) = ',',
@BaseIdent int
)
returns table as
return
( select row_number() over (order by n asc) + (@BaseIdent - 1) [i],
substring(@Input, n, charindex(@Delimiter, @Input + @Delimiter, n) - n) s
from dbo.Numbers
where n <= convert(int, len(@Input)) and
substring(@Delimiter + @Input, n, 1) = @Delimiter
)
go
Использование (выходные строки 3 миллиметров в 40-х на моем ноутбуке)
select *
from #yak
cross apply dbo.ufn_ParseArray(array, ',', 1)
очистка
drop table dbo.Numbers;
drop function [dbo].[ufn_ParseArray]
, Производительность здесь не удивительна, но вызывание функции, более чем миллион таблиц строки не является лучшей идеей. При выполнении строкового разделения по поводу многих строк я избежал бы функции.
Использование SQL Server 2016 и выше. Используйте этот код, чтобы ОБРЕЗАТЬ строки, проигнорировать Нулевые значения и применить индекс строки в правильном порядке. Это также работает с разделителем пространства:
DECLARE @STRING_VALUE NVARCHAR(MAX) = 'one, two,,three, four, five'
SELECT ROW_NUMBER() OVER (ORDER BY R.[index]) [index], R.[value] FROM
(
SELECT
1 [index], NULLIF(TRIM([value]), '') [value] FROM STRING_SPLIT(@STRING_VALUE, ',') T
WHERE
NULLIF(TRIM([value]), '') IS NOT NULL
) R