2013-07-05 2 views
1

У меня есть две таблицы, описанные ниже:Объединение двух таблиц с агрегатами

CREATE TABLE categories 
(
    id integer NOT NULL, 
    category integer NOT NULL, 
    name text, 
    CONSTRAINT kjhfskfew PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 

CREATE TABLE products_ 
(
    id integer NOT NULL, 
    date date, 
    id_employee integer, 
    CONSTRAINT grh PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 

Теперь я должен сделать доклад, в котором мне нужно следующую информацию: categories.category, categories.name (все из них, поэтому string_agg в порядке) - может быть много назначено одной категории и product_.id_employee ->, но не с запятой, как указано выше, с именем категории, но с назначенной самой новой датой (и вот моя проблема);

Я уже пробовал конструкции, как:

SELECT 
    DISTINCT ON (category) category, 
    string_agg(name, ','), 
    (SELECT 
    id_employee 
    FROM products_ 
    WHERE date = (SELECT 
        max(date) 
       FROM products_ 
       WHERE id IN (SELECT 
           id 
           FROM categories 
           WHERE id = c.id))) 
FROM categories c 
ORDER BY category; 

Но PostgreSQL говорит, что подзапрос возвращает многие строки ... Пожалуйста, помогите!

Пример ВСТАВКИ:

INSERT INTO categories(
      id, category, name) 
    VALUES (1,22,'car'),(2,22,'bike'),(3,22,'boat'),(4,33,'soap'),(5,44,'chicken'); 

INSERT INTO products_(
      id, date, id_employee) 
    VALUES (1,'2009-11-09',11),(2,'2010-09-09',2),(3,'2013-01-01',4),(5,'2014-09-01',90); 

ОК, я решил эту проблему. Это один работает просто отлично:

WITH max_date AS (
    SELECT 
     category, 
     max(date)    AS date, 
     string_agg(name, ',') AS names 
    FROM test.products_ 
     JOIN test.categories c 
     USING (id) 
    GROUP BY c.category 
) 
SELECT 
    max(id_employee) AS id_employee, 
    md.category, 
    names 
FROM test.products_ p 
    LEFT JOIN max_date md 
    USING (date) 
    LEFT JOIN test.categories 
    USING (category) 
WHERE p.date = md.date AND p.id IN (SELECT 
             id 
            FROM test.categories 
            WHERE category = md.category) 
GROUP BY category, names; 
+0

Если вы получаете шанс добавить некоторые 'команды INSERT' для строк данных образцов и резюме результатов вы хотели бы видеть из этого образца данных, помог бы сделать такого рода вещи гораздо легче ответить. –

+0

уверен, я только что обновил свой пост. – Borys

+0

Чего вы хотите достичь, неясно. Вы можете объяснить? – chetan

ответ

1

Кажется, что id используется для соединения двух таблиц, которые, кажется мне странным.

В любом случае базовый запрос для названий категории является:

SELECT c.category, string_agg(c.name, ','), 
FROM categories c 
group by c.category; 

Вопрос: как получить самое последнее имя? Этот подход использует row_number() функцию:

SELECT c.category, string_agg(c.name, ','), cp.id_employee 
FROM categories c left outer join 
    (select c.category, c.name, p.id_employee, 
      row_number() over (partition by c.category order by date desc) as seqnum 
     from categories c left outer join 
      products_ p 
      on c.id = p.id 
    ) cp 
    on cp.category = c.category and 
     cp.seqnum = 1 
group by c.category, cp.id_employee; 
+0

Да, это решение также верно;) – Borys

+0

«Кажется, что id используется для соединения двух таблиц, что мне кажется странным». - Почему это так? – Borys

+0

@Borys. , , Первый «id», используемый в качестве имени столбца, обычно относится к столбцу первичного ключа с автоматическим приращением в таблице. И это похоже на то, как он используется здесь. Таблицы являются «параллельными», поскольку между первичными ключами существует соотношение 1-1; но у них есть имена («категории» и «продукты»), которые предлагают очень разные сущности. Я ожидаю, что первичный ключ в 'category' будет' CategoryId' (или что-то в этом роде). И для 'products_' иметь внешний ключ, ссылающийся на него. –

Смежные вопросы