如何在SQL中拆分和显示单词中的不同字母?

时间:2014-05-24 04:21:35

标签: sql

昨天在求职面试中,我被问到这个问题,我对此一无所知。假设我有一个单词“曼哈顿”我想只显示字母'M','A','N','H','T' 在SQL中。怎么做? 任何帮助表示赞赏。

4 个答案:

答案 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)