返回列中以字符开头的所有单词

问题描述 投票:0回答:5

我有一个 VARCHAR 列,其中包含如下数据:

abc = :abc and this = :that

我需要一个查询来查找此数据列中以冒号开头的所有特殊“单词”。我真的不需要任何其他数据(ID 或其他数据),重复就可以了。如果需要的话,我可以稍后在 Excel 中删除重复项。因此,如果这是唯一的行,我想要这样的输出:

SpecialWords
:abc
:that

我想它需要一个 CHARINDEX 或类似的东西。但由于该列中可能有多个特殊单词,我不能只找到第一个 : 并删除其余的。

非常感谢任何帮助!预先感谢!

sql sql-server t-sql sql-server-2014
5个回答
2
投票

您必须根据空格拆分此值

并仅返回以冒号开头的字段
:
,我提供了两种解决方案来根据您需要的结果类型(表或单个值)实现此目的

表值函数

您可以创建一个 TV 函数来将此列拆分为一个表:

CREATE FUNCTION [dbo].[GETVALUES] 
    (   
    @DelimitedString    varchar(8000)
    )
RETURNS @tblArray TABLE
    (
    ElementID   int IDENTITY(1,1),  -- Array index
    Element     varchar(1000)               -- Array element contents
    )
AS
BEGIN

    -- Local Variable Declarations
    -- ---------------------------
    DECLARE @Index      smallint,
                    @Start      smallint,
                    @DelSize    smallint

    SET @DelSize = 1

    -- Loop through source string and add elements to destination table array
    -- ----------------------------------------------------------------------
    WHILE LEN(@DelimitedString) > 0
    BEGIN

        SET @Index = CHARINDEX(' ', @DelimitedString)

        IF @Index = 0
            BEGIN

            IF ((LTRIM(RTRIM(@DelimitedString))) LIKE ':%')
                INSERT INTO
                    @tblArray 
                    (Element)
                VALUES
                    (LTRIM(RTRIM(@DelimitedString)))

                BREAK
            END
        ELSE
            BEGIN

             IF (LTRIM(RTRIM(SUBSTRING(@DelimitedString, 1,@Index - 1)))) LIKE ':%'
                INSERT INTO
                    @tblArray 
                    (Element)
                VALUES
                    (LTRIM(RTRIM(SUBSTRING(@DelimitedString, 1,@Index - 1))))

                SET @Start = @Index + @DelSize
                SET @DelimitedString = SUBSTRING(@DelimitedString, @Start , LEN(@DelimitedString) - @Start + 1)

            END
    END

    RETURN
END

您可以像下面这样使用它:

DECLARE @SQLStr varchar(100)
SELECT @SQLStr = 'abc = :abc and this = :that and xyz = :asd'

SELECT
    *
FROM
 dbo.GETVALUES(@SQLStr)

结果:

标量值函数

