根据SQL Server

时间:2017-10-09 16:00:24

标签: sql-server sql-server-2008 tsql split

需要SQL Server查询。以下是示例

1)19003 IH-10 West,San Antonio,78257,TX,United States

在第一个示例中,字符串中有四个逗号。所以输出应该是

19003 IH-10 West

2)Chevron Pipe Line Company,4800 Fournace Place,Bellaire,77401-2324,TX,United States

在第二个示例中,字符串中有五个逗号。所以输出应该是

Chevron Pipe Line Company, 4800 Fournace Place

如果有四个逗号,则输出应该是主字符串的子字符串,直到第一个逗号,如果有五个逗号,则输出应该是主字符串的子字符串,直到第二个逗号。

在输入中,只有4或5个逗号。

我可以通过使用UDF来实现此要求。但我需要直接查询。

2 个答案:

答案 0 :(得分:2)

不确定这会如何表现。我强烈建议一种更好的方法来分割地址并存储为单独的字段,有许多地址解析解决方案可用。

如果这不是一个选项,则以下方法可行,但可能需要根据性能进行更改。

Drop Table #Temp
Create Table #Temp (Field Varchar(8000))
Insert #Temp Values ('19003 IH-10 West, San Antonio, 78257, TX, United States')
Insert #Temp Values ('Chevron Pipe Line Company, 4800 Fournace Place, Bellaire, 77401-2324, TX, United States')

;With cteFindCommas As
(
Select  CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field)+1)+1)+1)+1) FifthCommaPos,
        CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field)+1)+1)+1) FourthCommaPos,
        CharIndex(',', Field) FirstCommaPos,
        CharIndex(',', Field, CharIndex(',', Field)+1) SecondCommaPos,
        *
    From #Temp
)
Select  Case When FifthCommaPos > 0 Then Substring(Field, 0, SecondCommaPos)
             Else Substring(Field, 0, FirstCommaPos) End String,            
        * 
    From cteFindCommas

答案 1 :(得分:1)

这是我将如何做到的(请注意我的代码中的注释):

-- sample data
declare @sometable table (someid int identity, someAddress varchar(200));
insert @sometable (someAddress) 
values ('19003 IH-10 West, San Antonio, 78257, TX, United States'),
       ('Chevron Pipe Line Company, 4800 Fournace Place, Bellaire, 77401-2324, TX, US');

-- solution
select 
  someid,
  someAddress,
  newAddress = case commaCount when 4 then C4 when 5 then C5 end -- conditions for 4 or 5 commas only
from
(
  select 
    someid,
    someAddress,
    commaCount = len(v.a) - len(replace(v.a,',','')), -- calculate the number of commas
    C4 = substring(v.a, 1, charindex(',', v.a)-1), -- grab everything up to the 1st comma
    C5 = substring(v.a, 1, charindex(',', v.a, charindex(',', v.a)+1)-1) -- everything up to 2nd comma
  from @sometable t
    cross apply (values (t.someAddress)) v(a)   -- how I avoid repeated references to t.SomeAddress
) formatStrings;

<强>结果

someid  someAddress                                              newAddress
------- -------------------------------------------------------  ----------------------------------------------
1       19003 IH-10 West, San Antonio, 78257, TX, United States  19003 IH-10 West
2       Chevron Pipe Line Company, 4800 Fournace Place...        Chevron Pipe Line Company, 4800 Fournace Place

更新 - 添加效果测试

下面是我放在一起的测试工具;请注意我的评论。

示例数据

-- #1: Create Sample Data
------------------------------------------------------------------------------------------
declare @rows int = 100000;
if object_id('tempdb..#base') is not null drop table #base;
if object_id('tempdb..#address') is not null drop table #address;

-- grabbed 50 random addresses from here: https://www.randomlists.com/random-addresses
-- manually added the first comma (between street address and city)
select 
  someId      = identity(int,1,1),
  someAddress = stuff(addr,patindex('%'+replicate('[0-9]',5)+'%',addr),0,',')
