如何在SQL中检索字符串的第一,第二和第三个单词?

时间:2019-01-03 16:01:27

标签: sql sql-server ssms

我需要一个查询,该查询将提取字符串的第一个第二个和第三个单词。

我在每行中大约有5个单词,并且在同一行(1行)中,我只需要5个单词中的前三个单词。示例“ ATV BDSG 232用其他单词继续”。

我只需要在前一行(同一行)中同时使用前三个单词,例如“ ATV BDSG 232”。该表大约有1000行,在表的结尾,我应该又有1000行,但是每行应仅包含字符串的前三个字。

我找到了一个查询,该查询对于提取前两个类似栈溢出中讨论的“ ATV BDSG”的查询效果很好。查询是

"SELECT SUBSTRING(field1, 0, CHARINDEX(' ', field1, CHARINDEX(' ', field1, 0)+1)) FROM Table"

我们可以导出前三个单词来得出吗?

预先感谢

5 个答案:

答案 0 :(得分:1)

如果您不想创建专用功能,则可以使用连续的CROSS APPLY s:

SELECT
    T.s,
    FirstSpace.i,
    SecondSpace.j,
    ThirdSpace.k,
    CASE
        When ThirdSpace.k > 0 THEN LEFT(T.s, Thirdspace.k - 1)
        ELSE T.S
    END AS Phrase
FROM t
    CROSS APPLY (SELECT CHARINDEX(' ', T.s, 1)) AS FirstSpace(i)
    CROSS APPLY (SELECT CHARINDEX(' ', T.S, FirstSpace.i + 1)) AS SecondSpace(j)
    CROSS APPLY (SELECT CHARINDEX(' ', T.s, SecondSpace.j + 1)) AS ThirdSpace(k)

为您提供所需的结果:

|                   s                    | i | j | k  | phrase           |
|----------------------------------------|---|---|----|------------------|
| ATV BDSG 232 Continue with other words | 4 | 9 | 13 | ATV BDSG 232     |

答案 1 :(得分:0)

事情很简单,SQL Server提供的STRING_SPLIT()函数使事情变得简单

DECLARE @Var VARCHAR(100) = 'ATV BDSG 232 Continue with other words';

SELECT Word
FROM
    (
     SELECT Value AS Word,
            ROW_NUMBER()OVER(ORDER BY (SELECT NULL)) RN
     FROM STRING_SPLIT(@Var, ' ')
    ) T
WHERE RN <= 3;

但是由于您正在使用2012版本,因此您需要定义自己的函数。

您也可以采取艰难的方式,首先需要获取第一个单词,然后将其替换为''并获取第二个单词,然后对第三个单词执行相同的操作

DECLARE @Var VARCHAR(100) = 'ATV BDSG 232 Continue with other words';

WITH FW AS
(
  SELECT LEFT(@Var, CHARINDEX(' ', @Var)) FirstWord
),
 SW AS
(
  SELECT LEFT(REPLACE(@Var, FirstWord, ''),
              CHARINDEX(' ', REPLACE(@Var, FirstWord, ''))) SecondWord
  FROM FW
)
SELECT FirstWord,
       SecondWord,
       LEFT(REPLACE(REPLACE(V, FirstWord, ''), SecondWord, ''),
       CHARINDEX(' ', REPLACE(REPLACE(V, FirstWord, ''), SecondWord, ''))
       ) ThirdWord
FROM
    (
     SELECT *, @Var V
     FROM FW CROSS APPLY SW
    ) T

Demo

更新

如果您想选择第三个单词,那么

SELECT SUBSTRING(Str, 0, CHARINDEX(' ', Str, CHARINDEX(' ', Str, CHARINDEX(' ', Str, 0)+1)+1)) Words
FROM Strings

Demo

答案 2 :(得分:0)

 --make some test data

declare @test as nvarchar(100) = 'my test   string  for words';

select 1 id, cast('my test   string  for words' as nvarchar(max)) word into #test;
insert #test (id,word) values (2,'a  b c d e f g hhh   yyyyyy') ;
insert #test (id,word) values (3,'  a required test string  d e f g hhh   yyyyyy') ;
insert #test (id,word) values (4,'a quick test') ;
insert #test (id,word) values (5,'a test') ;
insert #test (id,word) values (6,'last') ;

--break up letters, count the first 3 words
;WITH CTE AS (SELECT 1 x, substring(@test,1,1) charx
             UNION ALL
             SELECT X + 1, substring(@test,x + 1,1) from CTE WHERE x < len(@test) 
             )
             select * from cte c3 where (SELECT count(0) cnt FROM CTE c1 JOIN CTE c2 on c1.x <= c3.x and c1.x + 1 = c2.x and c1.charx =' ' and c2.charx != ' ') < 3



;WITH   tabx as (select id, cast(ltrim(word) as nvarchar(max)) 'word' from #test),    --do some ltrim
        CTE AS (
                SELECT id, 1 x, substring(word,1,1) charx from tabx
                UNION ALL
                SELECT t.id, c.X + 1, substring(t.word,x + 1,1)  
                        from tabx t 
                            JOIN CTE c on c.id =  t.id and x < len(t.word) 
             ),
        disj as
             (select * from cte c3 where 
                        (SELECT count(0) cnt 
                                FROM CTE c1 
                                JOIN CTE c2 on c1.id = c3.id and c1.id = c2.id and c1.x <= c3.x and c1.x + 1 = c2.x and c1.charx =' ' and c2.charx != ' '
                        ) < 3
                ),
        rj as 
            (select disj.id,disj.x, disj.charx z  
                                from disj 
                                where disj.x = 1 
                UNION ALL 
                    select d.id, d.x, r.z + d.charx    
                            FROM rj r 
                            join disj d on r.id = d.id and r.x + 1 = d.x
            )
                select *  
                    from rj r1  
                        cross apply (select max(r2.x) TheRow from rj r2 where r1.id = r2.id) dq
                    where r1.x = dq.TheRow  
                    order by r1.id;

 --delete test data
drop table #test 

答案 3 :(得分:0)

/* This is not perfect - but interesting */
declare @t table (fullname varchar(100))
insert @t values('Mr Jones'),('Mrs Amy smith'),('Jim Smith'),('Dr Harry Web '),('Paul Fred andrew jones')

select fullname,

a.value as a ,
b.Value as b,
c.Value as c,
d.Value as d,
e.Value as e,
f.value as f

from @t
outer apply (select top 1 value from STRING_SPLIT(fullname, ' '))  a 
outer apply (select top 1 value from STRING_SPLIT(fullname, ' ')   where value not in (a.value ))  b
outer apply (select top 1 value from STRING_SPLIT(fullname, ' ')   where value not in (a.value,b.value ) ) c
outer apply (select top 1 value from STRING_SPLIT(fullname, ' ')   where value not in (a.value,b.value,c.value ))  d
outer apply (select top 1 value from STRING_SPLIT(fullname, ' ')   where value not in (a.value,b.value,c.value,d.value) ) e
outer apply (select top 1 value from STRING_SPLIT(fullname, ' ')   where value not in (a.value,b.value ,c.value,d.value,e.value) ) f

答案 4 :(得分:0)

要选择第一个单词-

Select top 1 Ltrim(Rtrim(value)) FROM STRING_SPLIT(@input,' ')

仅选择第二个单词-

Select Ltrim(Rtrim(value)) from STRING_SPLIT(@input,' ') Order by (Select NULL) OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY