TSQL将地址转换为邮件地址 - SQL Server 2005

时间:2010-12-09 21:01:45

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

我想将地址(Line1,Line2,Line3,City,State,ZIP)转换为没有空行并且城市,州和ZIP连接在一起的邮件地址(Addr1,Addr2,Addr3,Addr4)在一条线上。有一个功能这样做会非常好。

即。
线路1 =
Line2 = 123某处
3号线=
市=底特律
国家= MI
Zip = 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
ADDR3 =
Addr4 =

或一个 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

地址为

的地址

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

Per Phil在下面的评论中提出的请求,这是当前使用的逻辑(删除了许多字段以便于阅读):

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, '') <> ''

3 个答案:

答案 0 :(得分:3)

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

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

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 

从这里开始,你所要做的就是将琴弦拼接在一起。这个版本假定你有空值和空字符串来分解。

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

答案 1 :(得分:1)

假设空值实际上是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)

答案 2 :(得分:1)

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

-------------------------------------------------------------
-- 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