2010-06-09 10 views
5

Estoy intentando construir una consulta de PostgreSQL que haga lo siguiente pero hasta ahora mis esfuerzos han sido en vano.seleccione una fila de la tabla y sustituya un campo con uno de otra columna si existe

Problema: Hay dos tablas: A y B. me gustaría para seleccionar todas las columnas de la tabla A (tener columnas: ID, nombre, descripción) y sustituir la columna "A.name" con el valor de la columna "B.title" de la tabla B (que tiene columnas: id, table_A_id title, langcode) donde B.table_A_id es 5 y B.langcode es "nl" (si hay alguna fila).

Mis intentos:

SELECT A.name, 
case when exists(select title from B where table_A_id = 5 and langcode= 'nl') 
then B.title 
else A.name 
END 
FROM A, B 
WHERE A.id = 5 and B.table_A_id = 5 and B.langcode = 'nl' 

-- second try: 
SELECT COALESCE(B.title, A.name) as name 
from A, B 
where A.id = 5 and B.table_A_id = 5 and exists(select title from B where table_A_id = 5 and langcode= 'nl') 

He intentado usar un caso y COALESCE(), pero fracasó debido a mi falta de experiencia con ambos conceptos.

Gracias de antemano.

+0

No muy claro. "si no es nulo", dices en el título. Pero la palabra "nulo" no aparece en la explicación. ¿Quiere decir "si hay una fila relacionada en la otra tabla"? "B.table_A_id es 5": ¿esto es realmente una constante o se refiere al valor correspondiente de A.id? Un ejemplo podría ayudar – leonbloy

+0

¿Solo desea sub el "título" si "A.name" es nulo? – rfusca

+0

He editado el título y he añadido un ejemplo. Perdón por la confusion. B.table_A_id corresponde A.id de hecho. Y en cuanto a la sustitución, A.name debe reemplazarse con B.title si B.title existe con las condiciones WHERE anteriores. – EarthMind

Respuesta

3

araqnid's es la respuesta que está buscando, apuesto.

Pero si quiere hacer cumplir que no se devuelve más de una fila por cada fila A coincidente original, puede preferir hacer una subselección en lugar de una UNIÓN IZQUIERDA. Por ejemplo:

SELECT A.id, COALESCE(
    (SELECT max(B.title) FROM B WHERE 
    langcode = 'nl' AND B.table_a_id = A.id), A.name) as name 
FROM A 
WHERE A.id = 5 

utilizo "máximo" aquí para seleccionar un valor arbitrario, en el caso de que haya más de uno. Puede usar "min" o lo que considere apropiado en su caso.

Quizás esto sea más fácil de entender que LEFT JOIN, pero (aparte de que los dos no son exactamente equivalentes) un JOIN funcionará mejor que N subselects (mucho mejor es N es grande).

De todos modos, desde el punto de vista del aprendizaje, es bueno entender ambos.

+0

Esto hace exactamente lo que quiero. Sustituye A.name con B.title si existe el segundo, de lo contrario utiliza A.name como valor de retorno de la función COALESCE. La tabla B siempre tendrá solo 1 fila para la condición WHERE dada, pero me pregunto por qué utilizó MAX() (o MIN()) en lugar de LIMIT 1. Además, solo por curiosidad, ¿hay alguna manera de reemplazar la columna de nombre? con el valor de la función COALESCE()? Uso A. * para obtener todos los valores de la tabla A y alias el resultado de COALESCE() como nombre y agrega un nombre de columna adicional1 en la matriz devuelta. Gracias de nuevo. – EarthMind

+0

Puede usar perfectamente 'LIMIT 1' (es un poco más Postgresql-céntrico que MAX/MIN). Agregué un alias ("nombre"). Me temo que tendrá que reemplazar su 'A. *' con la lista completa de columnas (excepto 'nombre'). De todos modos, usar 'A. *' se considera una mala práctica, por lo general. – leonbloy

0

Prueba este

select A.id,B.title,A.description from TableA as A inner join tableB as B 
on A.id=B.id where B.table_A_id = 5 and B.langcode ='nl' 
+0

Esta consulta no devolverá A.name cuando B.title no exista. – EarthMind

1

Ok, no estoy seguro de cómo las tablas tienen que estar unidos, pero algo como esto debería hacer el trabajo:

SELECT   yourcolumnlist, 
        CASE WHEN A.name IS NULL THEN B.title ELSE A.name END 
FROM    TableA AS A 
INNER JOIN  TableB AS B 
ON    A.id = B.table_A_id 
WHERE    B.table_A_id = 5 
AND    B.langcode = 'nl' 

Otra forma de hacerlo sería ser el uso de la COALESCE) función (:

SELECT   yourcolumnlist, 
        COALESCE(A.name, B.title) 
FROM    TableA AS A 
INNER JOIN  TableB AS B 
ON    A.id = B.table_A_id 
WHERE    B.table_A_id = 5 
AND    B.langcode = 'nl' 
+0

Ambas consultas no devuelven filas. Debo señalar que cuando la tabla B no tiene filas donde langcode = 'nl', todavía debe devolver todas las filas de la tabla A.Y si hay filas donde langcode = 'nl', entonces el campo debe ser sustituido como se menciona en mi primera publicación. – EarthMind

2
select A.id, coalesce(B.title, A.name) 
from TableA AS A 
    left join (select table_a_id, title from TableB where langcode = 'nl') AS B 
     on B.table_a_id = A.id 
WHERE A.id = 5 
+0

Esto es lo que quieres, supongo. La única advertencia es que esto potencialmente puede dar más de una fila por fila de TableA, si hay más de una fila de TableB que coincida. – leonbloy

+0

Esto tampoco se comporta como se desea. Devuelve A.name cada vez, independientemente de si B.title existe o no. – EarthMind

+0

+1 Esto debería funcionar y, en general, es mejor que mi respuesta. – leonbloy

Cuestiones relacionadas