【问题标题】:TSQL to transform Address into a Mailing Address - SQL Server 2005TSQL 将地址转换为邮寄地址 - SQL Server 2005
【发布时间】:2010-12-11 05:39:18
【问题描述】:

我想将地址(Line1、Line2、Line3、City、State、ZIP)转换为没有空行且连接了 City、State 和 ZIP 的邮寄地址(Addr1、Addr2、Addr3、Addr4)一起在一条线上。有一个函数来做到这一点会非常好。


第 1 行=
Line2=123 某处
第 3 行=
城市=底特律
状态=MI
邮编=48000

这是传入地址的表结构:

IF OBJECT_ID('tempdb..#Employee') IS NOT NULL DROP TABLE #Employee
CREATE TABLE #Employee (Line1 VARCHAR(30), Line2 VARCHAR(30), Line3 VARCHAR(30), 
  City VARCHAR(17), State VARCHAR(2), ZIP VARCHAR(10)) 
GO 

INSERT #Employee VALUES ('', '123 Somewhere', '', 'Detroit', 'MI', '48000') 

SELECT * FROM #Employee  

生成的邮寄地址

Addr1=123 某处
Addr2=底特律 MI 48000
地址3=
地址4=

或一个带有 cr 字符的字段
地址=
123 某处cr
底特律 MI 48000 cr
cr
cr

一个函数可以很好地返回 Addr1、Addr2、Addr3 和 Addr4,或者只返回 Addr 。

SqueezeAddress(Line1, Line2, Line3, City, State, ZIP)
然后 SqueezeAddress 将返回 Addr1、Addr2、Addr3、Addr4

带cr的地址

所有 Addr1-4 行将是 VARCHAR (40) 或者如果使用一个字段 Addr VARCHAR (200)

根据 Phil 在下面 cmets 中的要求,这是当前正在使用的逻辑(删除了许多字段以使其更易于阅读):

SELECT Line1, Line2, Line3, 
    ISNULL(LTRIM(RTRIM(ADDR.City)) + ', ','')  + ISNULL(ADDR.RegionCode,'') 
    + ' ' + ISNULL(ADDR.PostalCode,'') AS Line4,

  UPDATE #tmpBilling
  SET Line1 = Line2, Line2 = NULL
  WHERE ISNULL(Line1, '') = ''
    AND ISNULL(Line2, '') <> ''

  UPDATE #tmpBilling
  SET Line2 = Line3, Line3 = NULL
  WHERE ISNULL(Line2, '') = ''
    AND ISNULL(Line3, '') <> ''

  UPDATE #tmpBilling
  SET Line2 = Line4, Line4 = NULL
  WHERE ISNULL(Line2, '') = ''
    AND ISNULL(Line4, '') <> ''

  UPDATE #tmpBilling
  SET Line3 = Line4, Line4 = NULL
  WHERE ISNULL(Line3, '') = ''
    AND ISNULL(Line2, '') <> ''

【问题讨论】:

  • 这些是列,不是行,对吧?
  • 福斯科:更正所有字段都是列。
  • Phil:我还没有尝试过任何东西。我注意到存储过程中有一些逻辑可以将 Addr1 字段一对一地写入表中。然后 4 个不同的 UPDATE 语句将进行比较并在其中一个为空时交换地址行。我会把上面的代码贴出来。

标签: sql-server sql-server-2005 tsql


【解决方案1】:

我可能在这里遗漏了一些东西,但如果这只是简单的字符串连接,那么这将起作用......

设置测试数据(我添加了几个样本)

IF OBJECT_ID('tempdb..#Employee') IS NOT NULL DROP TABLE #Employee 
CREATE TABLE #Employee (Line1 VARCHAR(30), Line2 VARCHAR(30), Line3 VARCHAR(30),  
  City VARCHAR(17), State VARCHAR(2), ZIP VARCHAR(10))  
GO  

INSERT #Employee VALUES ('', '123 Somewhere', '', 'Detroit', 'MI', '48001')  
INSERT #Employee VALUES ('123 Somewhere', 'Suite 500', '', 'Detroit', 'MI', '48002')  
INSERT #Employee VALUES ('123 Somewhere', 'Suite 500', 'attn: JP', 'Detroit', 'MI', '48003')  

