оновлення рядків таблиці в постгресах за допомогою підзапиту


301

Використовуючи postgres 8.4, моєю метою є оновлення існуючої таблиці:

CREATE TABLE public.dummy
(
  address_id SERIAL,
  addr1 character(40),
  addr2 character(40),
  city character(25),
  state character(2),
  zip character(5),
  customer boolean,
  supplier boolean,
  partner boolean

)
WITH (
  OIDS=FALSE
);

Спочатку я перевірив свій запит за допомогою оператора insert:

insert into address customer,supplier,partner
SELECT  
    case when cust.addr1 is not null then TRUE else FALSE end customer, 
    case when suppl.addr1 is not null then TRUE else FALSE end supplier,
    case when partn.addr1 is not null then TRUE else FALSE end partner
from (
    SELECT *
        from address) pa
    left outer join cust_original cust
        on (pa.addr1=cust.addr1 and pa.addr2=cust.addr2 and pa.city=cust.city 
            and pa.state=cust.state and substring(cust.zip,1,5) = pa.zip  )
    left outer join supp_original suppl 
        on (pa.addr1=suppl.addr1 and pa.addr2=suppl.addr2 and pa.city=suppl.city 
                and pa.state=suppl.state and pa.zip = substring(suppl.zip,1,5))
    left outer join partner_original partn
        on (pa.addr1=partn.addr1 and pa.addr2=partn.addr2 and pa.city=partn.city
                  and pa.state=partn.state and pa.zip = substring(partn.zip,1,5) )
where pa.address_id = address_id

будучи новачком, я не в змозі перетворити на оновлення оператора, тобто оновити існуючі рядки зі значеннями, поверненими оператором select. Будь-яка допомога високо цінується.


у вас є якийсь ідентифікатор в адресній таблиці, за допомогою якого можна визначити, що рядок існує?
Андрій Адамович

Так, я роблю, але його система генерується.
stackover

Відповіді:


681

Postgres дозволяє:

UPDATE dummy
SET customer=subquery.customer,
    address=subquery.address,
    partn=subquery.partn
FROM (SELECT address_id, customer, address, partn
      FROM  /* big hairy SQL */ ...) AS subquery
WHERE dummy.address_id=subquery.address_id;

Цей синтаксис не є стандартним SQL, але він набагато зручніший для цього типу запитів, ніж стандартний SQL. Я вважаю, що Oracle (принаймні) приймає щось подібне.


здається, що я намагаюся дещо іншу річ, наприклад. якщо є 3 стовпчики bool c1, c2, c3, усі вони встановлені на значення false раніше. але на основі підзапиту встановлено значення true. update set c1 = TRUE where id in (subquery1), set c2 = TRUE where id in (subquery2), set c3 = True where id in (subquery3). Я був успішним, коли я розділив це на 3 оновлення, але я не впевнений, як досягти результату за допомогою одного оновлення. сподіваюся, це має сенс.
stackover

3
FWIW, Oracle дійсно приймає цю основну конструкцію, однак продуктивність оновлення, як правило, сильно погіршується, оскільки таблиці збільшуються. Це нормально, хоча Oracle також підтримує заяву MERGE.
gsiems

3
Це абсолютно не працює в postgresql 9.5, я отримуюERROR: 42P01: relation "dummy" does not exist
user9645

72
dummyмає бути замінено назвою таблиці, яку ви намагаєтесь оновити. Будь ласка, зрозумійте питання та відповідь, перш ніж спробувати подати заявку.
Андрій Лазар

1
Можливо, варто згадати, що на початку запиту не потрібно вказувати шлях до стовпця з лівої сторони, лише в кінці, інакше db поскаржиться на ПОМИЛКУ: посилання стовпця "address_id" неоднозначне
OJVM


51

Якщо під час приєднання немає підвищення продуктивності, то для читання я віддаю перевагу загальним виразам таблиць (CTE):

WITH subquery AS (
    SELECT address_id, customer, address, partn
    FROM  /* big hairy SQL */ ...
)
UPDATE dummy
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE dummy.address_id = subquery.address_id;

ІМХО трохи сучасніший.


1
Синтаксис не сумісний зі старими версіями Postgres до v9.1 (див postgresql.org/docs/9.1/static/sql-update.html і попередні версії) я на v8.2, так що у вас є помістити весь CTE / З оператором всередині дужок після ключового слова FROM, і він буде працювати.
Spcogg другий

9

Існує багато способів оновлення рядків.

Якщо мова йде UPDATEпро рядки з використанням підзапитів, ви можете використовувати будь-який із цих підходів.

  1. Підхід-1 [Використання прямого посилання на таблицю]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2>
WHERE
  <table1>.address_id=<table2>.address_i;

Пояснення: table1це таблиця, яку ми хочемо оновити, table2 це таблиця, з якої ми отримаємо значення для заміни / оновлення. Ми використовуємо FROMпункт для отримання table2даних. WHERE пункт допоможе встановити правильне відображення даних.

  1. Підхід-2 [Використання підзапитів]
UPDATE
  <table1>
SET
  customer=subquery.customer,
  address=subquery.address,
  partn=subquery.partn
FROM
  (
    SELECT
      address_id, customer, address, partn
    FROM  /* big hairy SQL */ ...
  ) AS subquery
WHERE
  dummy.address_id=subquery.address_id;

Пояснення: Тут ми використовуємо FROMпідпункт всередині пункту та надаємо йому псевдонім. Так що він буде діяти як стіл.

  1. Підхід-3 [Використання декількох приєднаних таблиць]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2> as t2
  JOIN <table3> as t3
  ON
    t2.id = t3.id
WHERE
  <table1>.address_id=<table2>.address_i;

Пояснення: Іноді ми стикаємося з ситуацією в цій таблиці, так що важливо отримати належні дані для оновлення. Для цього Postgres дозволяє нам приєднатися до декількох таблиць усередині FROMпропозиції.

  1. Підхід-4 [Використання оператора WITH]

    • 4.1 [Використання простого запиту]
WITH subquery AS (
    SELECT
      address_id,
      customer,
      address,
      partn
    FROM
      <table1>;
)
UPDATE <table-X>
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE <table-X>.address_id = subquery.address_id;
  • 4.2 [Використання запиту зі складним JOIN]
WITH subquery AS (
    SELECT address_id, customer, address, partn
    FROM
      <table1> as t1
    JOIN
      <table2> as t2
    ON
      t1.id = t2.id;
    -- You can build as COMPLEX as this query as per your need.
)
UPDATE <table-X>
SET customer = subquery.customer,
    address  = subquery.address,
    partn    = subquery.partn
FROM subquery
WHERE <table-X>.address_id = subquery.address_id;

Пояснення: З Postgres 9.1 WITHвведено це поняття ( ). Використовуючи це, ми можемо робити будь-які складні запити та генерувати результат бажання. Ось ми використовуємо такий підхід для оновлення таблиці.

Сподіваюся, це було б корисно.😊



1

@Mayur "4.2 [Використання запиту зі складним JOIN]" із загальними виразами таблиці (CTE) зробив для мене трюк.

WITH cte AS (
SELECT e.id, e.postcode
FROM employees e
LEFT JOIN locations lc ON lc.postcode=cte.postcode
WHERE e.id=1
)
UPDATE employee_location SET lat=lc.lat, longitude=lc.longi
FROM cte
WHERE employee_location.id=cte.id;

Сподіваюсь, це допомагає ...: D

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.