2011-01-15 10 views
5

Come posso estrarre i valori da un record come singoli comuns in PostgreSQLCome posso estrarre i valori da un record come singole colonne in 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 

Invece di

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

vorrei per avere

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

C'è un modo per selezionare solo un'immagine per ciascun prodotto e restituire le colonne d irettamente invece di un disco?

+0

Perché avete bisogno di raggruppare quei 4 colonne per una colonna? –

+0

Non ho bisogno di raggrupparli, voglio solo avere un'immagine per ogni prodotto ma non c'è modo di mettere LIMIT su un join come in mysql, la cosa migliore che ho ottenuto è stata la query sopra con ROW – codeassembly

risposta

0

Basta specificare i componenti del 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 

Ma in ogni caso, vorrei rielaborare la query e utilizzare un join invece di una sottoclausola.

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 

Ma credo che bisogna specificare tutti i p-campi della distinta separatamente per garantire una sola immagine viene caricata per ogni prodotto.

+0

davvero lavoro per te? accedere ai campi dall'interno della riga usando la sintassi 'image.id'? Non riesco a farlo funzionare per i miei UDT ... –

+0

Ottengo 'ERRORE: manca la clausola FROM-entry per la tabella "image"' per la prima query, e la seconda non funziona "ERRORE: SELECT DISTINCT ON le espressioni devono corrispondere alle espressioni ORDER BY iniziali" Penso anche è più veloce eseguire una subquery per ogni prodotto (solo 10 in questo caso) invece di unire tutto e aggiungere DISTINCT, DISTINCT può essere molto lento se le tabelle sono grandi. – codeassembly

+0

ha voluto svendere la risposta per non provarlo in un codice proof-of-concept se la funzione ROW utilizza effettivamente i nomi di colonna come nomi di proprietà per struct. correggi il tuo codice, o cancellalo (così puoi guadagnare un ** distintivo ** disciplinato) il tuo codice non funzionerà, prova questo: 'seleziona x.table_name da (seleziona riga (nome_tabella, nome_colonna) x da information_schema.columns limite 1) come y' –

3

Prova questo:

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 

In alternativa, si può fare questo:

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 

Per selezionare tutti i campi:

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 

si può fare anche questo, ma questo rende la tutto l'esercizio dell'utilizzo di ROW senza punti quando si può semplicemente rimuovere la funzione ROW e riprenderla dall'esterno di ct/derivato e. Ho ipotizzato che la ROW dell'OP provenisse da una funzione; per la quale egli dovrebbe utilizzare i codici di sopra, non è la seguente:

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

che sembra essere molto utile per la mia query semplice, quindi suppongo che l'utilizzo di ROW non sia una buona soluzione per il mio problema principale, estrarre una riga dalla tabella delle immagini per ogni riga di prodotto. – codeassembly

+0

infatti, ecco perché, in primo luogo, ti chiedo perché è necessario raggruppare le colonne in una colonna –

0

Prova questa, lavorerà sul vostro codice esistente con modifiche minime (se la creazione di un tipo è una modifica minima per voi ;-)

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 

Proof-of-concept code:

Crea tipo prima:

create type your_type_here as (table_name varchar, column_name varchar) 

effettiva co 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) 

Ma credo che si dovrebbe affrontare con GROUP BY' and MAX combo or use ON` DISTINCT come quello che Daniel hanno inviato

Problemi correlati