我给出了如下数据表的示例。 key_value是唯一的,用于获取搜索结果。我目前所做的是使用key_value进行查询,然后解析内容。
+-----+-------------+----------------+
| id | key_value | content |
+-----+-------------+----------------+
| 1 | 001 | 100SW |
| 2 | 157 | 80SW/20CO |
| 3 | 222 | 50EA/50CMD |
| 4 | 275 | 1EA/29LI/70BW |
+-----+-------------+----------------+
我目前拥有的内容:( key_value的示例:275)
+-----+-------------+----------------+
| id | key_value | content |
+-----+-------------+----------------+
| 4 | 275 | 1EA/29LI/70BW |
+-----+-------------+----------------+
我想要实现的是这样的。 (key_value的例子:275)
+-------------+----------+----------+
| key_value | percent | content |
+-------------+----------+----------+
| 275 | 1 | EA |
| 275 | 29 | LI |
| 275 | 70 | BW |
+-------------+----------+----------+
是否可以在服务器端实现查询?
P.S。:如果重要的话,目前正在使用SQL Server 2005.
答案 0 :(得分:2)
我不确定这是否适用于sql server 2005.但它确实适用于sql server 2008.你先做的是一个递归cte,在/
字符(with...
)上砍掉内容。然后,您可以将结果拆分为数字和字母数字部分。对于你的testdata我已经使用了@t
,你可以观察到。将@t
替换为with... select...
中的表格名称。
declare @t table (id int, key_value varchar(3), content varchar(max))
insert into @t
values (1, '001', '100SW')
insert into @t
values (2, '157', '80SW/20CO')
insert into @t
values (3, '222', '50EA/50CMD')
insert into @t
values (4, '275', '1EA/29LI/70BW')
;with data as (
select key_value
, case when CHARINDEX('/', content) > 0
then SUBSTRING(content,1,CHARINDEX('/', content)-1)
else content
end as a
, case when CHARINDEX('/', content) > 0
then substring(content,CHARINDEX('/', content)+2, LEN(content)-CHARINDEX('/', content))
else content
end as b
from @t
union all
select key_value
, case when CHARINDEX('/', b) > 0
then SUBSTRING(b,1,CHARINDEX('/', b)-1)
else b
end as a
, case when CHARINDEX('/', b) > 0
then substring(b,CHARINDEX('/', b)+2, LEN(b)-CHARINDEX('/', b))
else null
end as b
from data
where b is not null
)
select key_value
, left(a,PATINDEX('%[a-zA-Z]%',a)-1) as [percent]
, SUBSTRING(a,PATINDEX('%[a-zA-Z]%',a), LEN(a)-PATINDEX('%[a-zA-Z]%',a)+1) as content
from data
答案 1 :(得分:1)
请检查一下......
declare @t table(id int, key_value varchar(50), content varchar(100))
insert into @t values (1 ,'001', '100SW'),(2,'157', '80SW/20CO' ),( 3 ,'222','50EA/50CMD'),(4,'275','1EA/29LI/70BW')
declare @idTofind int = 275
select b.key_value , b.FirstName as name
from (select * from
(
SELECT distinct key_value, S.a.value('(/H/r)[1]', 'VARCHAR(100)') FirstName
, S.a.value('(/H/r)[2]', 'VARCHAR(100)') SecondName, S.a.value('(/H/r)[3]', 'VARCHAR(100)') ThirdName
FROM
(
SELECT *,CAST (N'<H><r>' + Replace( content, '/','</r><r>') + '</r></H>' AS XML) AS [vals]
FROM @t
) d CROSS APPLY d.[vals].nodes('/H/r') S(a)
) a where key_value = @idTofind
)b
union
select b.key_value , b.SecondName as name
from (select * from
(
SELECT distinct key_value, S.a.value('(/H/r)[1]', 'VARCHAR(100)') FirstName
, S.a.value('(/H/r)[2]', 'VARCHAR(100)') SecondName, S.a.value('(/H/r)[3]', 'VARCHAR(100)') ThirdName
FROM
(
SELECT *,CAST (N'<H><r>' + Replace( content, '/','</r><r>') + '</r></H>' AS XML) AS [vals]
FROM @t
) d CROSS APPLY d.[vals].nodes('/H/r') S(a)
) a where key_value = @idTofind
)b
union
select b.key_value , b.ThirdName as name
from (select * from
(
SELECT distinct key_value, S.a.value('(/H/r)[1]', 'VARCHAR(100)') FirstName
, S.a.value('(/H/r)[2]', 'VARCHAR(100)') SecondName, S.a.value('(/H/r)[3]', 'VARCHAR(100)') ThirdName
FROM
(
SELECT *,CAST (N'<H><r>' + Replace( content, '/','</r><r>') + '</r></H>' AS XML) AS [vals]
FROM @t
) d CROSS APPLY d.[vals].nodes('/H/r') S(a)
) a where key_value = @idTofind
)b
答案 2 :(得分:1)
首先你可以创建功能
CREATE FUNCTION [dbo].func_split_string
(
@input as varchar(max)
)
RETURNS @result TABLE
(
content VARCHAR(20),
[percent] VARCHAR(20)
)
AS
BEGIN
DECLARE @name VARCHAR(255)
DECLARE @content VARCHAR(20)
DECLARE @percent VARCHAR(20)
DECLARE @pos INT
SET @input = @input + '/'
WHILE CHARINDEX('/', @input) > 0
BEGIN
SELECT @pos = CHARINDEX('/', @input)
SELECT @name = SUBSTRING(@input, 1, @pos-1)
SELECT @percent = LEFT (@name, PATINDEX('%[a-zA-Z]%', @name)-1)
SELECT @content = RIGHT (@name, LEN(@name)-PATINDEX('%[a-zA-Z]%', @name)+1)
INSERT INTO @result ([percent], content)
SELECT @percent, @content
SELECT @input = SUBSTRING(@input, @pos+1, LEN(@input)-@pos)
END
RETURN
END
然后你可以像这样运行它
SELECT t.key_value, fS.[percent], fS.content
FROM yourTableHere as t
CROSS APPLY [dbo].func_split_string(t.[content]) as fS
答案 3 :(得分:1)
类似于Brett Schneider的答案(在我写完这个查询后读到的,我应该事先检查过)。
WITH Contents AS (
SELECT key_value
, value = CASE WHEN CharIndex('/', content) > 0
THEN SubString(content, 1, CharIndex('/', content) - 1)
ELSE content
END
, next_value
= CASE WHEN CharIndex('/', content) > 0
THEN SubString(content, CharIndex('/', content) + 1
, Len(content))
ELSE ''
END
FROM table1
UNION ALL
SELECT t1.key_value
, value
= CASE WHEN CharIndex('/', c.next_value) > 0
THEN SubString(c.next_value, 1, CharIndex('/', c.next_value) - 1)
ELSE c.next_value
END
, next_value
= CASE WHEN CharIndex('/', c.next_value) > 0
THEN SubString(c.next_value, CharIndex('/', c.next_value) + 1
, Len(c.next_value))
ELSE ''
END
FROM table1 t1
INNER JOIN Contents c ON t1.key_value = c.key_value
WHERE c.next_value <> ''
), FindNumber AS (
SELECT key_value
, CharPos = CASE WHEN IsNumeric(SubString(value, 3, 1)) = 1 THEN 4
WHEN IsNumeric(SubString(value, 2, 1)) = 1 THEN 3
ELSE 2
END
, value
FROM Contents
)
SELECT Key_Value
, [Percent] = Cast(SubString(value, 1, CharPos - 1) AS int)
, Content = SubString(value, CharPos, Len(value))
FROM FindNumber
最大的区别是我们从字符串中分割数字的方式,在我的脚本中,我检查第三个字符,然后检查第二个字符是否是数字,因为数字是百分比,将永远不会超过3个数字,并且百分比是整数而不是字符串。
OP的评论似乎表明了对性能的追求,在这种情况下值得注意的是,有时,我想强调 SOMETIMES 部分,翻译{{ 1}}一些数学结构将加快执行速度。通常的权衡是可读性
没有CASE
的上一个查询是
CASE
工作原理:
WITH Contents AS (
SELECT key_value
, value
= SubString(content, 1
, Cast(CharIndex('/', content) as bit) * (CharIndex('/', content) - 1)
+ (1 - Cast(CharIndex('/', content) as bit)) * Len(content))
, next_value
= SubString(content
, Cast(CharIndex('/', content) as bit) * (CharIndex('/', content))
+ (1 - Cast(CharIndex('/', content) as bit)) * Len(content) + 1, Len(content))
FROM table1
UNION ALL
SELECT t1.key_value
, value
= SubString(c.next_value, 1
, Cast(CharIndex('/', c.next_value) as bit) * (CharIndex('/', c.next_value) - 1)
+ (1 - Cast(CharIndex('/', c.next_value) as bit)) * Len(c.next_value))
, next_value
= SubString(c.next_value
, Cast(CharIndex('/', c.next_value) as bit) * (CharIndex('/', c.next_value))
+ (1 - Cast(CharIndex('/', c.next_value) as bit)) * Len(c.next_value) + 1, Len(c.next_value))
FROM table1 t1
INNER JOIN Contents c ON t1.key_value = c.key_value
WHERE c.next_value <> ''
), FindNumber AS (
SELECT key_value
, CharPos = 2
+ IsNumeric(SubString(value, 3, 1))
+ IsNumeric(SubString(value, 2, 1))
, value
FROM Contents
)
SELECT *
FROM FindNumber
为1在内容中找到Cast(CharIndex('/', content) as bit)
为1找不到表示公式
(1 - Cast(CharIndex('/', content) as bit))
伪代码中的是
Cast(CharIndex('/', content) as bit) * (CharIndex('/', content) - 1)
+ (1 - Cast(CharIndex('/', content) as bit)) * Len(content))
因此,如果找到该字符,则公式返回 (IsFound) * (CharIndex('/', content) - 1)
+ (Not IsFound) * Len(content)
,否则返回CharIndex('/', content) - 1
Len(content)
返回一个int:1如果参数是数字,则返回0;如果参数不是,则返回0。
答案 4 :(得分:1)
要将字符串分隔为我们使用nodes() Method of XML data type的元素。要使用它,我们应该将content
字段转换为XML格式。只需将/
替换为</x><x>
即可。然后使用PATINDEX()函数查找字符串中的最后一位数字和第一个字母(%[0-9][a-z,A-Z]%
模式),我们将其分为数字和单词。
WITH CTE as
(
select id,key_value,
CAST('<x>'+REPLACE(content,'/','</x><x>')+'</x>' as XML) as xmlcont
FROM T
), CTE2 as
(
SELECT CTE.*,
a.f.value('data(.)','varchar(1000)') as xmlval
FROM CTE
CROSS APPLY CTE.xmlcont.nodes('x') as a(f)
)
SELECT ID,KEY_VALUE,
LEFT(XMLval,PATINDEX('%[0-9][a-z,A-Z]%',XMLval)) as [PERCENT],
SUBSTRING(XMLval,PATINDEX('%[0-9][a-z,A-Z]%',XMLval)+1,1000) as CONTENT
FROM CTE2