2011-01-15 3 views
5

Comment puis-je extraire les valeurs d'un enregistrement comme comuns individuels dans postgresqlComment puis-je extraire les valeurs d'un enregistrement sous forme de colonnes individuelles dans postgresql

SELECT 
p.*, 
(SELECT ROW(id,server_id,format,product_id) FROM products_images pi WHERE pi.product_id = p.id LIMIT 1) AS image 

FROM products p 

WHERE p.company = 1 ORDER BY id ASC LIMIT 10 

Au lieu de

image 
(3, 4, "jpeg", 7) 

Je voudrais avoir

id | server_id | format | product_id 
3 | 4   | jpeg | 7 

Y at-il un moyen de sélectionner une seule image pour chaque produit et retourner les colonnes d irectement au lieu d'un record?

+0

Pourquoi avez-vous besoin de regrouper ces 4 colonnes à une colonne? –

+0

Je n'ai pas besoin de les grouper, je veux juste avoir une image pour chaque produit mais il n'y a aucun moyen de mettre LIMIT sur une jointure comme dans mysql, la meilleure chose que j'ai obtenue est la requête ci-dessus avec ROW – codeassembly

Répondre

0

Il suffit de spécifier les composants de votre struct:

SELECT a,b,c,image.id, image.server_id, ... 
FROM (

SELECT 
p.*, 
(SELECT ROW(id,server_id,format,product_id) FROM products_images pi WHERE pi.product_id = p.id LIMIT 1) AS image 

FROM products p 

WHERE p.company = 1 ORDER BY id ASC LIMIT 10 
) as subquery 

Mais de toute façon, je serais réusinage la requête et utiliser une jointure au lieu d'un paragraphe.

SELECT DISTINCT ON (p.*) p.*, 
     p.id,pi.server_id,pi.format,pi.product_id 
    FROM products p 
    LEFT JOIN product_images pi ON pi.product_id = p.id 
    WHERE p.company = 1 
    ORDER BY id ASC 
    LIMIT 10 

Mais je crois que vous devez spécifier tous les champs de p dans le distinct séparément pour assurer une seule image est chargée par produit.

+0

vraiment travailler pour vous? accéder aux champs depuis la ligne en utilisant la syntaxe 'image.id'? Je ne peux pas le faire fonctionner pour mon UDT ... –

+0

Je reçois 'ERREUR: entrée de clause FROM manquante pour la table "image"' pour la première requête, et la seconde ne fonctionne pas "ERREUR: SELECT DISTINCT ON expressions doivent correspondre à des expressions initiales ORDER BY" Je pense aussi c'est plus rapide d'exécuter une sous-requête pour chaque produit (seulement 10 dans ce cas) au lieu de tout joindre et d'ajouter DISTINCT, DISTINCT peut être très lent si les tables sont grandes. – codeassembly

+0

a voulu réduire votre réponse pour ne pas l'essayer dans un code de preuve de concept si la fonction ROW utilise en effet les noms de colonnes comme noms de propriétés pour struct. corrigez votre code, ou supprimez-le (pour pouvoir obtenir un badge ** discipliné) votre code ne fonctionnera pas, essayez ceci: 'select x.table_name from (sélectionnez row (nom_table, column_name) x from information_schema.columns limite 1) comme y' –

3

Essayez ceci:

create type xxx as (t varchar, y varchar, z int); 

with a as 
(
select row(table_name, column_name, (random() * 100)::int) x 
from information_schema.columns 
) 
-- cannot cast directly to xxx, should cast to text first 
select (x::text::xxx).t, (x::text::xxx).y, (x::text::xxx).z 
from a 

Vous pouvez faire ceci:

with a as 
(
select row(table_name, column_name, (random() * 100)::int) x 
from information_schema.columns 
), 
-- cannot cast directly to xxx, should cast to text first 
b as (select x::text::xxx as w from a) 

select 
(w).t, (w).y, (w).z 
from b 

Pour sélectionner tous les champs:

with a as 
(
select row(table_name, column_name, (random() * 100)::int) x 
from information_schema.columns 
), 
-- cannot cast directly to xxx, should cast to text first 
b as (select x::text::xxx as w from a) 

select 
(w).* 
from b 

Vous pouvez le faire aussi, mais ce qui rend la tout l'exercice d'utiliser ROW un inutile lorsque vous pouvez simplement supprimer la fonction ROW et le ramasser de l'extérieur de cte/derived tabl e. J'ai supposé que le ROW de l'OP provenait d'une fonction; pour lequel il doit utiliser les codes ci-dessus, pas ce qui suit:

with a as 
(
select row(table_name, column_name, (random() * 100)::int)::xxx x 
from information_schema.columns 
) 
select 
(x).t, (x).y, (x).z 
from a 
+0

cela semble être beaucoup de travail pour ma requête simple, donc je suppose que l'utilisation de ROW n'est pas une bonne solution pour mon problème principal, extraire une ligne de la table des images pour chaque ligne de produit. – codeassembly

+0

en effet, c'est pourquoi en premier lieu, je vous demande pourquoi vous avez besoin de regrouper les colonnes à une colonne –

0

Essayez cela fonctionnera sur votre code existant avec un minimum de modifications (si la création d'un type est une modification minimale pour vous ;-)

create type image_type as (id int, server_id int, format varchar, product_id int); 

SELECT 
p.*, 
((SELECT ROW(id,server_id,format,product_id) 
    FROM products_images pi 
    WHERE pi.product_id = p.id LIMIT 1)::text::image_type).* 

FROM products p 

WHERE p.company = 1 ORDER BY id ASC LIMIT 10 

preuve de concept Code:

Créer premier type:

create type your_type_here as (table_name varchar, column_name varchar) 

co réelle de:

select 
a.b, 
((select row(table_name, column_name) 
    from information_schema.columns limit 1)::text::your_type_here).* 
from generate_series(1,10) as a(b) 

Mais je suppose que vous devez aborder avec GROUP BY' and MAX combo or use DISTINCT ON` comme ce que Daniel a posté

Questions connexes