应用掩码在SQL Server查询/视图中格式化字符串

时间:2010-08-23 09:52:36

标签: sql sql-server

是否有一种巧妙的方法可以将掩码应用于SQL Server查询中的字符串?

我有两个表,一个是电话号码,存储为varchar,没有文字0155567890,还有一个电话类型,其中包含该电话号码类型的掩码:(##) #### ####

返回字符串的最佳方法是什么(对于合并文档),以便查询返回完全格式化的电话号码:

(01) 5556 7890

7 个答案:

答案 0 :(得分:7)

我也需要这个,并且由于Sjuul的伪代码,我能够创建一个函数来执行此操作。

CREATE FUNCTION [dbo].[fx_FormatUsingMask] 
(
    -- Add the parameters for the function here
    @input nvarchar(1000),
    @mask nvarchar(1000)
)
RETURNS nvarchar(1000)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @result nvarchar(1000) = ''
    DECLARE @inputPos int = 1
    DECLARE @maskPos int = 1
    DECLARE @maskSign char(1) = ''

    WHILE @maskPos <= Len(@mask)
    BEGIN
        set @maskSign = substring(@mask, @maskPos, 1)

        IF @maskSign = '#'
        BEGIN
            set @result = @result + substring(@input, @inputPos, 1)
            set @inputPos += 1
            set @maskPos += 1
        END
        ELSE
        BEGIN
            set @result = @result + @maskSign
            set @maskPos += 1
        END
    END
    -- Return the result of the function
    RETURN @result

END

答案 1 :(得分:2)

这正是我头脑中的想法。我不知道这是否是最好的解决方案,但我认为它应该是可行的。

使用名称applyMask(orso)

创建一个函数

伪代码:

WHILE currentPosition < Length(PhoneNr) AND safetyCounter < Length(Mask)
    IF currentSign = "#"
        result += Mid(PhoneNr, currentPosition, 1)
        currentPosition++
    ELSE
        result += currentSign
        safetyCounter++
    END
END
Return result

答案 2 :(得分:2)

以防万一有人需要表值函数。

方法1

create function ftMaskPhone
(
    @phone varchar(30),
    @mask varchar(50)
)
returns table as
return
    with ci(n, c, nn) as (
        select
            1,
            case
                when substring(@mask, 1, 1) = '#' then substring(@phone, 1, 1)
                else substring(@mask, 1, 1)
            end,
            case when substring(@mask, 1, 1) = '#' then 1 else 0 end
        union all
        select
            n + 1,
            case
                when substring(@mask, n + 1, 1) = '#' then substring(@phone, nn + 1, 1)
                else substring(@mask, n + 1, 1)
            end,
            case when substring(@mask, n + 1, 1) = '#' then nn + 1 else nn end
        from ci where n < len(@mask))
    select (select c + '' from ci for xml path(''), type).value('text()[1]', 'varchar(50)') PhoneMasked
GO

然后将其应用为

declare @mask varchar(50)
set @mask = '(##) #### ####'

select pm.PhoneMasked
from Phones p
    outer apply ftMaskPhone(p.PhoneNum, @mask) pm

方法2

让我们留下一个历史。低于一个是更高效的。

create function ftMaskPhone
(
    @phone varchar(30),
    @mask varchar(50)
)
returns table as
return
    with v1(N) as (
        select 1 union all select 1 union all select 1 union all select 1 union all select 1
        union all
        select 1 union all select 1 union all select 1 union all select 1 union all select 1
    ),
    v2(N) as (select 1 from v1 a, v1 b),
    v3(N) as (select top (isnull(len(@mask), 0)) row_number() over (order by @@spid) from v2),
    v4(N, C) as (
        select N, isnull(substring(@phone, case when c.m = 1 then row_number() over (partition by c.m order by N) end, 1), substring(@mask, v3.N, 1))
        from v3
            cross apply (select case when substring(@mask, v3.N, 1) = '#' then 1 end m) c
    )
    select Value = (
        select c + ''
        from v4
        order by N
        for xml path(''), type
    ).value('text()[1]', 'varchar(50)')
go

答案 3 :(得分:1)

@Sean指出,SQL Server 2012及更高版本支持FORMAT函数,该函数几乎可以满足您的需要,并具有以下警告:

  • 它需要一个数字来格式化,而不是VARCHAR。这可以通过使用CAST来解决。

  • 提供的掩码((##) #### ####CAST会删除前导零,而您留下(1) 5556 7890。您可以将掩码更新为(0#) #### ####。在您代表Australian phone number的肢体上,似乎反正0总是存在:

    在澳大利亚境内,要访问除呼叫者所在地区(包括使用“移动”电话的呼叫者)以外的“区域”内的座机电话的“号码”,首先必须拨打澳大利亚的“中继线访问代码”为0加上“区域”代码,后跟“本地”数字。因此,“全国号码”(FNN)有十个数字:0x xxxx xxxx。

但是最终,我会认为SQL Server不是不是处理数据表示/格式(与日期一样,与电话号码一样)的最佳场所。我建议使用Google的libphonenumber之类的方法在客户端进行此操作。将电话号码输入数据库后,您可以存储电话号码本身以及电话号码所属的国家/地区,然后在显示电话号码(或进行类似呼叫或检查有效性的操作)时使用该号码。

答案 4 :(得分:0)

如果你需要“屏蔽”,而是用另一个隐藏真实值,然后“取消屏蔽”字符串,你可以尝试这个功能,或者为此扩展它。 :)

https://stackoverflow.com/a/22023329/2175524

答案 5 :(得分:0)

有一个内置的FORMAT函数,几乎可以正常工作。不幸的是,它将int作为第一个参数,因此它去除了前导零:

select format(0155567890 ,'(##) #### ####')

(1) 5556 7890

答案 6 :(得分:-1)

我想隐藏一些信息,所以我使用了RIGHT函数。它仅显示右侧的前4个字符。

CONCAT('xxx-xx-', RIGHT('03466045896', 4))

以上代码将显示“ xxx-xx-5896