SELECT * FROM #Employee 

从这里,您所要做的就是将字符串缝合在一起。此版本假定您有 null 和空字符串要考虑在内。

SELECT
    isnull(nullif(Line1, '') + char(13) + char(10), '')
  + isnull(nullif(Line2, '') + char(13) + char(10), '')
  + isnull(nullif(Line3, '') + char(13) + char(10), '')
  + City + ' ' + State + ' ' + ZIP
  + char(13) + char(10) + '------------------------------'
 from #Employee

将其包装成一个函数:

CREATE FUNCTION dbo.SqueezeAddress
 (
   @Line1  varchar(30)
  ,@Line2  varchar(30)
  ,@Line3  varchar(30)
  ,@City   varchar(17)
  ,@State    varchar(2)
  ,@Zip    varchar(10)
 )
RETURNS varchar(200)
AS
 BEGIN
    RETURN isnull(nullif(@Line1, '') + char(13) + char(10), '')
            + isnull(nullif(@Line2, '') + char(13) + char(10), '')
            + isnull(nullif(@Line3, '') + char(13) + char(10), '')
            + @City + ' ' + @State + ' ' + @ZIP
            + char(13) + char(10) + '------------------------------'
 END
GO

最后,将函数放入查询中:

SELECT dbo.SqueezeAddress(Line1, Line2, Line3, City, State, Zip)
 from #Employee

【讨论】:

  • 干得好。为其他帖子辩护。我刚刚添加了一个以回车作为分隔符的返回字段。这将在 Word 2007 邮件合并中使用,我很确定这一字段方法应该有效。
【解决方案2】:

更直接(而且更容易调试,恕我直言):

-------------------------------------------------------------
-- assumptions:
-- 
-- * nullable fields never contain an nil (empty) string.
--   every nullable column will contain either a proper value
--   or NULL.
--
-- * zipcode is a 5- or 9-digit USPS zip code, without a dash.
--   Addresses lacking a zipcode will be NULL.
--------------------------------------------------------------
drop table dbo.address
go
create table dbo.address
(
  id int not null identity(1,1) primary key clustered ,
  line1   varchar(100) null ,
  line2   varchar(100) null ,
  line3   varchar(100) null ,
  city    varchar(100) null ,
  state   varchar(2)   null ,
  zipcode varchar(9)   null ,
)
go
-----------------------------------------------------------------------
-- create a work table and rotate the source table such that
-- the work table contains 1 row for each non-null row for each address
-----------------------------------------------------------------------
drop table #addr
go
create table #addr
(
  id      int          not null , -- pk.1
  line_no int          not null , -- pk.2
  value   varchar(100) not null ,

  primary key clustered ( id , line_no ) ,

)
go

insert #addr ( id , line_no , value )
select addr.id , addr.line_no , addr.value
from ( select id      = t.id ,
       line_no = row_number() over ( partition by t.id order by t.seq ) ,
       value   = t.value
       from ( select id    = id ,
                     seq   = 1  ,
                     value = line1
              from dbo.address where line1 is not null
              UNION
              select id    = id ,
                     seq   = 2  ,
                     value = line2
              from dbo.address where line2 is not null
              UNION
              select id    = id ,
                     seq   = 3  ,
                     value = line3
              from dbo.address where line3 is not null
              UNION
              select id    = id ,
                     seq   = 4  ,
                     value = ltrim(rtrim(
                                 coalesce( city    , '' )
                               + case when city is not null and state is not null then ', ' else '' end
                               + coalesce( state   , '' )
                               + case when ( city is not null or state is not null ) and zipcode is not null then ' ' else '' end
                               + coalesce( left(zipcode,5) , '' )
                               + case when len(zipcode) = 9 then '-' + right(zipcode,4) else '' end
                               ))
              from dbo.address
              where city    is not null
                 OR state   is not null
                 OR zipcode is not null
            ) t
     ) addr

