Сжатие данных в SQL Server - PullRequest
       1

Сжатие данных в SQL Server

1 голос
/ 06 апреля 2011

У меня есть таблица в следующем формате:

Name    Address1    Address2    Address3
Joe     NULL        1 A Road    London
Bob     2 A Lane    NULL        London

Я хотел бы запустить обновление, чтобы переместить все значения влево, где есть нулевые значения, чтобы я получил:

Name    Address1    Address2    Address3
Joe     1 A Road    London      NULL
Bob     2 A Lane    London      NULL

Пожалуйста, помогите!

Спасибо, Джош

Ответы [ 2 ]

3 голосов
/ 06 апреля 2011
BEGIN TRANSACTION
update person set Address1 = Address2, Address2 = null 
  where Address1 is null and Address2 is not null;
update person set Address2 = Address3, Address3 = null
  where Address2 is null and Address3 is not null;
update person set Address1 = Address2, Address2 = null
  where Address1 is null and Address2 is not null;
select top 100 * from person
ROLLBACK TRANSACTION

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

РЕДАКТИРОВАТЬ: с дополнительной информацией (6 полей адреса): вы можете сделать как вышетолько повторить 5 раз, чтобы переместиться, так что в худшем случае вы, где еще сделали

Declare StoredProcedure OneRound
BEGIN
  update person set Address1 = Address2, Address2 = null 
    where Address1 is null and Address2 is not null;
  update person set Address2 = Address3, Address3 = null
    where Address2 is null and Address3 is not null;
  update person set Address3 = Address4, Address4 = null 
    where Address3 is null and Address4 is not null;
  update person set Address4 = Address5, Address5 = null
    where Address4 is null and Address5 is not null;
  update person set Address5 = Address6, Address6 = null 
    where Address5 is null and Address6 is not null;
END

Declare StoredProc FixAllAddresses
BEGIN
  call OneRound
  call OneRound
  call OneRound
  call OneRound
  call OneRound
END

Вы также можете использовать cusor (предупреждающий псидо-код). Я не посмотрел синтаксис для курсоров T-SQL, и это былоНекоторое время, чтобы я неправильно понял детали, проверьте синтаксис в онлайн-справке.

Declare cursor @personCursor for select ID,Address1,Address2,... from person;
OPEN @personCursor
FETCH @personCursor into (@personID, @addr1, @addr2, @addr3...)
while(@@FETCH_STATUS)
BEGIN
  IF @addr1 is null
  BEGIN
    IF @addr2 is not null
    BEGIN
      @addr1 = @addr2
      @addr2 = null
    END
    ELSE IF @addr3 is not null
      @addr1 = @addr3
      @addr3 = null
    BEGIN
    -- Boaring, ugly code goes here for addr4,addr5,addr6
    END
  END

  IF @addr2 is null
    IF @addr3 is not null
    BEGIN
      @addr2 = @addr3
      @addr3 = null
    END
    ELSE IF @addr4 is not null
      @addr2 = @addr4
      @addr4 = null
    BEGIN
    -- Boaring, ugly code goes here for addr5, addr6
    END
  BEGIN

  -- repeat for addr3, addr4,

  if @addr5 is null
  BEGIN
    IF addr6 is not null
    BEGIN
      @addr5 = @addr6
      @addr6 = null
    END
  END

  END
  update person set address1 = @addr1, address2 = @addr2, ... 
    where PersonId = @personId
  FETCH @personCursor into (@personID, @addr1, @addr2, @addr3...)  
END

Начало хранимого процесса, вызываемое 5 раз, приводит к меньшему количеству кода и может быть менее подвержено ошибкам, курсор только перебирает ваших сотрудников один раз, но не фильтрует.Я подозреваю, что хранимое решение процесса ниже будет быстрее, но это будет зависеть от ваших данных.

2 голосов
/ 06 апреля 2011

Решение Дэвида является наиболее эффективным. Тот, который может быть более легко расширяемым для большего числа столбцов.

;WITH cte
     AS (SELECT *,
                 MAX(CASE WHEN RN=1 THEN value END) OVER (PARTITION BY ContactId) AS new_Address1,
                 MAX(CASE WHEN RN=2 THEN value END) OVER (PARTITION BY ContactId) AS new_Address2,
                 MAX(CASE WHEN RN=3 THEN value END) OVER (PARTITION BY ContactId) AS new_Address3
         FROM   #Addresses
                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,Address1),
                                           (2,Address2),
                                           (3,Address3)) t (idx, value)) d)
UPDATE cte
SET    Address1 = new_Address1,
       Address2 = new_Address2,
       Address3 = new_Address3  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...