SQL: Как обновить несколько полей, чтобы содержимое пустого поля перемещалось в логически последние столбцы - теряйте пустые строки адреса - PullRequest
3 голосов
/ 24 февраля 2011

У меня есть три столбца адресной строки, aline1, aline2, aline3 для адреса улицы.Как установлено из противоречивых данных, любой или все они могут быть пустыми.Я хочу переместить первую непустую строку в addrline1, 2-ю непустую строку в addrline2 и очистить строку 3, если нет трех непустых строк, иначе оставьте это.(«First» означает, что aline1 является первым, если он не заполнен, aline2 является первым, если aline1 пуст, а aline3 является первым, если aline1 и 2 оба являются пустыми)могут быть повторяющиеся строки.Я мог бы добавить ключ.

Не считая большого оператора case, который перечисляет возможную комбинацию пробела и не пробела и перемещает поля, как я могу обновить таблицу?(Эта та же самая проблема имеет более 3 строк, поэтому я не хочу использовать оператор case)

Я использую Microsoft SQL Server 2008

Ответы [ 5 ]

5 голосов
/ 24 февраля 2011

Еще одна альтернатива. Он использует недокументированную функцию %%physloc%% для работы без ключа. Вам было бы гораздо лучше добавить ключ к таблице.

CREATE TABLE #t
(
aline1 VARCHAR(100), 
aline2 VARCHAR(100), 
aline3  VARCHAR(100)
)

INSERT INTO #t VALUES(NULL, NULL, 'a1')
INSERT INTO #t VALUES('a2', NULL, 'b2')

;WITH cte
     AS (SELECT *,
                 MAX(CASE WHEN RN=1 THEN value END) OVER (PARTITION BY %%physloc%%) AS new_aline1,
                 MAX(CASE WHEN RN=2 THEN value END) OVER (PARTITION BY %%physloc%%) AS new_aline2,
                 MAX(CASE WHEN RN=3 THEN value END) OVER (PARTITION BY %%physloc%%) AS new_aline3
         FROM   #t
                OUTER APPLY (SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN value IS NULL THEN 1 ELSE 0 END, idx) AS
                                   RN, idx, value
                             FROM   (VALUES(1,aline1),
                                           (2,aline2),
                                           (3,aline3)) t (idx, value)) d)
UPDATE cte
SET    aline1 = new_aline1,
       aline2 = new_aline2,
       aline3 = new_aline3  


SELECT *
FROM #t

DROP TABLE #t
2 голосов
/ 25 февраля 2011

Р.А. Киберкиви, Томас и Мартин, большое спасибо - это были очень щедрые ответы каждого из вас.Все эти ответы были тем типом кормления с ложечки, который я искал.Я бы сказал, что все они основаны на устройстве, подобном ключу, и работают, разделяя адреса на строки, некоторые из которых пусты, а некоторые нет, исключая пустые.В случае строк адресов, на мой взгляд, это семантически уловка для того, чтобы проблема соответствовала тому, что хорошо работает в SQL, и это не естественный способ осмыслить проблему.Строки адреса не являются «действительно» отдельными строками в таблице, которая была просто денормализована для отчета.Но это спорный вопрос, и согласны ли вы или нет, я (начинающий ранга) думаю, что каждый из ваших альтернатив идиоматическое решение стоит уточняя и изучение.

1002 * Я также получает много подобных случаи, когда действительно есть нормализация бытьсделано - например, collatDesc1, collatCode1, collatLastAppraisal1, ... collatLastAppraisal5, с более сложными критериями относительно того, что делать в исключении и как заказать, чем с адресами, и я думаю, что методы из ваших ответов будут полезны.%% это весело - так как я могу создать ключ в этом случае, я не буду его использовать (как советует Мартин).В вещах Мартина были и другие вещи, с которыми я тоже не был знаком, и я все еще бросаю их.

FWIW, вот триггер, который я опробовал, я не знаю, что я действительно буду использовать его для решения проблемы.Я думаю, что это квалифицирует «пузырчатую сортировку», где своп выражается особым образом.

create trigger fixit on lines 
instead of insert as
declare @maybeblank1 as varchar(max)
declare @maybeblank2 as varchar(max)
declare @maybeblank3 as varchar(max)


