Как извлечь значения из записи в виде отдельных столбцов в postgresql - PullRequest
9 голосов
/ 15 января 2011

Как мне извлечь значения из записи как отдельные команды в 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

Вместо

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

Я хотел бы получить

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

Есть ли способ выбрать только одно изображение для каждого продукта и вернуть столбцы непосредственно вместо записи?

Ответы [ 4 ]

7 голосов
/ 15 января 2011

Попробуйте:

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

В качестве альтернативы вы можете сделать это:

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

Чтобы выбрать все поля:

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

Вы можете сделать это тоже, но это делает все упражнение использования ROW бессмысленным, когда вы можете просто удалить функцию ROW и перехватить ее из-за пределов cte / производной таблицы.Я предположил, что ОП ОП пришла из функции;для чего он должен использовать коды выше, а не следующие:

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
3 голосов
/ 15 января 2011

Просто укажите компоненты вашей структуры:

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

Но в любом случае я бы переработал запрос и использовал бы объединение вместо подпункта.

 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

Но я считаю, что вы должны указать все p-поля в отдельности отдельно, чтобы обеспечить загрузку только одного изображения для каждого продукта.

1 голос
/ 15 января 2011

Попробуйте, это будет работать с вашим существующим кодом с минимальными изменениями (если создание типа является минимальной модификацией для вас; -)

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

Код подтверждения концепции:

Сначала создайте тип:

create type your_type_here as (table_name varchar, column_name varchar)

Фактический код:

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)

Но я полагаю, вы должны решить эту проблему с помощью GROUP BY' and MAX combo or use DISTINCT ON`, как то, что написал Дэниел

0 голосов
/ 29 мая 2019

каждая таблица имеет связанный составной тип с тем же именем

https://www.postgresql.org/docs/current/plpgsql-declarations.html#PLPGSQL-DECLARATION-ROWTYPES

Итак, этот код

drop table if exists "#typedef_image"
;
create temp table "#typedef_image"(
    id int,
    server_id int,
    format text,
    product_id int
    )
;
select (row(3, 4, 'jpeg', 7)::"#typedef_image").*

будет работать

...