into #base from (values
('886 Hartford Ave., Gwynn Oak, MD 21207'),
('322 Wakehurst St., Deerfield, IL 60015'),
('62 South Oak Valley St., Lorain, OH 44052'),
('72 53rd St., New Bern, NC 28560'),
('569 Swanson Ave., Snellville, GA 30039'),
('15 Walnut St., New Bern, NC 28560'),
('94 Kingston St., North Royalton, OH 44133'),
('77 Rock Creek St., Ocean Springs, MS 39564'),
('688 S. Bellevue St., Mableton, GA 30126'),
('61 Queen Rd., Potomac, MD 20854'),
('72 Jockey Hollow Drive, Elgin, IL 60120'),
('777 School St., Clarksville, TN 37040'),
('50 North 1st Street, Mount Prospect, IL 60056'),
('8004 Valley Drive, Long Beach, NY 11561'),
('8569 Franklin Court, Lakeland, FL 33801'),
('837 Buckingham St., Newnan, GA 30263'),
('46 Birch Hill St., Helena, MT 59601'),
('617 E. Brookside Drive, Jersey City, NJ 07302'),
('8133 Valley View St., Clearwater, FL 33756'),
('42 South Ave., Greensburg, PA 15601'),
('8782 Oak Meadow St., Helotes, TX 78023'),
('35 Valley Farms Ave., Racine, WI 53402'),
('7613 Cobblestone Road, Orlando, FL 32806'),
('27 Broad Lane, Kaukauna, WI 54130'),
('9213 Corona Dr., Rockville, MD 20850'),
('7390 W. Bay Court, Mason, OH 45040'),
('561 W. St Louis Ave., Silver Spring, MD 20901'),
('7447 Evergreen Ave., Rocky Mount, NC 27804'),
('24 NW. Pilgrim Road, Sun Prairie, WI 53590'),
('846 E. Hall St., Lake Villa, IL 60046'),
('919 Green Hill Street, New Orleans, LA 70115'),
('532 Newbridge Lane, Hanover, PA 17331'),
('3 E. Rose Rd., Waukegan, IL 60085'),
('15 South Euclid Rd., Springfield Gardens, NY 11413'),
('453 Mulberry Ave., Parlin, NJ 08859'),
('8128 New Saddle Court, Fullerton, CA 92831'),
('9143 Lafayette Ave., Jackson Heights, NY 11372'),
('481 Edgewater St., Dacula, GA 30019'),
('8243 Hilltop St., Camp Hill, PA 17011'),
('70 Lookout St., Marlborough, MA 01752'),
('9370 South Shirley Drive, King Of Prussia, PA 19406'),
('8071 Plymouth Road, Huntersville, NC 28078'),
('593 Charles St., Buckeye, AZ 85326'),
('9092 Atlantic Ave., Yuma, AZ 85365'),
('81 Longbranch Road, Ontario, CA 91762'),
('868 Garfield St., New Lenox, IL 60451'),
('8333 Kirkland Rd., Plainview, NY 11803'),
('9714 Prospect Ave., Monroe Township, NJ 08831'),
('7 N. Atlantic Ave., Reidsville, NC 27320'),
('9283 Cherry Lane, Waukegan, IL 60085')) a(addr);

-- index to support large sample data requests:
create unique clustered index uq_cl_base on #base(someid);

-- Create randomized addresses: up to 6,250,000 dummy rows (50^4)
with r(x) as (select top(@rows/50) 1 from #base a, #base b, #base c, #base d),
base(Field) as
(
  select Field  =
    max(
      case itemNumber when 1 then substring(item,charindex(' ',item)+1, len(item)+1) end+
        case abs(checksum(newid())%10)
        when 0 then ', Unit '+ cast(abs(checksum(newid())%100)+1 as varchar(3))
        when 1 then ', Suite '+ cast(abs(checksum(newid())%100)+1 as varchar(3))
        when 2 then ', Penthouse' else '' end)+','+
    max(case ItemNumber when 2 then item end)+','+
    max(case ItemNumber when 3 then left(item,3)+', ' end)+
    max(case ItemNumber when 4 then item end)+', United States'
  from #base t
  cross apply dbo.DelimitedSplit8K(t.someAddress,',')
  group by t.someId
)
select addressId = identity(int,1,1),
       field     =
         left(cast(abs(checksum(newid())%10000)+1 as varchar(5)), 
           case checksum(newid())%3 when 4 then 4 when 1 then 1 else 3 end)+' '+b.Field
into #address
from base b
cross join r
order by newid();
go

效果测试

set nocount on;
print 'solution 1'+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @field varchar(100);
  ;With cteFindCommas As
  (
  Select  CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field)+1)+1)+1)+1) FifthCommaPos,
          CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field, CharIndex(',', Field)+1)+1)+1) FourthCommaPos,
          CharIndex(',', Field) FirstCommaPos,
          CharIndex(',', Field, CharIndex(',', Field)+1) SecondCommaPos, *
  From #Address
  )
  select @field = case when FifthCommaPos > 0 Then Substring(Field, 0, SecondCommaPos)
                  else Substring(Field, 0, FirstCommaPos) end
  From cteFindCommas;
print datediff(ms,@st,getdate());
go 5

print 'solution 2'+char(10)+replicate('-',50);
go
declare @st datetime = getdate(), @field varchar(100);
  select @field = case commaCount when 4 then C4 when 5 then C5 end -- conditions for 4 or 5 commas only
  from
  (
    select
      addressId,
      field,
      commaCount = len(v.a) - len(replace(v.a,',','')), -- calculate the number of commas
      C4 = substring(v.a, 1, charindex(',', v.a)-1), -- grab everything up to the 1st comma
      C5 = substring(v.a, 1, charindex(',', v.a, charindex(',', v.a)+1)-1) -- everything up to 2nd comma
    from #address t cross apply (values (t.field)) v(a)
  ) formatStrings;
print datediff(ms,@st,getdate());
go 5

结果(100,000行测试)

solution 1
--------------------------------------------------
Beginning execution loop
133
133
130
126
126
Batch execution completed 5 times.

solution 2
--------------------------------------------------
Beginning execution loop
156
160
156
157
153
Batch execution completed 5 times.

看起来Joe C&#39的解决方案(解决方案#1)更快。