set @maybeBlank1 = (select line1 from inserted)
set @maybeBlank2 = (select line2 from inserted)
set @maybeBlank3 = (select line3 from inserted)

declare @counter int
set @counter = 0 

while @counter < 3
begin
    set @counter = @counter + 1
    if @maybeBlank2 = '' 
        begin
            set @maybeBlank2  =@maybeblank3
            set @maybeBlank3 = ''
        end
    if @maybeBlank1 = ''
        begin
            set @maybeBlank1 = @maybeBlank2
            set @maybeBlank2 = ''
        end
end
select * into #kludge from inserted
update #kludge
    set line1 = @maybeBlank1,
    line2 = @maybeBlank2,
    line3 = @maybeBlank3
insert into lines 
    select * from #kludge
2 голосов
/ 24 февраля 2011

Обновление - изменен оператор на оператор обновления.Решение с выписанным оператором Case *

При использовании этого решения вам потребуется уникальный ключ в промежуточной таблице.

With Inputs As
    (
    Select PK, 1 As LineNum, aline1 As Value
    From StagingTable
    Where aline1 Is Not Null
    Union All
    Select PK, 2, aline2
    From StagingTable
    Where aline2 Is Not Null
    Union All
    Select PK, 3, aline3
    From StagingTable
    Where aline3 Is Not Null
    )
    , ResequencedInputs As
    (
    Select PK, Value
        , Row_Number() Over( Order By LineNum ) As LineNum
    From Inputs
    )
    , NewValues As
    (
    Select S.PK
        , Min( Case When R.LineNum = 1 Then R.addrline1 End ) As addrline1
        , Min( Case When R.LineNum = 2 Then R.addrline1 End ) As addrline2
        , Min( Case When R.LineNum = 3 Then R.addrline1 End ) As addrline3
    From StagingTable As S
        Left Join ResequencedInputs As R
            On R.PK = S.PK
    Group By S.PK
    )
Update OtherTable
Set addrline1 = T2.addrline1
    , addrline2 = T2.addrline2
    , addrline3 = T2.addrline3
From OtherTable As T
    Left Join NewValues As T2
        On T2.PK = T.PK
2 голосов
/ 24 февраля 2011

Вот альтернативный

Пример таблицы для обсуждения, не беспокойтесь о бессмысленных данных, они просто должны быть нулевыми или нет

create table taddress (id int,a varchar(10),b varchar(10),c varchar(10));
insert taddress
select 1,1,2,3 union all
select 2,1, null, 3 union all
select 3,null, 1, 2 union all
select 4,null,null,2 union all
select 5,1, null, null union all
select 6,null, 4, null

Запрос, который действительно просто нормализуетданные

;with tmp as (
    select *, rn=ROW_NUMBER() over (partition by t.id order by sort)
    from taddress t
    outer apply
    (
        select 1, t.a where t.a is not null union all
        select 2, t.b where t.b is not null union all
        select 3, t.c where t.c is not null
            --- EXPAND HERE
    ) u(sort, line)
)
select t0.id, t1.line, t2.line, t3.line
from taddress t0
left join tmp t1 on t1.id = t0.id and t1.rn=1
left join tmp t2 on t2.id = t0.id and t2.rn=2
left join tmp t3 on t3.id = t0.id and t3.rn=3
--- AND HERE
order by t0.id

РЕДАКТИРОВАТЬ - для обновления обратно в таблицу

;with tmp as (
    select *, rn=ROW_NUMBER() over (partition by t.id order by sort)
    from taddress t
    outer apply
    (
        select 1, t.a where t.a is not null union all
        select 2, t.b where t.b is not null union all
        select 3, t.c where t.c is not null
            --- EXPAND HERE
    ) u(sort, line)
)
UPDATE taddress
set a = t1.line,
    b = t2.line,
    c = t3.line
from taddress t0
left join tmp t1 on t1.id = t0.id and t1.rn=1
left join tmp t2 on t2.id = t0.id and t2.rn=2
left join tmp t3 on t3.id = t0.id and t3.rn=3
1 голос
/ 24 февраля 2011

Вы можете сделать триггер вставки и обновления, который проверяет, являются ли поля пустыми, а затем переместить их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...