昨天在求职面试中,我被问到这个问题,我对此一无所知。假设我有一个单词“曼哈顿”我想只显示字母'M','A','N','H','T' 在SQL中。怎么做? 任何帮助表示赞赏。
答案 0 :(得分:12)
嗯,这是我的解决方案(sqlfiddle) - 它旨在使用"关系SQL"操作,可能一直是面试官在概念上的目的。
完成的大部分工作只是将字符串转换为一组(pos,letter)记录,因为相关的最终应用DQL仅仅是应用了分组和排序的SELECT。
select letter
from (
-- All of this just to get a set of (pos, letter)
select ns.n as pos, substring(ss.s, ns.n, 1) as letter
from (select 'MANHATTAN' as s) as ss
cross join (
-- Or use another form to create a "numbers table"
select n from (values (1),(2),(3),(4),(5),(6),(7),(8),(9)) as X(n)
) as ns
) as pairs
group by letter -- guarantees distinctness
order by min(pos) -- ensure output is ordered MANHT
上述查询在SQL Server 2008中有效,但可能必须为其他供应商更改"Numbers Table"。否则,没有任何特定于供应商的使用 - 没有CTE,或函数的交叉应用,或程序语言代码..
话虽如此,上面的内容是为了展示一种概念方法 - SQL被设计用于集合和关系以及跨记录的多重性;从某种意义上说,上面的例子只是对这种情况的歪曲。
检查中间关系,
select ns.n as pos, substring(ss.s, ns.n, 1) as letter
from (select 'MANHATTAN' as s) as ss
cross join (
select n from (values (1),(2),(3),(4),(5),(6),(7),(8),(9)) as X(n)
) as ns
使用cross join生成字符串(1行)的笛卡尔积和数字(9行);然后使用字符串和每个编号应用substring
函数,以根据其位置获取每个字符。结果集包含记录 -
POS LETTER
1 M
2 A
3 N
..
9 N
然后外部选择组根据字母对每个记录进行分组,结果记录按建立分组的字母的最小(第一)发生位置排序。 (没有字母的顺序会有所不同,但最终的顺序不会得到保证。)
答案 1 :(得分:7)
一种方法(如果使用SQL Server)使用recursive CTE (Commom Table Expression)。
DECLARE @source nvarchar(100) = 'MANHATTAN'
;
WITH cte AS (
SELECT SUBSTRING(@source, 1, 1) AS c1, 1 as Pos
WHERE LEN(@source) > 0
UNION ALL
SELECT SUBSTRING(@source, Pos + 1, 1) AS c1, Pos + 1 as Pos
FROM cte
WHERE Pos < LEN(@source)
)
SELECT DISTINCT c1 from cte
SqlFiddle for this is here。我不得不为SqlFiddle内联@source
,但上面的代码在Sql Server中工作正常。
第一个SELECT
生成初始行(在本例中为&#39; M&#39;,1)。第二个SELECT
是生成后续行的递归部分,每次Pos
列都会递增,直到最终满足终止条件WHERE Pos < LEN(@source)
。最终选择删除重复项。在内部,SELECT DISTINCT
对行进行排序以便于删除重复项,这就是为什么最终输出恰好按字母顺序排列的原因。由于您没有将订单指定为要求,因此我将其保留原样。但您可以修改它以使用GROUP
代替MIN(Pos)
,如果您需要输出字符&#39;原始订单。
同样的技术可以用于生成字符串的所有Bigrams,只需对上面的一般结构稍作修改。
答案 2 :(得分:3)
declare @charr varchar(99)
declare @lp int
set @charr='Manhattan'
set @lp=1
DECLARE @T1 TABLE (
FLD VARCHAR(max)
)
while(@lp<=LEN(@charr))
begin
if(not exists(select * from @T1 where FLD=(select SUBSTRING(@charr,@lp,1))))
begin
insert into @T1
select SUBSTRING(@charr,@lp,1)
end
set @lp=@lp+1
end
select * from @T1
检查这可能对你有帮助
答案 3 :(得分:3)
这是 @ user2864740 的Oracle版本的答案。唯一的区别是你如何构建“数字表”(加上别名的细微差别)
select letter
from (
select ns.n as pos, substr(ss.s, ns.n, 1) as letter
from (select 'MANHATTAN' as s from dual) ss
cross join (
SELECT LEVEL as n
FROM DUAL
CONNECT BY LEVEL <= 9
ORDER BY LEVEL) ns
) pairs
group by letter
order by min(pos)