---------------------------------------------------------------------
-- finally, do another table rotation to build the desired result set
---------------------------------------------------------------------
select id    = addr.id    ,
       line1 = line1.value ,
       line2 = line2.value ,
       line3 = line3.value ,
       line4 = line4.value
from      #addr addr
left join #addr line1 on line1.id = addr.id and line1.line_no = 1
left join #addr line2 on line2.id = addr.id and line2.line_no = 2
left join #addr line3 on line3.id = addr.id and line3.line_no = 3
left join #addr line4 on line4.id = addr.id and line4.line_no = 4
order by addr.id

【讨论】:

  • 这很酷。我希望将所有这些复杂性隐藏在一个函数中。我对函数不够熟悉,不知道它是否可行或推荐。 SqueezeAddress(Line1, Line2, Line3, City, State, ZIP) 然后 SqueezeAddress 将返回 Addr1, Addr2, Addr3, Addr4
【解决方案3】:

假设空值实际上是 NULL 而不是空字符串,并且需要 City、State 和 Zip:

;With AddressValues As
    (
    Select PK, Line1 As LineValue, 1 As LinePos
    From AddressTable
    Union All
    Select PK, Line2, 2
    From AddressTable
    Union All
    Select PK, Line3, 3
    From AddressTable
    Union All
    Select PK, [City] + ', ' + [State] + '  ' + [Zip], 4
    From AddressTable
    )
    , OrderedValues As
    (
    Select PK, LineValue
        , Row_Number() Over( Partition By PK Order By LinePos ) As Num
    From AddressValues
    Where LineValue Is Not Null
    )
    , ValuesAsColumns As
    (
    Select PK
        , Case When Num = 1 Then LineValue End As Line1
        , Case When Num = 2 Then LineValue End As Line2
        , Case When Num = 3 Then LineValue End As Line3
        , Case When Num = 4 Then LineValue End As Line4
    From OrderedValues
    Group By PK
    )
Update #tmpBilling
Set Line1 = VC.Line1
    , Line2 = VC.Line2
    , Line3 = VC.Line3
    , Line4 = VC.Line4
From #tmpBilling As B
    Join ValuesAsColumns As VC
        On VC.PK = B.PK

编辑

下面是函数形式的相同结果:

CREATE FUNCTION dbo.SqueezeAddress
(
    @Line1 varchar(50)
    , @Line2 varchar(50)
    , @Line3 varchar(50)
    , @City varchar(50)
    , @State varchar(50)
    , @Zip varchar(50)
    , @LineNumToReturn int

)
RETURNS varchar(50)
AS
BEGIN

Declare @Result varchar(50);

With AddressValues As
    (
    Select @Line1 As LineValue, 1 As LinePos
    Union All
    Select @Line2, 2
    Union All
    Select @Line3, 3
    Union All
    Select @City + ', ' + @State + '  ' + @Zip, 4
    )
    , OrderedValues As
    (
    Select LineValue
        , Row_Number() Over( Order By LinePos ) As Num
    From AddressValues
    Where LineValue Is Not Null
    )
Select @Result = LineValue
From OrderedValues
Where Num = @LineNumToReturn

Return @Result  

END
GO

Select dbo.SqueezeAddress(null, '123 Main St', null, 'Detroit', 'MI', '12345', 1)
, dbo.SqueezeAddress(null, '123 Main St', null, 'Detroit', 'MI', '12345', 2)
, dbo.SqueezeAddress(null, '123 Main St', null, 'Detroit', 'MI', '12345', 3)
, dbo.SqueezeAddress(null, '123 Main St', null, 'Detroit', 'MI', '12345', 4)

)

【讨论】:

  • 这很酷。我希望将所有这些复杂性隐藏在一个函数中。我对函数不够熟悉,不知道它是否可行或推荐。 SqueezeAddress(Line1, Line2, Line3, City, State, ZIP) 然后 SqueezeAddress 将返回 Addr1, Addr2, Addr3, Addr4
  • @Gerhard Weiss - 我以函数的形式添加了一个解决方案,可以达到相同的结果。简而言之,您需要将输出中所需的行号传递给函数。
猜你喜欢
  • 1970-01-01
  • 2011-04-08
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
相关资源
最近更新 更多