在可选子字符串之前获取列文本的简明方法?

时间:2013-07-14 15:53:50

标签: sql sql-server-2008 tsql

我正在寻找一种简洁的方法来在SQL Server 2008上获取可选标记之前的列的前导文本(所以没有IIF)。我有一个nvarchar列,在文本中的某个点可能有也可能没有标记,我需要返回完整的列值(如果没有标记)或者标记之前的位(如果有的话)是)。 (这不是我的架构,我无法改变它。)

我看到了这些选择:

  1. 使用CHARINDEXSUBSTRING执行此操作,这是详细而丑陋的(见下文),或

  2. 创建一个集中和隐藏丑陋的功能,并使用它(见下文)。

  3. 是否有更好的内置选项?如果是这样,它是什么? (这个问题的答案很可能是“不”。)

    (我认为this answer谈论PARSENAME可能是一个选项,但因为标记是可选的,所以它并没有真正帮助,而这样做而不是创建一个函数似乎是对我来说有点讨厌......)


    选项#1的示例:

    SELECT
        CASE
            WHEN CHARINDEX('{}', data, 1) = 0 THEN
                data
            ELSE
                SUBSTRING(data, 1, CHARINDEX('{}', data, 1) - 1)
        END AS trimmedData
    FROM ...
    

    咳嗽。破解。


    选项#2的示例

    SELECT dbo.StrUntil(data, '{}') as trimmedData
    FROM ...
    

    ...其中dbo.StrUntil类似于:

    IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'FN' AND name = 'StrUntil')
       exec('CREATE FUNCTION [dbo].[StrUntil]() RETURNS INT AS BEGIN RETURN 0 END')
    GO
    
    ALTER FUNCTION [dbo].[StrUntil](
    @str    nvarchar(max),
    @substr nvarchar(max)
    )
    RETURNS nvarchar(max)
    AS
    BEGIN
        RETURN CASE
            WHEN CHARINDEX(@substr, @str, 1) = 0 THEN
                @str
            ELSE
                SUBSTRING(@str, 1, CHARINDEX(@substr, @str, 1) - 1)
        END
    END
    

2 个答案:

答案 0 :(得分:2)

另一种方法是将标记附加到列的末尾,并在连接值上使用charindex

left(data, charindex(N'{}', data+N'{}')-1)

答案 1 :(得分:1)

我更喜欢将定义放在代码中而不是将其隐藏在函数中。一个原因是用户定义函数的性能 - 尽管自SQL Server早期以来性能有了很大提高。另一个原因是用户定义的功能今天可能对你有意义,但对未来的其他人可能没有意义。要了解查询,则需要查找函数的定义。 (如果您在编写的代码中定义了一组常用函数,则可以减轻这种情况。)

如果你需要经常这样做,那么我会建议两件事之一。首先,使用您希望定义它的任何方法创建一个包含TrimmedData列的视图。

另一种是用计算列定义表:

TrimmedData as (CASE when data like '%{}%' then left(data, charindex('{}', data)-1)
                     else data
                end)

在任何一种情况下,"表"的用户都可以使用它。 (或观点)。这可确保TrimmedData的定义始终相同且随时可用。

作为一个注释,使用likeleft()代替charindex()substr()是一个(不重要的)偏好问题:

SELECT (CASE when data like '%{}%' then left(data, charindex('{}', data) - 1)
             else data
        end) as TrimmedData
FROM ...

我强迫自己在此上下文中使用like来不断提醒自己,它在许多数据库上都经过高度优化,而且往往是查找子字符串的最佳表现方法。