2010-02-05 8 views
5

У меня есть столбец адреса в таблице, который мне нужно разбить на несколько столбцов в представлении SQL Server 2005. Мне нужно разбить столбец на символ строки, chr (10), и в колонке может быть от 1 до 4 линий (от 0 до 3 строк). Ниже приведены несколько примеров того, что мне нужно сделать. Каков самый простой способ сделать это?Разделение столбца адреса на отдельные столбцы в представлении SQL

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. 
+0

Любая вероятность, что данные * не * сохранены в пределах одного столбца? –

+0

Все адресные строки хранятся в одном столбце. – Jamie

ответ

3

это расколет адрес с помощью функции 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 
+0

Это отлично подходит для разбора частей, но функция parseame заполняет массив в обратном порядке. Поэтому, если у вас есть что-то вроде 123.456.789, он возвращает 1 = 789, 2 = 456 и 3 = 123. И если у вас есть 123.456, он возвращает 1 = 456 и 2 = 123. В обоих этих сценариях мне нужно 1 = 123, 2 = 456 и в первом примере 3 = 789. Не уверен, что это ясно. Я чувствую, что должен быть в состоянии сделать это, используя ваш метод coalesce и перейдя в обратном порядке или что-то в этом роде, но я не могу понять это правильно. – Jamie

+0

добавлен код, чтобы отменить заказ – SQLMenace

+0

Ок, он почти там. Единственная проблема, которую я вижу сейчас, это то, что возвращает NULL для всех четырех полей, если в конце поля источника есть строка. Другими словами, существует пустая последняя строка. Есть ли способ, чтобы мы могли очистить любые фиды линий и/или пробелы в конце, которые могли бы отбросить его? Спасибо за вашу помощь SQLMenace! – Jamie

0

Разбор текста в SQL не является забавой. Если бы мне пришлось сделать что-то подобное, я бы экспортировал столбец в текстовый файл csv и проанализировал его на языке сценариев, например Perl/PHP/Python. Таким образом, я могу воспользоваться встроенными строковыми функциями и регулярным выражением языка сценариев.

1

Это ужасно противно ... Я настоятельно рекомендую, если вы хотите обработать каждую адресную строку отдельно, что вы храните его правильно в первую очередь. Вместо того, чтобы продолжать делать то, что вы делаете, добавьте дополнительные столбцы, исправьте существующие данные один раз (вместо того, чтобы «исправлять» его каждый раз, когда вы запускаете запрос), а затем настраиваете хранимую процедуру, которая выполняет вставку/обновление так что он знает, как использовать другие столбцы.

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; 

ParseName() трюк Дениса гораздо опрятнее, конечно, но вы должны быть очень осторожны при использовании замены символа, который действительно невозможно появиться в данных, естественно. Карат (^), вероятно, хорошая ставка, но, как я уже сказал, вам нужно быть осторожным.

Существуют также программные пакеты, которые действительно хороши при очистке адреса и других демографических данных. Но очистка ввода данных является самой важной вещью здесь, и я буду продолжать подчеркивать ... если каждую адресную строку нужно рассматривать отдельно, а затем хранить ее таким образом.

+0

Я абсолютно согласен на 100%, но в данном конкретном случае у меня нет контроля над структурой данных. Это расстраивает, но это то, что есть. – Jamie

+1

Ну, пока пользователи готовы дождаться представления, чтобы выполнить это разделение каждый раз, когда вы запускаете запрос ... тогда я думаю, вы правы, это то, что это (дрянной дизайн). –

Смежные вопросы