如果您需要返回一个值(不是表格),那么您可以使用此函数,它将返回由 分隔的所有值(换行 + 回车符

CHAR(13) + CHAR(10)

CREATE FUNCTION dbo.GetValues2
(
    @DelimitedString    varchar(8000)
)
RETURNS varchar(8000)
AS
BEGIN

       DECLARE @Index      smallint,
                    @Start      smallint,
                    @DelSize    smallint,
                    @Result varchar(8000)

    SET @DelSize = 1
    SET @Result = ''

    WHILE LEN(@DelimitedString) > 0
    BEGIN

        SET @Index = CHARINDEX(' ', @DelimitedString)

        IF @Index = 0
            BEGIN

            if (LTRIM(RTRIM(@DelimitedString))) LIKE ':%'
           SET @Result = @Result + char(13) + char(10) +  (LTRIM(RTRIM(@DelimitedString)))

                BREAK
            END
        ELSE
            BEGIN

             IF (LTRIM(RTRIM(SUBSTRING(@DelimitedString, 1,@Index - 1)))) LIKE ':%'

                    SET @Result = @Result + char(13) + char(10) + (LTRIM(RTRIM(SUBSTRING(@DelimitedString, 1,@Index - 1))))

                SET @Start = @Index + @DelSize
                SET @DelimitedString = SUBSTRING(@DelimitedString, @Start , LEN(@DelimitedString) - @Start + 1)

            END
    END


    return @Result
END
GO

您可以像下面这样使用它

DECLARE @SQLStr varchar(100)
SELECT @SQLStr = 'abc = :abc and this = :that and xyz = :asd'

SELECT dbo.GetValues2(@SQLStr)

结果

表格结果换行不可见,只需将数据复制到编辑器中,它就会如图所示

参考文献


0
投票

一种方法是编写专门的 SPLIT 函数。我建议从互联网上获取一个 TSQL Split 函数,看看是否可以根据您的需要调整代码。

从头开始,您可以编写一个函数,使用 CHARINDEX 循环遍历列值,直到找不到更多

:
字符。


0
投票

使用

charindex
怎么样?

rextester 示例:

create table mytable (testcolumn varchar(20))
insert into mytable values ('this = :that'),('yes'), (':no'), ('abc = :abc')


select right(testcolumn, charindex(':', reverse(testcolumn)) - 1) from mytable
where testcolumn like '%:%'

参考

SQL 选择字符后的所有内容

更新

解决萨米人的问题:

没看到两个单词可以在一个冒号中,这样怎么样?

select replace(substring(testcolumn, charindex(':', testcolumn), len(testcolumn)), ':', '')

再次更新

我明白了,实际说法是

this = :that and that = :this


0
投票

如果性能很重要,那么您需要使用内联表值函数来分割字符串并提取您需要的内容。您可以使用 delimitedSplit8KdelimitedSplit8K_lead 来实现此目的。

declare @string varchar(8000) = 'abc = :abc and this = :that';

select item 
from dbo.DelimitedSplit8K(@string, ' ')
where item like ':%';

返回:

item
------
:abc
:that

为了获得比我上面发布的更好的性能,您可以使用 ngrams8k,如下所示:

declare @string varchar(8000) = 'abc = :abc and this = :that';

select position, item = 
  substring(@string, position,
    isnull(nullif(charindex(' ',@string,position+1),0),8000)-position)
from dbo.ngrams8k(@string, 1)
where token = ':';

这甚至可以为您提供正在搜索的项目的位置:

position   item
---------- -------
7          :abc
23         :that

0
投票

我会使用递归 CTE。 https://learnsql.com/blog/recursive-cte-sql-server/

DROP TABLE IF EXISTS #allwords;
CREATE TABLE #allwords (id INT, S VARCHAR(MAX));
    
INSERT INTO #allwords (id, S)
VALUES
(1, 'abc = :abc and this = :that'),
(2, 'abc = :abc'),
(3, 'abc = :abc this = :that other = :other another = :another');
    
WITH recursivecte
AS (SELECT id,
S,
SUBSTRING(   S, --Original String
CHARINDEX(':', S, 0) + 1, -- First separator
ABS(CHARINDEX(' ', -- Abs for missing space
S, 
CHARINDEX(':', S, 0)) - 
CHARINDEX(':', S, 0)) 
) AS Token,
SUBSTRING(S, CHARINDEX(':', S, 0) + 1, LEN(S)) AS TokenRemoved
FROM #allwords a
WHERE CHARINDEX(':', S, 0) > 0
UNION ALL
SELECT id,
S,
SUBSTRING(
TokenRemoved,
CHARINDEX(':', TokenRemoved, 0) + 1,
ABS(CHARINDEX(' ', 
TokenRemoved, 
CHARINDEX(':', TokenRemoved, 0))
- CHARINDEX(':', TokenRemoved, 0))
),
SUBSTRING(TokenRemoved, 
CHARINDEX(':', TokenRemoved, 0) + 1, 
LEN(TokenRemoved)) AS TokenRemoved
FROM recursivecte R
WHERE CHARINDEX(':', TokenRemoved, 0) > 0)
SELECT id,
S,
Token
FROM recursivecte
ORDER BY id,
LEN(recursivecte.TokenRemoved) DESC;
© www.soinside.com 2019 - 2024. All rights reserved.