已经有查询来获取第一个用“。”分隔的单词,我需要一个显示第三个单词的新列
SELECT
MyColumn,
LEFT(MyColumn, CHARINDEX('.', MyColumn) - 1) AS [1st Sequence]
FROM
dbo.MyTable
样品#1:
2345.Z2Z2.A12151.AB4R
查询应返回A12151
样本#2:
STR4.35S982F.X24
查询应返回X24
编辑:
感谢大家分享您的疑问。尽管WITH CTE有效,但我正在考虑一个更简单的查询,因为它将用作我的下拉列表中的数据源,并且在另一个下拉列表更改时将始终刷新。
我认为这可以通过SUBSTRING来完成。请参阅下面我发现并测试的查询,其中提取了第二个单词。我正在修改它以提取第三个单词。如果有人能帮助我,我会非常感激:
SELECT MyColumn,
SUBSTRING(MyColumn, CHARINDEX('.', MyColumn) + 1 , CHARINDEX('.', MyColumn, CHARINDEX('.', MyColumn)+1) - (CHARINDEX('.', MyColumn) + 1))
FROM dbo.MyTable
答案 0 :(得分:2)
我建议使用Common Table Expressions:
;WITH CTE AS
(
SELECT 1 AS RowNo, LEFT(MyColumn, CHARINDEX('.', MyColumn)-1) AS Word,
RIGHT(MyColumn, LEN(MyColumn) - CHARINDEX('.', MyColumn)) AS Remainder
FROM Dummy
WHERE CHARINDEX('.', MyColumn) >0
UNION ALL
SELECT RowNo +1, LEFT(Remainder, CHARINDEX('.', Remainder)-1) AS Word,
RIGHT(Remainder, LEN(Remainder) - CHARINDEX('.', Remainder)) AS Remainder
FROM CTE
WHERE CHARINDEX('.', Remainder) >0
UNION ALL
SELECT RowNo+ 1, Remainder As Word, NULL As Remainder
FROM CTE
WHERE CHARINDEX('.', Remainder) = 0
)
SELECT Word
FROM CTE
WHERE RowNo = 3
结果:
X24
A12151
有关详细信息,请参阅:Recursive Queries Using Common Table Expressions
[EDIT#2]
假设您希望将每个单词放入不同的列,则必须将最后的SELECT
语句更改为:
SELECT ID, [1], [2], [3], [4]
FROM (
SELECT RowNo, Word, ROW_NUMBER() OVER(PARTITION BY RowNo ORDER BY RowNo) AS ID
FROM CTE
) AS src
PIVOT (MAX(Word) FOR RowNo IN([1], [2], [3], [4])) AS pvt
结果:
ID 1 2 3 4
1 2345 35S982F A12151 AB4R
2 STR4 Z2Z2 X24 (null)
答案 1 :(得分:2)
一种方法是使用Jeff Moden的DelmimitedSplit8k。这个分割器的优点是它返回每个项目的序数位置,这对您的目标至关重要。它也是许多其他人不返回的东西(包括SQL Server的STRING_SPLIT
)。这变得非常简单:
WITH VTE AS (
SELECT *
FROM (VALUES('2345.Z2Z2.A12151.AB4R'),('STR4.35S982F.X24'))V(S))
SELECT DS.Item
FROM VTE
CROSS APPLY dbo.DelimitedSplit8K(VTE.S,'.') DS
WHERE DS.ItemNumber = 3;
答案 2 :(得分:1)
使用PARSENAME
可以解决这个问题,但如果字符串中有三个以上的点,则不支持限制。
使用样本数据执行查询:
DECLARE @SampleTable TABLE (TextValue VARCHAR (2000));
INSERT INTO @SampleTable (TextValue)
VALUES ('2345.Z2Z2.A12151.AB4R'), ('STR4.35S982F.X24'), ('123.345'), ('12345'), (NULL);
SELECT CASE (LEN(TextValue) - LEN(REPLACE(TextValue, '.', '')))
WHEN 3 THEN PARSENAME(TextValue, 2)
WHEN 2 THEN PARSENAME(TextValue, 1)
ELSE TextValue
END AS TextValue
FROM @SampleTable
答案 3 :(得分:1)
当您没有SQL2016并且不允许创建函数或存储过程时,可以将其强制转换为xml,然后选择第n个节点。
declare @someText nvarchar(max) = 'this is some very interesting text'
select CAST( '<p>'+Replace(rtrim(ltrim(@someText)),' ','</p><p>')+'</p>' AS XML).value('(/p)[5]','nvarchar(MAX)')
result -> interesting
答案 4 :(得分:0)
请试试这个 -
;WITH CTE AS
(
SELECT *
FROM (VALUES('2345.Z2Z2.A12151.AB4R'),('STR4.35S982F.X24'))V(S)
)
,CTE1 AS
(
SELECT * ,
REVERSE(SUBSTRING(REVERSE(S),CHARINDEX('.',REVERSE(S),0)
,(CHARINDEX('.', REVERSE(S), CHARINDEX('.',REVERSE(S),0)+1) - CHARINDEX('.',REVERSE(S),0)))) N FROM CTE
)
SELECT S,SUBSTRING(N,0,LEN(N)) N
FROM CTE1
输出
S N
--------------------- ---------------------
2345.Z2Z2.A12151.AB4R A12151
STR4.35S982F.X24 35S982F
(2 rows affected)
答案 5 :(得分:0)
首先,在SQL Server 2016及更高版本中运行的快速而肮脏的解决方案是通过将分隔符替换为","
并使用JSON_VALUE仅提取第N个值将字符串转换为JSON数组:
select JSON_VALUE('["' + REPLACE('2345.Z2Z2.A12151.AB4R','.','","') + '"]','$[2]')
返回
A12151
这很脏,因为它执行(可能很重)字符串替换。如果该函数应用于很多行,则可以相加。
更好的解决方案是不在SQL中拆分字符串。问题是
这将用作我的下拉列表的数据源,并将在另一个下拉列表更改时始终刷新
解析用于显示目的是客户端数据访问代码的工作,而不是数据库的工作。首先,字段应仅包含单个值。如果2345.Z2Z2.A12151.AB4R
中的四个值很重要,则应将它们存储在4个不同的字段中,以便于查询和索引。
也就是说,是的情况,人们希望存储Value Objects - 数据项的值不应被视为单独的entites。许多ORM都支持Value Objects,如EF Core 2.0和NHibernate。
使用值对象,字符串中的四个值可以映射到单个属性,并在UI中的数据绑定表达式中使用。即使没有ORM支持,实现Value对象也很容易。它可以像使用构造函数创建一个类一样简单,该构造函数接受一个字符串和ToString()
覆盖,返回要序列化的字符串,例如:
class MyComplexInvoice
{
public string A {get;set;}
public string B {get;set;}
public string C {get;set;}
public string D {get;set;}
public MyComplexInvoice(string input)
{
var items=inmput.Split('.');
A=items[0];
...
}
public override string ToString()
{
return $"{A}.{B}.{C}.{D}";
}
}
更好的实现方法是使用Parse()
和TryParse()
方法,例如大多数内置类型中的方法,例如:
class MyComplexInvoice
{
public string A {get;set;}
public string B {get;set;}
public string C {get;set;}
public string D {get;set;}
public MyComplexInvoice(string a,string string c,string d)
{
A=a ?? throw ArgumentNullException(nameof(a));
...
}
public static bool TryParse(string input,out MyComplexInvoice inv)
{
inv=null;
if (String.IsNullOrWhitespace(input) return false;
var items=inmput.Split('.');
if (items.Length!=4) return false;
// More validations ....
inv=new MyComplexInvoice(items[0],items[1],items[2],items[3]);
return true;
}
public override string ToString()
{
return $"{A}.{B}.{C}.{D}";
}
}
答案 6 :(得分:0)
在T-SQL中,您可以使用窗口函数:
declare @nthPos int = 2
select MyColumn,
(
select [value]
from (
select row_number() over (order by (select null)) as 'ID', [value]
from string_split(MyColumn, '.')
) x
where ID = @nthPos
) as 'nthValue'
from dbo.MyTable
答案 7 :(得分:0)
对于一个讨厌的日志文件,我需要这个确切的东西,其中包含需要解析的数据。我写了两个版本。一个带有Tally表,另一个没有。据我了解,Tally表版本应该更快。不知道这是不是真的,但这就是我最后得到的结果。对于Tally表,我必须承认下面的许多代码来自另一篇文章。如果找到它,我会引用它。
(SQL SERVER)
CREATE FUNCTION dbo.fn_SplitGetNth (@pSTR VARCHAR(MAX),@pOccurance int,@pDlm VARCHAR(MAX)=',')
RETURNS VARCHAR(MAX)
BEGIN
DECLARE @vRslt VARCHAR(MAX)
SET @pSTR=@pDlm + @pSTR + @pDlm;
SELECT @vrslt=Word FROM
(
SELECT SUBSTRING(@pstr,id+1,CHARINDEX(@pDlm,@pSTR,id+1)-id-1)[Word],ROW_NUMBER() OVER (ORDER BY id)[Position]
FROM Tally where id<LEN(@pstr)
AND SUBSTRING(@pSTR,ID,1)=@pDlm
) a
WHERE a.Position=@pOccurance
RETURN @vRslt;
end
Usage:
SELECT dbo.fn_SplitGetNth('STR4.35S982F.X24',3,'.')
结果:
COLUMN1
-------
X24
没有理货单:
CREATE FUNCTION dbo.fnSplitStringX
(
@string NVARCHAR(MAX),
@delimiter CHAR(1),
@nthValue int
)
RETURNS NVARCHAR(120)
AS
BEGIN
DECLARE @start INT, @end INT, @cnt INT=0;
SELECT @start = 1, @end = CHARINDEX(@delimiter, @string)
WHILE @start < LEN(@string) + 1 BEGIN
IF @end = 0
SET @end = LEN(@string) + 1
SET @cnt=@cnt+1
-- INSERT INTO @output (splitdata)
IF (@cnt=@nthValue)
BEGIN
RETURN SUBSTRING(@string, @start, @end - @start)
END
SET @start = @end + 1
SET @end = CHARINDEX(@delimiter, @string, @start)
END
RETURN ''
END
答案 8 :(得分:0)
CREATE FUNCTION TextSplit (@Testo VARCHAR(MAX), @Delimiter VARCHAR(128), @Position INT)
RETURNS varchar(max)
AS
BEGIN
DECLARE @Xml XML
DECLARE @Output TABLE (ID int IDENTITY(1,1),SplitData varchar(max))
DECLARE @Result varchar(max)
SET @Xml = CAST(('<a>'+REPLACE(@Testo,@delimiter,'</a><a>')+'</a>') AS XML)
INSERT INTO @Output (SplitData)
SELECT ltrim(rtrim(A.value('.', 'VARCHAR(MAX)'))) FROM @Xml.nodes('a') AS FN(a)
SET @Result = (SELECT SplitData FROM @Output WHERE ID = @Position)
RETURN(@Result);
END