كيف يمكنني تقسيم سلسلة لذا يمكن الوصول إليها في البند العاشر ؟
-
08-06-2019 - |
سؤال
باستخدام SQL Server, كيف يمكنني تقسيم سلسلة لذا يمكن الوصول إليها في البند العاشر ؟
اتخاذ سلسلة "مرحبا جون سميث".كيف يمكنني تقسيم سلسلة من الفضاء و الوصول إلى العنصر في الفهرس 1 الذي ينبغي أن عودة "جون"?
المحلول
قد تجد الحل في 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
نصائح أخرى
أنا لا أصدق SQL Server لديه المدمج في تقسيم وظيفة أخرى من UDF ، فقط إجابة أخرى أعرفه هو أن خطف PARSENAME وظيفة:
SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 2)
PARSENAME يأخذ سلسلة انشقاقات على فترة حرف.فإنه يأخذ عددا كما في الحجة الثانية ، أن عدد يحدد الجزء من سلسلة العودة (العمل من الخلف إلى الأمام).
SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 3) --return Hello
مشكلة واضحة عندما السلسلة يحتوي بالفعل على فترة.ما زلت أعتقد باستخدام UDF هو أفضل وسيلة...أي اقتراحات أخرى ؟
أولا إنشاء وظيفة (باستخدام 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
التحديث
الإصدار السابق سوف تفشل لإدخال سلسلة أطول من 4000 حرف.هذا الإصدار يعتني الحصر:
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
الاستخدام لا يزال هو نفسه.
معظم الحلول هنا استخدام حين الحلقات أو متكررة CTEs.مجموعة القائم على النهج سوف تكون متفوقة ، أعدك:
CREATE FUNCTION [dbo].[SplitString]
(
@List NVARCHAR(MAX),
@Delim VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT [Value] FROM
(
SELECT
[Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_objects) AS x
WHERE Number <= LEN(@List)
AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
) AS y
);
أكثر على تقسيم الوظائف ، لماذا (والدليل على ذلك) في حين الحلقات التكرارية CTEs لا نطاق ، بدائل أفضل ، إذا كان تقسيم سلاسل قادمة من طبقة التطبيقات:
- تقسيم سلاسل الطريق الصحيح – أو القادم أفضل طريقة
- تقسيم السلاسل :متابعة
- تقسيم السلاسل :الآن مع أقل من T-SQL
- مقارنة سلسلة تقسيم / سلسلة طرق
- تجهيز قائمة من الأعداد الصحيحة :توجهي
- تقسيم قائمة من الأعداد الصحيحة :آخر تقرير اخبارى
- أكثر على تقسيم القوائم :مخصص المحددات ، ومنع التكرارات ، و الحفاظ على النظام
- إزالة التكرارات من السلاسل في SQL Server
في SQL Server عام 2016 أو أعلاه ، رغم ذلك ، يجب أن ننظر في STRING_SPLIT()
و STRING_AGG()
:
يمكنك الاستفادة من عدد طاولة للقيام سلسلة تحليل.
إنشاء المادية أرقام الجدول:
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
إنشاء جدول الاختبار مع 1000000 الصفوف
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
الاستخدام (النواتج 3mil الصفوف في 40s على جهاز الكمبيوتر المحمول)
select *
from #yak
cross apply dbo.ufn_ParseArray(array, ',', 1)
تنظيف
drop table dbo.Numbers;
drop function [dbo].[ufn_ParseArray]
الأداء هنا ليست مذهلة ، ولكن استدعاء دالة أكثر من مليون صف الجدول ليست أفضل فكرة.إذا كان أداء سلسلة الانقسام على العديد من الصفوف وأود أن تجنب وظيفة.
هذا السؤال هو لا حول سلسلة نهج تقسيم, ولكن عن كيفية الحصول على أقصى عنصر.
كل الإجابات هنا هي القيام ببعض النوع من سلسلة تقسيم استخدام العودية ، CTE
s متعددة CHARINDEX
, REVERSE
و PATINDEX
, واختراع وظائف الدعوة CLR طرق, عدد الجداول ، CROSS APPLY
s ...معظم الإجابات تغطي العديد من الأسطر من التعليمات البرمجية.
ولكن إذا كنت حقا لا أريد شيئا أكثر من نهج للحصول على أقصى عنصر - ويمكن أن يتم ذلك كما واحد حقيقي-بطانة, لا UDF, ولا حتى حدد الفرعية...و كميزة اضافية: نوع آمنة
الحصول على 2 جزء محدد من الفضاء:
DECLARE @input NVARCHAR(100)=N'part1 part2 part3';
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)')
بالطبع يمكنك استخدام المتغيرات بالنسبة محدد و موقف (استخدام sql:column
استرداد موضع مباشرة من استعلام القيمة):
DECLARE @dlmt NVARCHAR(10)=N' ';
DECLARE @pos INT = 2;
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)')
إذا كانت السلسلة قد تشمل ممنوع الشخصيات (وخاصة بين &><
) لا يمكنك أن تفعل ذلك بهذه الطريقة.مجرد استخدام FOR XML PATH
على السلسلة الأولى ليحل محل كل ممنوع الشخصيات مع تركيب تسلسل الهروب ضمنا.
انها حالة خاصة جدا إذا كان - بالإضافة إلى ذلك - جهاز محدد الفاصلة المنقوطة.في هذه الحالة لا محل محدد الأولى إلى '#DLMT#', واستبدال هذه علامات XML أخيرا:
SET @input=N'Some <, > and &;Other äöü@€;One more';
SET @dlmt=N';';
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');
تحديث SQL Server 2016+
للأسف المطورين نسيت أن عودة جزء من مؤشر مع STRING_SPLIT
.ولكن باستخدام SQL-Server 2016+ هناك OPENJSON
.
على الوثائق بوضوح:
عندما OPENJSON يوزع سلمان مجموعة ، ترجع الدالة الفهارس العناصر في النص JSON المفاتيح.
مثل سلسلة 1,2,3
تحتاج إلى شيء أكثر من الأقواس: [1,2,3]
.
سلسلة من الكلمات مثل this is an example
يحتاج إلى ["this","is","an"," example"]
.
هذه هي سهلة جدا سلسلة عمليات.مجرد محاولة ذلك:
DECLARE @str VARCHAR(100)='Hello John Smith';
SELECT [value]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]')
WHERE [key]=1 --zero-based!
هنا هو 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 مع ليون>1 كما في :
select * From SplitString('Hello**John**Smith','**')
هنا أنشر طريقة بسيطة الحل
CREATE FUNCTION [dbo].[split](
@delimited NVARCHAR(MAX),
@delimiter NVARCHAR(100)
) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE @xml XML
SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'
INSERT INTO @t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM @xml.nodes('/t') as records(r)
RETURN
END
وتنفيذ وظيفة مثل هذا
select * from dbo.split('Hello John Smith',' ')
في رأيي أنتم مما يجعلها معقدة جدا.مجرد إنشاء CLR UDF وينبغي القيام به معها.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;
public partial class UserDefinedFunctions {
[SqlFunction]
public static SqlString SearchString(string Search) {
List<string> SearchWords = new List<string>();
foreach (string s in Search.Split(new char[] { ' ' })) {
if (!s.ToLower().Equals("or") && !s.ToLower().Equals("and")) {
SearchWords.Add(s);
}
}
return new SqlString(string.Join(" OR ", SearchWords.ToArray()));
}
};
ماذا عن استخدام string
و values()
البيان ؟
DECLARE @str varchar(max)
SET @str = 'Hello John Smith'
DECLARE @separator varchar(max)
SET @separator = ' '
DECLARE @Splited TABLE(id int IDENTITY(1,1), item varchar(max))
SET @str = REPLACE(@str, @separator, '''),(''')
SET @str = 'SELECT * FROM (VALUES(''' + @str + ''')) AS V(A)'
INSERT INTO @Splited
EXEC(@str)
SELECT * FROM @Splited
نتيجة مجموعة تحقيقها.
id item
1 Hello
2 John
3 Smith
أنا استخدم الجواب فريدريك ولكن هذا لم ينجح في SQL Server 2005
أنا تعديله و أنا باستخدام select
مع union all
ويعمل
DECLARE @str varchar(max)
SET @str = 'Hello John Smith how are you'
DECLARE @separator varchar(max)
SET @separator = ' '
DECLARE @Splited table(id int IDENTITY(1,1), item varchar(max))
SET @str = REPLACE(@str, @separator, ''' UNION ALL SELECT ''')
SET @str = ' SELECT ''' + @str + ''' '
INSERT INTO @Splited
EXEC(@str)
SELECT * FROM @Splited
والنتيجة-مجموعة:
id item
1 Hello
2 John
3 Smith
4 how
5 are
6 you
هذا النمط يعمل بشكل جيد و يمكنك التعميم
Convert(xml,'<n>'+Replace(FIELD,'.','</n><n>')+'</n>').value('(/n[INDEX])','TYPE')
^^^^^ ^^^^^ ^^^^
ملاحظة المجال, مؤشر و نوع.
السماح لبعض الجدول مع معرفات مثل
sys.message.1234.warning.A45
sys.message.1235.error.O98
....
ثم يمكنك كتابة
SELECT Source = q.value('(/n[1])', 'varchar(10)'),
RecordType = q.value('(/n[2])', 'varchar(20)'),
RecordNumber = q.value('(/n[3])', 'int'),
Status = q.value('(/n[4])', 'varchar(5)')
FROM (
SELECT q = Convert(xml,'<n>'+Replace(fieldName,'.','</n><n>')+'</n>')
FROM some_TABLE
) Q
تقسيم و صب كل أجزاء.
إذا كان لديك قاعدة بيانات التوافق مستوى 130 أو أعلى ثم يمكنك استخدام STRING_SPLIT وظيفة جنبا إلى جنب مع تعويض الجلب شروط الحصول على العنصر المحدد من قبل المؤشر.
للحصول على هذا البند في مؤشر N (صفر) ، يمكنك استخدام التعليمات البرمجية التالية
SELECT value
FROM STRING_SPLIT('Hello John Smith',' ')
ORDER BY (SELECT NULL)
OFFSET N ROWS
FETCH NEXT 1 ROWS ONLY
للتحقق من مستوى توافق قاعدة البيانات الخاصة بك, تنفيذ هذا الكود:
SELECT compatibility_level
FROM sys.databases WHERE name = 'YourDBName';
كنت أبحث عن الحل على الشبكة أدناه يعمل بالنسبة لي.المرجع.
و يمكنك استدعاء الدالة مثل هذا :
SELECT * FROM dbo.split('ram shyam hari gopal',' ')
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[Split](@String VARCHAR(8000), @Delimiter CHAR(1))
RETURNS @temptable TABLE (items VARCHAR(8000))
AS
BEGIN
DECLARE @idx INT
DECLARE @slice VARCHAR(8000)
SELECT @idx = 1
IF len(@String)<1 OR @String IS NULL RETURN
WHILE @idx!= 0
BEGIN
SET @idx = charindex(@Delimiter,@String)
IF @idx!=0
SET @slice = LEFT(@String,@idx - 1)
ELSE
SET @slice = @String
IF(len(@slice)>0)
INSERT INTO @temptable(Items) VALUES(@slice)
SET @String = RIGHT(@String,len(@String) - @idx)
IF len(@String) = 0 break
END
RETURN
END
آخر الحصول على ن أخذ جزء من سلسلة من delimeter وظيفة:
create function GetStringPartByDelimeter (
@value as nvarchar(max),
@delimeter as nvarchar(max),
@position as int
) returns NVARCHAR(MAX)
AS BEGIN
declare @startPos as int
declare @endPos as int
set @endPos = -1
while (@position > 0 and @endPos != 0) begin
set @startPos = @endPos + 1
set @endPos = charindex(@delimeter, @value, @startPos)
if(@position = 1) begin
if(@endPos = 0)
set @endPos = len(@value) + 1
return substring(@value, @startPos, @endPos - @startPos)
end
set @position = @position - 1
end
return null
end
و الاستخدام:
select dbo.GetStringPartByDelimeter ('a;b;c;d;e', ';', 3)
والتي ترجع:
c
جرب هذا:
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
التحديث 18.09.2013
CREATE FUNCTION dbo.SplitStrings_CTE(@List nvarchar(max), @Delimiter nvarchar(1))
RETURNS @returns TABLE (val nvarchar(max), [level] int, PRIMARY KEY CLUSTERED([level]))
AS
BEGIN
;WITH cte AS
(
SELECT SUBSTRING(@List, 0, CHARINDEX(@Delimiter, @List + @Delimiter)) AS val,
CAST(STUFF(@List + @Delimiter, 1, CHARINDEX(@Delimiter, @List + @Delimiter), '') AS nvarchar(max)) AS stval,
1 AS [level]
UNION ALL
SELECT SUBSTRING(stval, 0, CHARINDEX(@Delimiter, stval)),
CAST(STUFF(stval, 1, CHARINDEX(@Delimiter, stval), '') AS nvarchar(max)),
[level] + 1
FROM cte
WHERE stval != ''
)
INSERT @returns
SELECT REPLACE(val, ' ','' ) AS val, [level]
FROM cte
WHERE val > ''
RETURN
END
التجريبي على SQLFiddle
Alter Function dbo.fn_Split
(
@Expression nvarchar(max),
@Delimiter nvarchar(20) = ',',
@Qualifier char(1) = Null
)
RETURNS @Results TABLE (id int IDENTITY(1,1), value nvarchar(max))
AS
BEGIN
/* USAGE
Select * From dbo.fn_Split('apple pear grape banana orange honeydew cantalope 3 2 1 4', ' ', Null)
Select * From dbo.fn_Split('1,abc,"Doe, John",4', ',', '"')
Select * From dbo.fn_Split('Hello 0,"&""&&&&', ',', '"')
*/
-- Declare Variables
DECLARE
@X xml,
@Temp nvarchar(max),
@Temp2 nvarchar(max),
@Start int,
@End int
-- HTML Encode @Expression
Select @Expression = (Select @Expression For XML Path(''))
-- Find all occurences of @Delimiter within @Qualifier and replace with |||***|||
While PATINDEX('%' + @Qualifier + '%', @Expression) > 0 AND Len(IsNull(@Qualifier, '')) > 0
BEGIN
Select
-- Starting character position of @Qualifier
@Start = PATINDEX('%' + @Qualifier + '%', @Expression),
-- @Expression starting at the @Start position
@Temp = SubString(@Expression, @Start + 1, LEN(@Expression)-@Start+1),
-- Next position of @Qualifier within @Expression
@End = PATINDEX('%' + @Qualifier + '%', @Temp) - 1,
-- The part of Expression found between the @Qualifiers
@Temp2 = Case When @End < 0 Then @Temp Else Left(@Temp, @End) End,
-- New @Expression
@Expression = REPLACE(@Expression,
@Qualifier + @Temp2 + Case When @End < 0 Then '' Else @Qualifier End,
Replace(@Temp2, @Delimiter, '|||***|||')
)
END
-- Replace all occurences of @Delimiter within @Expression with '</fn_Split><fn_Split>'
-- And convert it to XML so we can select from it
SET
@X = Cast('<fn_Split>' +
Replace(@Expression, @Delimiter, '</fn_Split><fn_Split>') +
'</fn_Split>' as xml)
-- Insert into our returnable table replacing '|||***|||' back to @Delimiter
INSERT @Results
SELECT
"Value" = LTRIM(RTrim(Replace(C.value('.', 'nvarchar(max)'), '|||***|||', @Delimiter)))
FROM
@X.nodes('fn_Split') as X(C)
-- Return our temp table
RETURN
END
أنا أعرف أنها مسألة قديمة, ولكن أعتقد أن بعض واحد يمكن أن تستفيد من الحل.
select
SUBSTRING(column_name,1,CHARINDEX(' ',column_name,1)-1)
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name))
,1
,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)-1)
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name))
,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)+1
,LEN(column_name))
from table_name
المزايا:
- أنه يفصل كل 3 السلاسل الفرعية deliminator من قبل ' '.
- يجب عدم استخدام حين حلقة ، كما أنه يقلل من الأداء.
- لا تحتاج إلى محور كل الناتجة sub-string سيتم عرضها في صف واحد
القيود:
- واحد يجب أن تعرف مجموعه لا.المساحات (sub-string).
ملاحظة:الحل يمكن أن تعطي sub-string يصل إلى N.
أن تغلبت الحد يمكننا استخدام التالية المرجع.
ولكن مرة أخرى فوق الحل لا يمكن استخدامها في الجدول (أكتاولي لم أكن قادرة على استخدامها).
مرة أخرى أتمنى أن هذا الحل يمكن أن تساعد بعض واحد.
تحديث: في حالة السجلات > 50000 ليس من المستحسن استخدام LOOPS
كما أنها سوف تتحلل الأداء
تقريبا جميع إجابات أخرى تقسيم البرمجية استبدال سلسلة يتم تقسيم والتي النفايات دورات وحدة المعالجة المركزية وأداء الذاكرة لا لزوم لها مخصصات.
انا تغطية أفضل طريقة للقيام string split هنا: http://www.digitalruby.com/split-string-sql-server/
هنا هو رمز:
SET NOCOUNT ON
-- You will want to change nvarchar(MAX) to nvarchar(50), varchar(50) or whatever matches exactly with the string column you will be searching against
DECLARE @SplitStringTable TABLE (Value nvarchar(MAX) NOT NULL)
DECLARE @StringToSplit nvarchar(MAX) = 'your|string|to|split|here'
DECLARE @SplitEndPos int
DECLARE @SplitValue nvarchar(MAX)
DECLARE @SplitDelim nvarchar(1) = '|'
DECLARE @SplitStartPos int = 1
SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)
WHILE @SplitEndPos > 0
BEGIN
SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, (@SplitEndPos - @SplitStartPos))
INSERT @SplitStringTable (Value) VALUES (@SplitValue)
SET @SplitStartPos = @SplitEndPos + 1
SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)
END
SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, 2147483647)
INSERT @SplitStringTable (Value) VALUES(@SplitValue)
SET NOCOUNT OFF
-- You can select or join with the values in @SplitStringTable at this point.
يمكنك تقسيم سلسلة في SQL دون الحاجة إلى الدالة:
DECLARE @bla varchar(MAX)
SET @bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C'
-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT
x.XmlCol.value('.', 'varchar(36)') AS val
FROM
(
SELECT
CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b
CROSS APPLY b.RawXml.nodes('e') x(XmlCol);
إذا كنت بحاجة إلى دعم التعسفي السلاسل (مع xml أحرف خاصة)
DECLARE @bla NVARCHAR(MAX)
SET @bla = '<html>unsafe & safe Utf8CharsDon''tGetEncoded ÄöÜ - "Conex"<html>,Barnes & Noble,abc,def,ghi'
-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT
x.XmlCol.value('.', 'nvarchar(MAX)') AS val
FROM
(
SELECT
CAST('<e>' + REPLACE((SELECT @bla FOR XML PATH('')), ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b
CROSS APPLY b.RawXml.nodes('e') x(XmlCol);
مجموعة النقي القائم على الحل باستخدام TVF
مع العودية CTE
.يمكنك JOIN
و APPLY
هذه الوظيفة إلى أي بيانات.
create function [dbo].[SplitStringToResultSet] (@value varchar(max), @separator char(1))
returns table
as return
with r as (
select value, cast(null as varchar(max)) [x], -1 [no] from (select rtrim(cast(@value as varchar(max))) [value]) as j
union all
select right(value, len(value)-case charindex(@separator, value) when 0 then len(value) else charindex(@separator, value) end) [value]
, left(r.[value], case charindex(@separator, r.value) when 0 then len(r.value) else abs(charindex(@separator, r.[value])-1) end ) [x]
, [no] + 1 [no]
from r where value > '')
select ltrim(x) [value], [no] [index] from r where x is not null;
go
الاستخدام:
select *
from [dbo].[SplitStringToResultSet]('Hello John Smith', ' ')
where [index] = 1;
النتيجة:
value index
-------------
John 1
بدءا من SQL Server 2016 نحن string_split
DECLARE @string varchar(100) = 'Richard, Mike, Mark'
SELECT value FROM string_split(@string, ',')
النهج الحديث باستخدام STRING_SPLIT, يتطلب ملقم SQL 2016 وما فوق.
DECLARE @string varchar(100) = 'Hello John Smith'
SELECT
ROW_NUMBER() OVER (ORDER BY value) AS RowNr,
value
FROM string_split(@string, ' ')
النتيجة:
RowNr value
1 Hello
2 John
3 Smith
فمن الممكن الآن الحصول على ال nth عنصر من رقم الصف.
هارون برتراند الجواب هو رائع ولكن معيبة.لا دقة التعامل مع الفضاء محدد (كما هو المثال في السؤال الأصلي) لأن طول وظيفة شرائح مسافات زائدة.
التالية هي رمز له ، مع تعديل صغير للسماح مساحة محدد:
CREATE FUNCTION [dbo].[SplitString]
(
@List NVARCHAR(MAX),
@Delim VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT [Value] FROM
(
SELECT
[Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
FROM sys.all_objects) AS x
WHERE Number <= LEN(@List)
AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim+'x')-1) = @Delim
) AS y
);
هنا هي الدالة التي سيتم إنجاز السؤال المتمثل في تقسيم سلسلة والوصول إلى البند العاشر:
CREATE FUNCTION [dbo].[SplitString]
(
@List VARCHAR(MAX),
@Delimiter VARCHAR(255),
@ElementNumber INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @inp VARCHAR(MAX)
SET @inp = (SELECT REPLACE(@List,@Delimiter,'_DELMTR_') FOR XML PATH(''))
DECLARE @xml XML
SET @xml = '<split><el>' + REPLACE(@inp,'_DELMTR_','</el><el>') + '</el></split>'
DECLARE @ret VARCHAR(MAX)
SET @ret = (SELECT
el = split.el.value('.','varchar(max)')
FROM @xml.nodes('/split/el[string-length(.)>0][position() = sql:variable("@elementnumber")]') split(el))
RETURN @ret
END
الاستخدام:
SELECT dbo.SplitString('Hello John Smith', ' ', 2)
النتيجة:
John
الحل بسيط لتحليل الاسم الأول والأخير
DECLARE @Name varchar(10) = 'John Smith'
-- Get First Name
SELECT SUBSTRING(@Name, 0, (SELECT CHARINDEX(' ', @Name)))
-- Get Last Name
SELECT SUBSTRING(@Name, (SELECT CHARINDEX(' ', @Name)) + 1, LEN(@Name))
في حالتي (و في العديد من الآخرين على ما يبدو...), لدي قائمة من الأسماء الأولى والأخيرة مفصولة مسافة واحدة.هذا يمكن استخدامها مباشرة داخل select إلى إعراب الاسم الأول والأخير.
-- i.e. Get First and Last Name from a table of Full Names
SELECT SUBSTRING(FullName, 0, (SELECT CHARINDEX(' ', FullName))) as FirstName,
SUBSTRING(FullName, (SELECT CHARINDEX(' ', FullName)) + 1, LEN(FullName)) as LastName,
From FullNameTable
وأنا أعلم به في وقت متأخر ، ولكن مؤخرا كان هذا الشرط جاء مع رمز أدناه.أنا لم يكن لديك خيار استخدام دالة معرفة من قبل المستخدم.ويساعد هذا الأمل.
SELECT
SUBSTRING(
SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
)
حسنا, لي ليس كل ما أبسط, ولكن هنا هو رمز يمكنني استخدام لتقسيم بفواصل إدخال متغير في القيم الفردية ، ووضعها في جدول متغير.أنا متأكد من أنك يمكن تعديل هذا قليلا إلى الانقسام على أساس مسافة ثم القيام الأساسي حدد الاستعلام ضد هذا الجدول متغير للحصول على النتائج الخاصة بك.
-- 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
هذا المفهوم هو الى حد كبير نفس.واحدة البديل الآخر هو الاستفادة .صافي التوافق داخل SQL Server 2005 نفسها.يمكنك أساسا تكتب لنفسك طريقة بسيطة في .الشبكة التي من شأنها أن تقسيم السلسلة ثم فضح هذا الإجراء المخزن/وظيفة.
هذا شيء فعلته من أجل الحصول على محدد المميز في سلسلة.(اختبار في MSSQL 2008)
أولا خلق الوظائف التالية:(وجدت في: هنا
CREATE FUNCTION dbo.SplitStrings_Moden
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
E2(N) AS (SELECT 1 FROM E1 a, E1 b),
E4(N) AS (SELECT 1 FROM E2 a, E2 b),
E42(N) AS (SELECT 1 FROM E4 a, E2 b),
cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1)))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
FROM cteStart s;
و
create FUNCTION dbo.getToken
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255),
@Pos int
)
RETURNS varchar(max)
as
begin
declare @returnValue varchar(max);
select @returnValue = tbl.Item from (
select ROW_NUMBER() over (order by (select null)) as id, * from dbo.SplitStrings_Moden(@List, @Delimiter)
) as tbl
where tbl.id = @Pos
return @returnValue
end
ثم يمكنك استخدامه هكذا:
select dbo.getToken('1111_2222_3333_', '_', 1)
والتي العودة 1111