Postgresql - обновить недействительные ячейки на основе максимального числа строк - PullRequest
0 голосов
/ 14 февраля 2012

POSTGRES- Я хочу обновить столбец Employees.zipcode_mod в таблице Employees для «недопустимых почтовых индексов» (Employees.zipcode), которые являются недействительными, если они не существуют в Ref_Zips.zip5

Правило обновления состоит в том, чтобы найти все недействительные почтовые индексы длиной 3 или более символов и сопоставить их с первыми тремя цифрами столбца Tmp_Agg_Zips.zip и обновить Employees.zipcode_mod с помощью Tmp_Agg_Zips.zip, который имеет наибольшее число Tmp_Agg_Zips.emp_cnt. Если есть связь между несколькими значениями Tmp_Agg_Zips.zip, тогда получите «самое высокое» значение zip.

Обновление

Если недопустимый zipcode превышает 3 знака, но его первые три цифры не совпадают ни с одной из первых трех цифр Tmp_Agg_Zips.zip ИЛИ недопустим zipcode меньше 3 символов или пусто, просто обновите Employees.zipcode_mod с Tmp_Agg_Zips.zip, которое имеет максимальное значение Tmp_Agg_Zips.emp_cnt, независимо от первых трех цифр. Например, 88888 и null обновляются до 10012 в приведенном ниже примере.

Это для Postgres 8,4 .

Сотрудники

Gender | zipcode | zipcode_mod
   M   |  99574  |
   F   |  99574  |
   F   |  10012  |
   F   |  10012  |
   F   |  10012  |
   F   |  19001  |
   M   |    100  | 10012
   M   |    190  | 19001
   M   |     19  | 10012
   F   |   null  | 10012
   F   |  88888  | 10012
   F   |   8888  | 10012

Tmp_Agg_Zips

  zip | emp_cnt
99574 |  2
10012 |  3
19001 |  1

Ref_Zips

zip5
99574
10012
19001

1 Ответ

1 голос
/ 14 февраля 2012

За обновленный вопрос

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

UPDATE employees e
SET    zipcode_mod =
   CASE WHEN length(e.zipcode) > 2 THEN
      COALESCE((
         SELECT t.zip
         FROM   tmp_agg_zips t
         WHERE  substr(t.zipcode, 1, 3) = substr(e.zipcode, 1, 3)
         ORDER  BY t.emp_cnt DESC, t.zip  -- lowest zip for mult. emp_cnt
         LIMIT  1
         ), t0.zip)
   ELSE
      t0.zip
   END
FROM  (
   SELECT zip
   FROM   tmp_agg_zips
   ORDER  BY emp_cnt DESC, t.zip
   LIMIT  1
   ) t0
WHERE  NOT EXISTS (
   SELECT *
   FROM   ref_zips r
   WHERE  r.zip5 = e.zipcode
   )

Для оригинального вопроса

Этот запрос работает с более ранними версиями PostgreSQL:

UPDATE employees e
SET    zipcode_mod =
    CASE WHEN length(e.zipcode) > 2 THEN (
        SELECT t.zip
        FROM   tmp_agg_zips t
        WHERE  substr(t.zipcode, 1, 3) = substr(e.zipcode, 1, 3)
        ORDER  BY t.emp_cnt DESC, t.zip -- lowest zip for mult. emp_cnt
        LIMIT  1
        )
    ELSE (
        SELECT zip
        FROM   tmp_agg_zips
        ORDER  BY emp_cnt DESC, t.zip
        LIMIT  1
        )
    END
WHERE  NOT EXISTS (
        SELECT *
        FROM   ref_zips r
        WHERE  r.zip5 = e.zipcode
        )

В PostgreSQL 9.1 , CTE должен работать лучше:

WITH x AS (
    SELECT zip
    FROM   tmp_agg_zips
    ORDER  BY emp_cnt DESC, t.zip
    LIMIT  1
    )
UPDATE employees e
SET    zipcode_mod =
    CASE WHEN length(e.zipcode) > 2 THEN (
        SELECT t.zip
        FROM   tmp_agg_zips t
        WHERE  left(t.zipcode, 3) = left(e.zipcode, 3)
        ORDER  BY t.emp_cnt DESC, t.zip  -- pick lowest zip
        LIMIT  1
        )
    ELSE
        x.zip
    END
FROM   x
WHERE  NOT EXISTS (
        SELECT *
        FROM   ref_zips r
        WHERE  r.zip5 = e.zipcode
        )

Если в tmp_agg_zips есть несколько строк с одинаковыми (самыми высокими) emp_cnt, я выбираю «самые низкие» zip. Вы не указали, как разорвать эти связи.

Кстати, разные имена столбцов для почтовых индексов мне не помогают. Таблица с именами столбцов делает работу лучше.

...