actualizar filas de tabla en postgres usando subconsulta

304

Usando postgres 8.4, mi objetivo es actualizar la tabla existente:

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
);

Inicialmente probé mi consulta usando la instrucción de inserción:

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

al ser novato, no puedo convertir la declaración de actualización, es decir, actualizar las filas existentes con valores devueltos por la declaración de selección. Cualquier ayuda es muy apreciada.

apilamiento
fuente
¿tiene algún tipo de identificación en la tabla de direcciones que pueda usarse para determinar que esa fila existe?
Andrey Adamovich
Sí, pero es sys generado.
stackover

Respuestas:

683

Postgres permite:

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;

Esta sintaxis no es SQL estándar, pero es mucho más conveniente para este tipo de consulta que SQL estándar. Creo que Oracle (al menos) acepta algo similar.

Andrew Lazarus
fuente
Parece que estoy intentando algo diferente, por ejemplo. si hay 3 columnas bool c1, c2, c3 todas configuradas en falso inicialmente. pero basado en subconsulta se establecen en verdadero. actualice el conjunto c1 = VERDADERO donde id en (subconsulta1), establezca c2 = VERDADERO donde id en (subconsulta2), establezca c3 = Verdadero donde id en (subconsulta3). Tuve éxito cuando dividí esto como 3 actualizaciones, pero no estoy seguro de cómo lograr el resultado con una sola actualización. Espero que esto tenga sentido.
stackover
3
FWIW, Oracle acepta esa construcción básica, sin embargo, el rendimiento de la actualización tiende a degradarse severamente a medida que las tablas se hacen más grandes. Eso está bien, ya que Oracle también admite la declaración MERGE.
gsiems
3
Esto no lo hace totalmente el trabajo en PostgreSQL 9.5, lo entiendoERROR: 42P01: relation "dummy" does not exist
user9645
73
dummytiene que ser reemplazado por el nombre de la tabla que está intentando actualizar. Por favor, comprenda la pregunta y la respuesta antes de intentar aplicar.
Andrew Lazarus
1
Vale la pena mencionar que al comienzo de la consulta no es necesario especificar la ruta a la columna del lado izquierdo, solo al final, de lo contrario, la base de datos se quejará con ERROR: la referencia de columna "address_id" es ambigua
OJVM
51

Si no hay ganancias de rendimiento con una combinación, prefiero las expresiones de tabla comunes (CTE) para facilitar la lectura:

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;

En mi humilde opinión un poco más moderno.

steevee
fuente
1
La sintaxis no es compatible con versiones anteriores de Postgres, anteriores a v9.1, (consulte postgresql.org/docs/9.1/static/sql-update.html y las versiones anteriores) Estoy en v8.2, así que tiene para poner toda la instrucción CTE / With entre corchetes después de la palabra clave FROM y funcionará.
Spcogg el segundo
9

Hay muchas formas de actualizar las filas.

Cuando se trata de UPDATEfilas usando subconsultas, puede usar cualquiera de estos enfoques.

  1. Enfoque-1 [Uso de referencia directa de tabla]
UPDATE
  <table1>
SET
  customer=<table2>.customer,
  address=<table2>.address,
  partn=<table2>.partn
FROM
  <table2>
WHERE
  <table1>.address_id=<table2>.address_i;

Explicación: table1es la tabla que queremos actualizar, table2 es la tabla, de la que obtendremos el valor que se reemplazará / actualizará. Estamos usando una FROMcláusula para obtener los table2datos de. WHERE La cláusula ayudará a establecer la asignación de datos adecuada.

  1. Enfoque-2 [Uso de SubQueries]
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;

Explicación: Aquí estamos usando subquerie dentro de la FROMcláusula y le estamos dando un alias. Para que actúe como la mesa.

  1. Enfoque-3 [Uso de varias tablas unidas]
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;

Explicación: A veces nos enfrentamos a la situación en que la unión de tabla es tan importante para obtener los datos adecuados para la actualización. Para hacerlo, Postgres nos permite unir varias tablas dentro de la FROMcláusula.

  1. Enfoque-4 [Uso de la instrucción WITH]

    • 4.1 [Utilizando una consulta simple]
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 [Uso de la consulta con JOIN complejo]
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;

Explicación: Desde Postgres 9.1, este ( WITH) concepto ha sido introducido. Usando eso, podemos hacer consultas complejas y generar resultados de deseo. Aquí estamos usando este enfoque para actualizar la tabla.

Espero que esto sea útil.

Mayur
fuente
1
update json_source_tabcol as d
set isnullable = a.is_Nullable
from information_schema.columns as a 
where a.table_name =d.table_name 
and a.table_schema = d.table_schema 
and a.column_name = d.column_name;
Pugazendhi Asaimuthu
fuente
1

@Mayur "4.2 [Uso de la consulta con JOIN complejo]" con expresiones de tabla comunes (CTE) me ayudó.

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;

Espero que esto ayude ...: D

Festus Ngor
fuente