【问题标题】:Formatting Phone Number to US Format (###) ###-####将电话号码格式化为美国格式 (###) ###-####
【发布时间】:2019-10-07 16:20:58
【问题描述】:

我正在尝试将 SQL Server 数据库中的大约 1000 个电话号码重新格式化为美国格式 (###) ###-####

目前电话号码的格式多种多样,从##########、###-###-####,一种是###)-### -####。还有一个只有六位数。

作为第一步,我一直在尝试隔离所有这些行中的数字,但它只是返回与它们原来相同的值。

select SUBSTRING(phone, PATINDEX('%[0-9]%', phone), LEN(phone)) from people

我怎样才能最好地编写一个查询,将它们全部格式化为(###) ###-####

预期输出:

(555) 222-3333
(555) 444-3030
(555) 092-0920
(555) 444-4444

【问题讨论】:

标签: sql sql-server format substring phone-number


【解决方案1】:

由于已经提出了一个建议,并且在字符串中隔离数字的建议使用了 while 循环,因此我需要发布一个不使用任何循环的替代方案。相反,它使用计数或数字表。有很多解决方案。我喜欢使用速度快且读取次数为零的视图。

这是我的计数表版本。

create View [dbo].[cteTally] as

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )
select N from cteTally

接下来我们需要一个表值函数来使用我们的计数表删除不是数字的字符。这也非常快,因为我们使用的是计数表而不是循环。

create function GetOnlyNumbers
(
    @SearchVal varchar(8000)
) returns table as return

    with MyValues as
    (
        select substring(@SearchVal, N, 1) as number
            , t.N
        from cteTally t 
        where N <= len(@SearchVal)
            and substring(@SearchVal, N, 1) like '[0-9]'
    )

    select distinct NumValue = STUFF((select number + ''
                from MyValues mv2
                order by mv2.N
                for xml path('')), 1, 0, '')
    from MyValues mv

现在我们已经完成了所有的跑腿工作,我们可以专注于手头的任务。由于您没有提供任何示例数据,我只是编造了一些东西。我不确定这是否代表您的数据,但这适用于我创建的示例数据。

if OBJECT_ID('tempdb..#Something') is not null
    drop table #Something

create table #Something(SomeVal varchar(100))

insert #Something values
('Maybe you have other stuff in here. 5552223333 additional characters can cause grief')
, ('321-654-9878')
, ('123)-333-4444')
, ('1234567')

select replace(format(try_convert(bigint, n.NumValue), '(###) ###-####'), '() ', '')
    , n.NumValue
from #Something s
cross apply dbo.GetOnlyNumbers(s.SomeVal) n

格式化数据的输出如下所示:

(555) 222-3333
(321) 654-9878
(123) 333-4444
123-4567

【讨论】:

    【解决方案2】:

    如果这种重新格式化将被重复使用的东西,那么按照@GSerg 的建议创建一个 UDF 将是可行的方法。

    如果这只是一次清理,您可以尝试一下。

    首先使用一系列嵌套的 REPLACE() 函数将所有数字替换为空字符串。

    DECLARE @PhoneNumbers TABLE (
    
    Number varchar (20))
    
    INSERT INTO @PhoneNumbers VALUES ('(888-239/1239')
    INSERT INTO @PhoneNumbers VALUES ('222.1234')
    
    SELECT 
    REPLACE(
        REPLACE(
            REPLACE(
                REPLACE(
                    REPLACE(
                        REPLACE(
                            REPLACE(
                                REPLACE(
                                    REPLACE(
                                        REPLACE(Number, '0', '')
                                    , '1', '')
                                , '2', '')
                            , '3', '')
                        , '4', '')
                    , '5', '')
                , '6', '')
            , '7', '')
        , '8', '')
    , '9', '')
    FROM @PhoneNumbers
    

    然后将这些结果非数字字符放入各自嵌套的 REPLACE() 函数中并格式化结果。您将不得不单独处理每个长度。如果您只有 7 位数字,并且您想将其格式化为 10 位数字,您希望这些额外的 3 位数字是什么。这将处理 10 位数的电话号码。

    SELECT FORMAT(x.NumbersOnly, '(###) ###-####')
    FROM 
    (
        SELECT 
        CONVERT(BIGINT,
            REPLACE(
                REPLACE(
                    REPLACE(
                        REPLACE(Number, '(', '')
                    , '-', '')
                , '/', '')
            , '.', '')
        ) AS NumbersOnly
        FROM @PhoneNumbers
    ) x
    WHERE LEN(x.NumbersOnly) = 10
    

    这里是dbfiddle

    【讨论】:

      猜你喜欢
      • 2010-10-14
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-08-16
      • 2011-03-06
      • 2015-10-02
      相关资源
      最近更新 更多