【问题标题】:Split Address column into separate columns in SQL view在 SQL 视图中将地址列拆分为单独的列
【发布时间】:2010-02-05 16:44:24
【问题描述】:

我在表中有一个地址列,我需要在 SQL Server 2005 的视图中拆分为多个列。我需要在换行符 chr(10) 上拆分列,并且可能从 1到列中的 4 行(0 到 3 个换行符)。下面是我需要做的几个例子。实现这一目标的最简单方法是什么?

Examples:

Address                 Address1      Address2       Address3            Address4
------------        =   -----------   -----------    -----------------   ---------
My Company              My Company     123 Main St.  Somewhere,NY 12345  
123 Main St.         
Somewhere,NY 12345

Address                 Address1       Address2      Address3      Address4
------------        =   ------------   ----------    -----------   ---------
123 Main St.            123 Main St.

【问题讨论】:

  • 数据是否存储在单个列中?
  • 所有地址行都存储在一个列中。

标签: sql sql-server database sql-server-2005


【解决方案1】:

这将使用 parsename 函数拆分地址并将其与 COALESCE 结合以在正确的列中获取正确的信息

如果您的行数超过 4 行,此方法将不起作用

编辑:添加了颠倒顺序的代码

    create table #test (address varchar(1000))

    --test data
    insert #test values('My Company
    123 Main St.         
    Somewhere,NY 12345')

    insert #test values('My Company2
    666 Main St.  
    Bla Bla       
    Somewhere,NY 12345')

    insert #test values('My Company2')

    --split happens here
                            select
replace(parsename(address,ParseLen +1),'^','') as Address1,
replace(parsename(address,ParseLen ),'^','') as Address2,
replace(parsename(address,ParseLen -1),'^','') as Address3,
replace(parsename(address,ParseLen -2),'^','') as Address4
from(
select case  ascii(right(address,1)) when 10 then
replace(replace(left(address,(len(address)-1)),'.','^'),char(10),'.')  
else 
replace(replace(address,'.','^'),char(10),'.') end as address,
case  ascii(right(address,1)) when 10 then
len(replace(replace(address,'.','^'),char(10),'.')) -
len(replace(replace(address,'.','^'),char(10),'')) -1
else
len(replace(replace(address,'.','^'),char(10),'.')) -
len(replace(replace(address,'.','^'),char(10),'')) end as ParseLen
 from #test) x

【讨论】:

  • 这很好地解析了片段,但是 parsename 函数以相反的顺序填充它的数组。所以如果你有类似 123.456.789 的东西,它会返回 1=789、2=456 和 3=123。如果你有 123.456 它返回 1=456 和 2=123。在这两种情况下,我需要 1=123、2=456,在第一个示例中需要 3=789。不确定这是否清楚。我觉得我应该能够使用您的合并方法并以相反的顺序执行此操作,但我似乎无法做到这一点。
  • 好的,差不多了。我现在看到的唯一问题是,如果源字段末尾有换行符,则所有四个字段都返回 NULL。换句话说,最后一行是空白的。有没有办法我们可以在最后清理任何可能会丢弃它的换行符和/或空格?感谢您对 SQLMenace 的所有帮助!
  • 杰米,你试过我发布的解决方案了吗?它应该将第 4 行提要之后的任何内容视为第 4 行上的更多数据(但这表明您的解决方案中还有另一个数据完整性问题)。
  • Aaron,我确实尝试了您的解决方案,输出正是我所需要的。唯一的问题是速度。我在原始帖子中没有提到运行时间,但它需要尽快执行。上面的解决方案的执行速度是您发布的解决方案的两倍,但您的输出似乎是正确的。您是否看到任何进一步优化您的解决方案的方法?非常感谢您的帮助。
  • 已更新以考虑结束换行
【解决方案2】:

这非常讨厌...我强烈建议,如果您想分别处理每个地址行,请首先正确存储它。而不是继续做你正在做的事情,添加额外的列,修复现有数据一次(而不是每次运行查询时“修复”它),然后调整存储过程执行插入/更新,以便知道使用其他列。

DECLARE @Address TABLE(id INT IDENTITY(1,1), ad VARCHAR(MAX));

INSERT @Address(ad) SELECT 'line 1
line 2
line 3
line 4'
UNION ALL SELECT 'row 1
row 2
row 3'
UNION ALL SELECT 'address 1
address 2'
UNION ALL SELECT 'only 1 entry here'
UNION ALL SELECT 'let us try 5 lines
line 2
line 3
line 4 
line 5';

SELECT
    id,
    Line1 = REPLACE(REPLACE(COALESCE(Line1, ''), CHAR(10), ''), CHAR(13), ''),
    Line2 = REPLACE(REPLACE(COALESCE(Line2, ''), CHAR(10), ''), CHAR(13), ''),
    Line3 = REPLACE(REPLACE(COALESCE(SUBSTRING(Rest, 1, COALESCE(NULLIF(CHARINDEX(CHAR(10), Rest), 0), LEN(Rest))), ''), CHAR(10), ''), CHAR(13), ''),
    Line4 = REPLACE(REPLACE(COALESCE(SUBSTRING(Rest, NULLIF(CHARINDEX(CHAR(10), Rest) + 1, 1), LEN(Rest)), ''), CHAR(10), ''), CHAR(13), '')
FROM

(
    SELECT 
        id,
        ad,
        Line1,
        Line2 = SUBSTRING(Rest, 1, COALESCE(NULLIF(CHARINDEX(CHAR(10), Rest), 0), LEN(Rest))),
        Rest = SUBSTRING(Rest, NULLIF(CHARINDEX(CHAR(10), Rest) + 1, 1), LEN(Rest))
    FROM
    (
        SELECT
            id,
            ad,
            Line1 = SUBSTRING(ad, 1, COALESCE(NULLIF(CHARINDEX(CHAR(10), ad), 0), LEN(ad))),
            Rest = SUBSTRING(ad, NULLIF(CHARINDEX(CHAR(10), ad) + 1, 1), LEN(ad))
        FROM
            @address
    ) AS x
) AS y
ORDER BY id;

Denis 的 PARSENAME() 技巧当然要整洁得多,但是您必须非常小心地使用真正不可能自然出现在数据中的替换字符。克拉 (^) 可能是一个不错的选择,但就像我说的,你需要小心。

还有一些非常擅长清理地址和其他人口统计数据的软件包。但是清理数据条目是这里最重要的事情,我将继续强调......如果每个地址行都需要单独处理,那么就以这种方式存储它们。

【讨论】:

  • 我 100% 完全同意,但在这种特殊情况下,我无法控制数据的结构。这令人沮丧,但事实就是如此。
  • 好吧,只要用户愿意等待视图在您每次运行查询时执行此拆分...那么我想您是对的,就是这样(糟糕的设计)。
【解决方案3】:

在 SQL 中解析文本并不好玩。如果我必须做这样的事情,我会将列导出到 csv 文本文件并用脚本语言(如 Perl/PHP/Python)对其进行解析。这样我就可以利用内置的字符串函数和脚本语言的正则表达式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    • 2021-04-27
    • 2017-11-02
    相关资源
    最近更新 更多