我可以使用t-SQL标记字符串吗
我想知道是否有这样创建的SQL Server 2008表:我可以使用t-SQL标记字符串吗,sql,sql-server,tsql,tokenize,Sql,Sql Server,Tsql,Tokenize,我想知道是否有这样创建的SQL Server 2008表: CREATE TABLE tbl (id INT PRIMARY KEY, dvt NVARCHAR(32), d0 TINYINT, d1 TINYINT, d2 TINYINT); INSERT INTO tbl (id, dvt, d0, d1, d2) VALUES(1, '
CREATE TABLE tbl (id INT PRIMARY KEY,
dvt NVARCHAR(32),
d0 TINYINT,
d1 TINYINT,
d2 TINYINT);
INSERT INTO tbl (id, dvt, d0, d1, d2)
VALUES(1, '1', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2)
VALUES(2, '', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2)
VALUES(3, '2,5', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2)
VALUES(4, '13, 34, 45, 5', NULL, NULL, NULL);
INSERT INTO tbl (id, dvt, d0, d1, d2)
VALUES(5, '1,8, 10', NULL, NULL, NULL);
我需要从“dvt”列中提取字符串,并将其拆分为“d0”、“d1”和“d2”列。“dvt”值可以用逗号分隔
我可以使用C和一个标记化函数来实现这一点,但我想知道是否可以使用SQL来实现这一点
列之前:
1, "1", NULL, NULL, NULL
2, "", NULL, NULL, NULL
3, "2,5", NULL, NULL, NULL
4, "13, 34, 45, 5", NULL, NULL, NULL
5, "1,8, 10", NULL, NULL, NULL
以下列之后:
1, "1", 1, NULL, NULL
2, "", NULL, NULL, NULL
3, "2,5", 2, 5, NULL
4, "13, 34, 45, 5", 13, 34, 45 -- 5 is discarded
5, "1,8, 10", 1, 8, 10
这是可能的
您可以通过重复调用CHARINDEX并检查空值来完成,但编写一个函数来拆分字符串可能更好、更清晰。尝试类似的方法
;WITH Vals AS (
SELECT id,
dvt,
CAST('<r>'+REPLACE(dvt,',','</r><r>')+'</r>' AS XML).query('/r[1]').value('.','varchar(max)') d1,
CAST('<r>'+REPLACE(dvt,',','</r><r>')+'</r>' AS XML).query('/r[2]').value('.','varchar(max)') d2,
CAST('<r>'+REPLACE(dvt,',','</r><r>')+'</r>' AS XML).query('/r[3]').value('.','varchar(max)') d3
FROM tbl
)
SELECT id,
dvt,
CASE WHEN d1 = '' THEN NULL ELSE d1 END d1,
CASE WHEN d2 = '' THEN NULL ELSE d2 END d2,
CASE WHEN d3 = '' THEN NULL ELSE d3 END d3
FROM Vals
这类代码的主要问题是重复使用计算 SQL Server擅长缓存结果如果您键入完全相同的CHARINDEX计算5次,它只计算一次并重复使用该结果4次 对于那些不得不输入或维护代码的可怜的程序员来说,这并不是什么安慰 SQLServer2005以后版本的交叉应用程序确实有所帮助。逻辑是重复的,但结果可以重复引用,而不是重复键入计算
SELECT
*,
SUBSTRING(dvt, 1, ISNULL(comma1.pos-1, LEN(dvt)) ) AS item1,
SUBSTRING(dvt, comma1.pos+1, ISNULL(comma2.pos-1, LEN(dvt))-comma1.pos) AS item2,
SUBSTRING(dvt, comma2.pos+1, ISNULL(comma3.pos-1, LEN(dvt))-comma2.pos) AS item3
FROM
(
SELECT 'ab,c,def,hij' AS dvt
UNION ALL
SELECT 'xyz,abc' AS dvt
)
AS data
OUTER APPLY
(SELECT NULLIF(CHARINDEX(',', data.dvt, 1 ), 0) AS pos ) AS comma1
OUTER APPLY
(SELECT NULLIF(CHARINDEX(',', data.dvt, comma1.pos+1), 0) AS pos WHERE comma1.pos > 0) AS comma2
OUTER APPLY
(SELECT NULLIF(CHARINDEX(',', data.dvt, comma2.pos+1), 0) AS pos WHERE comma2.pos > 0) AS comma3
OUTER APPLY
(SELECT NULLIF(CHARINDEX(',', data.dvt, comma3.pos+1), 0) AS pos WHERE comma3.pos > 0) AS comma4
另一种选择是简单地编写一个表值用户定义函数,即使该函数的结果始终是一行,也可以这样做。然后您只需交叉应用该函数。我需要Sybase的字符串标记器;名称数据中由1个或多个空格分隔 名称日期干净,没有逗号或其他特殊字符
declare @test varchar(60)
select @test=str_replace(lower(rtrim('Jayanta Narayan Choudhuri'))," ",",")
exec sp_splitwords @test
这是基于肯尼·卢卡斯在
我可以将变音SQL函数移植到Sybase
Sybase允许从一个漂亮的解决方案中递归函数
已更改从粘贴的函数的1行
变音和字符串标记器的组合意味着我可以模糊搜索名称
第一个中间名和姓氏及其轮换哇,很有趣。但有一件事,我在SQLFiddle中尝试了一下,结果发现:查询已被取消,因为此查询575的估计成本超过了配置的阈值200。知道这是什么意思吗?不知道。我是在SQLServer2008上运行的。可能意味着查询将过于密集?好吧,无论如何,谢谢!我需要研究它-看看它做什么,然后我标记它。谢谢你的样品。我为自己的处境做了一些调整。结果证明它相当笨重,而且还必须抛弃TINYINT而代之以SMALLINT。请看一看:@ahmd0-对不起,我无法从这个公司网络访问SQLFiddle。如果你把代码添加到你的问题中,我可以帮你看一下。另一个通用选项是编写一个表值函数,该函数接受一个字符串参数并返回一行,其中head是第一个逗号之前的所有内容,tail是第一个逗号之后的所有内容。如果没有逗号,head=整个输入参数,tail=null。然后,您可以交叉应用这三次,以获得前三个值。@Dems-很奇怪,是什么阻止您在公司网络上访问SQL FIDLE?过去,我曾与一家互联网白名单机构交谈,并获得了他们名单的认可;这就是你所经历的吗?我很乐意与管理您的公司白名单过滤器的任何团体聊天,以尝试解决这一问题,假设这是正在发生的事情。@JakeFeasel-不确定细节。在XP上使用IE6,它会加载页面,然后我认为AJAX会尝试填充这两个问题,但它会被卡住。我无法安装其他浏览器。@Dems-gah!IE6,我的哀悼。是的,它肯定不适用于那种旧的浏览器。您确实看到问题是用sql server标记的吗?有不同的看法。
drop proc sp_splitwords
go
create proc sp_splitwords(@instr varchar(80)) as
begin
declare @pos int,
@word varchar(80),
@list varchar(81)
create table #words(word varchar(80))
select @list = @instr + ','
set @pos = patindex('%,,%',@list)
while @pos > 0
begin
select @list = str_replace(@list,',,',',')
set @pos = patindex('%,,%',@list)
end
set @pos = patindex('%,%',@list)
while @pos > 0
begin
set @word = substring(@list, 1,@pos-1)
set @list = substring(@list, @pos+1,len(@list)-@pos)
if NOT( @word is null OR LEN(@word) = 0 )
insert into #words (word) values (@word)
set @pos = patindex('%,%',@list)
end
select * from #words
order by len(word) desc
drop table #words
end
CREATE FUNCTION Metaphone2 (@str VARCHAR(100))
RETURNS VARCHAR(25) AS
BEGIN
RETURN @str
END
DROP FUNCTION Metaphone2
GO
CREATE FUNCTION Metaphone2 (@str VARCHAR(100))
RETURNS VARCHAR(25) AS
BEGIN
RETURN dbo.Metaphone(@str)
END