SQL Server:如何拆分一列中的字符串并将值分配给另一列(没有额外的行!)

Har*_*vey 3 sql sql-server

在一张表中,我有一个完整的地址,我必须将其分成城市和邮政编码以存储在其他列中。

这是示例地址:

address= 'Marco Polo street 8a, 44000 Vienna'
Run Code Online (Sandbox Code Playgroud)

有些行可能包含多个地址,但我必须只保留最后一个逗号 ( 44000 Vienna) 之后的最后部分。

所以最终的结果应该是:

 post_office = 44000 
 city = Vienna
Run Code Online (Sandbox Code Playgroud)

到目前为止已尝试: /sf/answers/940167091/

带有嵌套子字符串,如下所示:

city = SUBSTRING(SUBSTRING(address, CHARINDEX(' ', address, 0) + 1, LEN(address)), CHARINDEX(',', address, 0) + 1, LEN(address))
Run Code Online (Sandbox Code Playgroud)

post_office = SUBSTRING(SUBSTRING(address, CHARINDEX(',', address, 0) + 1, LEN(address)), 0, CHARINDEX(' ', address, 0))
Run Code Online (Sandbox Code Playgroud)

但这仅部分有效,因为城市也可以有多个单词,例如:

city = '44300 Vienna Old Town'
Run Code Online (Sandbox Code Playgroud)

我的数据的规则是:找到最后一个逗号,获取逗号后面的所有数字并将其定义为post_office然后,在第一个空格之后post_office直到字符串的其余部分,应将其定义为城市。

我正在运行 Microsoft SQL Server 2017 (v14.0.3391.2 - X64)

bud*_*mat 5

好吧,我想您的问题下面的评论已经详细说明了为什么数据存储方式是一个坏主意,以及如果您对地址的假设不是 100% 准确,您的尝试可能会以何种方式失败。

话虽这么说,您可能正在尝试解决这个问题,如果您确定您定义的规则始终适合,您就可以做您想做的事。

为此,请使用该REVERSE()函数两次来查找最后一次出现的子字符串。这样,您可以从最后一个逗号开始分隔所有内容。使用TRIM()该函数删除可能出现的周围空白,例如,如果逗号后面直接有空格。

如果您确定邮政编码中只有数字字符和空格,并且邮政编码紧随其后,您可以使用PATINDEXLEFT()RIGHT()查找第一个非数字字符,类似于此 SO post

完整的解决方案:对于输入数据

地址
马可波罗街 8a, 44000 维也纳
马可波罗街 8a, 44000 维也纳老城区
马可波罗街 8a,44000 维也纳
Marco Polo street 8a, Marco Polo street 8b, 44 000 维也纳老城区
马可波罗街 8a, 44 00 0 维也纳

该声明

with tmp as (
select TRIM(REVERSE(SUBSTRING(REVERSE(address),0,CHARINDEX(',',REVERSE(address))))) lastpart
  from addresstable
  ) 
  select LEFT(lastpart, PATINDEX('%[^0-9 ]%', lastpart) -1) as postcode,
         RIGHT(lastpart, len(lastpart) - PATINDEX('%[^0-9 ]%', lastpart) + 1) as city
  from tmp
Run Code Online (Sandbox Code Playgroud)

产生结果

邮政编码 城市
44000 维也纳
44000 维也纳老城
44000 维也纳
44 000 维也纳老城
44 00 0 维也纳

笔记:

  • 如果您不想允许空格,请将它们从PATINDEX(), ie的表达式中删除'%[^0-9]%'
  • 如果您希望您的postcode类型为int,请TRY_CONVERT()REPLACE()和一起使用NULLIF()。请参阅下面的这个 SO 答案和 dbfiddle 。请注意,这会删除可能属于邮政编码的可能的前导零。

或者,如果您确定最后一个逗号之后直到下一个空格之前的任何字符串都是the postcode,并且您希望在邮政编码中允许字母字符,那么您之前的尝试已经做到了。但是,如果您的邮政编码有空格,这将会中断。

with tmp as (
select TRIM(REVERSE(SUBSTRING(REVERSE(address),0,CHARINDEX(',',REVERSE(address))))) lastpart
  from addresstable
  ) 
  select SUBSTRING(lastpart,0,CHARINDEX(' ',lastpart,0)+1) as postcode,
         SUBSTRING(lastpart,CHARINDEX(' ',lastpart,0)+1,LEN(lastpart)) as city
  from tmp
Run Code Online (Sandbox Code Playgroud)

请参阅此 db<>fiddle以了解两者的比较,包括一些不适用于两者之一的地址示例。