fra*_*lic 18 sql sql-server string puzzle
在SQL Server中是否有一种优雅的方法可以在所有行中查找单个varchar(50)列中的所有不同字符?
如果可以在没有游标的情况下完成奖励积分:)
例如,假设我的数据包含3行:
productname
-----------
product1
widget2
nicknack3
Run Code Online (Sandbox Code Playgroud)
不同的字符库存将是"productwigenka123"
mdm*_*dma 19
这是一个查询,它将每个字符作为单独的行返回,以及出现的次数.假设你的桌子被称为'产品'
WITH ProductChars(aChar, remain) AS (
SELECT LEFT(productName,1), RIGHT(productName, LEN(productName)-1)
FROM Products WHERE LEN(productName)>0
UNION ALL
SELECT LEFT(remain,1), RIGHT(remain, LEN(remain)-1) FROM ProductChars
WHERE LEN(remain)>0
)
SELECT aChar, COUNT(*) FROM ProductChars
GROUP BY aChar
Run Code Online (Sandbox Code Playgroud)
要将它们全部合并为一行(如问题中所述),请将最终更改SELECT
为
SELECT aChar AS [text()] FROM
(SELECT DISTINCT aChar FROM ProductChars) base
FOR XML PATH('')
Run Code Online (Sandbox Code Playgroud)
以上使用了我在这里找到的一个很好的黑客,它模仿了GROUP_CONCAT
MySQL.
第一级递归被展开,因此查询不会在输出中返回空字符串.
使用它(适用于任何支持CTE的RDBMS):
select x.v into prod from (values('product1'),('widget2'),('nicknack3')) as x(v);
Run Code Online (Sandbox Code Playgroud)
测试查询:
with a as
(
select v, '' as x, 0 as n from prod
union all
select v, substring(v,n+1,1) as x, n+1 as n from a where n < len(v)
)
select v, x, n from a -- where n > 0
order by v, n
option (maxrecursion 0)
Run Code Online (Sandbox Code Playgroud)
最终查询:
with a as
(
select v, '' as x, 0 as n from prod
union all
select v, substring(v,n+1,1) as x, n+1 as n from a where n < len(v)
)
select distinct x from a where n > 0
order by x
option (maxrecursion 0)
Run Code Online (Sandbox Code Playgroud)
Oracle版本:
with a(v,x,n) as
(
select v, '' as x, 0 as n from prod
union all
select v, substr(v,n+1,1) as x, n+1 as n from a where n < length(v)
)
select distinct x from a where n > 0
Run Code Online (Sandbox Code Playgroud)
鉴于您的列是varchar,这意味着它只能在您拥有的任何代码页上存储代码0到255中的字符.如果您只使用32-128 ASCII代码范围,那么您可以逐个查看是否有任何字符32-128.以下查询执行此操作,查看sys.objects.name:
with cteDigits as (
select 0 as Number
union all select 1 as Number
union all select 2 as Number
union all select 3 as Number
union all select 4 as Number
union all select 5 as Number
union all select 6 as Number
union all select 7 as Number
union all select 8 as Number
union all select 9 as Number)
, cteNumbers as (
select U.Number + T.Number*10 + H.Number*100 as Number
from cteDigits U
cross join cteDigits T
cross join cteDigits H)
, cteChars as (
select CHAR(Number) as Char
from cteNumbers
where Number between 32 and 128)
select cteChars.Char as [*]
from cteChars
cross apply (
select top(1) *
from sys.objects
where CHARINDEX(cteChars.Char, name, 0) > 0) as o
for xml path('');
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
15806 次 |
最近记录: |