2017-10-11 4 views
5

J'ai deux tables dans une base de données de rapports, une pour les commandes et une pour les articles de commande. Chaque commande peut avoir plusieurs éléments de commande, ainsi que d'une quantité pour chaque:Comment créer une requête qui renvoie des noms de colonnes dynamiques dans Postgresql?

Orders 
+----------+---------+ 
| order_id | email | 
+----------+---------+ 
| 1  | [email protected] | 
+----------+---------+ 
| 2  | [email protected] | 
+----------+---------+ 
| 3  | [email protected] | 
+----------+---------+ 

Order Items 
+---------------+----------+----------+--------------+ 
| order_item_id | order_id | quantity | product_name | 
+---------------+----------+----------+--------------+ 
| 1    | 1  | 1  | Tee Shirt | 
+---------------+----------+----------+--------------+ 
| 2    | 1  | 3  | Jeans  | 
+---------------+----------+----------+--------------+ 
| 3    | 1  | 1  | Hat   | 
+---------------+----------+----------+--------------+ 
| 4    | 2  | 2  | Tee Shirt | 
+---------------+----------+----------+--------------+ 
| 5    | 3  | 3  | Tee Shirt | 
+---------------+----------+----------+--------------+ 
| 6    | 3  | 1  | Jeans  | 
+---------------+----------+----------+--------------+ 

Aux fins des rapports, j'adorerait denormalise ces données dans une vue PostgreSQL séparée (ou tout simplement exécuter une requête) qui transforme les données ci-dessus dans quelque chose comme ceci:

+----------+---------+-----------+-------+-----+ 
| order_id | email | Tee Shirt | Jeans | Hat | 
+----------+---------+-----------+-------+-----+ 
| 1  | [email protected] | 1   | 3  | 1 | 
+----------+---------+-----------+-------+-----+ 
| 2  | [email protected] | 2   | 0  | 0 | 
+----------+---------+-----------+-------+-----+ 
| 3  | [email protected] | 3   | 1  | 0 | 
+----------+---------+-----------+-------+-----+ 

-à-dire, il est une somme de la quantité de chaque élément dans l'ordre avec le nom du produit; et les noms de produits définis en tant que titres de colonne. Dois-je utiliser quelque chose comme un tableau croisé pour ce faire, ou y a-t-il une manière intelligente d'utiliser des sous-requêtes même si je ne connais pas la liste des noms de produits distincts avant l'exécution de la requête.

+0

Si je ne connais pas la liste des noms de produits distincts, utilisez le tableau croisé –

+0

@Joe: Avez-vous réussi à résoudre le problème? – lakshman

+0

Pas avec une requête particulièrement agréable, malheureusement, j'ai dû énumérer chacun de mes produits dans la requête. Toujours à la recherche d'un bon moyen d'utiliser le tableau croisé pour cela – Joe

Répondre

0

Ceci est une réponse possible:

create table orders 
(
    orders_id int PRIMARY KEY, 
    email text NOT NULL 
); 

create table orders_items 
(
    order_item_id int PRIMARY KEY, 
    orders_id int REFERENCES orders(orders_id) NOT NULL, 
    quantity int NOT NULL, 
    product_name text NOT NULL 
); 

insert into orders VALUES (1, '[email protected]'); 
insert into orders VALUES (2, '[email protected]'); 
insert into orders VALUES (3, '[email protected]'); 

insert into orders_items VALUES (1,1,1,'T-Shirt'); 
insert into orders_items VALUES (2,1,3,'Jeans'); 
insert into orders_items VALUES (3,1,1,'Hat'); 
insert into orders_items VALUES (4,2,2,'T-Shirt'); 
insert into orders_items VALUES (5,3,3,'T-Shirt'); 
insert into orders_items VALUES (6,3,1,'Jeans'); 


select 
    orders.orders_id, 
    email, 
    COALESCE(tshirt.quantity, 0) as "T-Shirts", 
    COALESCE(jeans.quantity,0) as "Jeans", 
    COALESCE(hat.quantity, 0) as "Hats" 
from 
    orders 
    left join (select orders_id, quantity from orders_items where product_name = 'T-Shirt') 
    as tshirt ON (tshirt.orders_id = orders.orders_id) 
    left join (select orders_id, quantity from orders_items where product_name = 'Jeans') 
    as jeans ON (jeans.orders_id = orders.orders_id) 
    left join (select orders_id, quantity from orders_items where product_name = 'Hat') 
    as hat ON (hat.orders_id = orders.orders_id) 
; 

Testé avec postgresql. Résultat:

orders_id | email | T-Shirts | Jeans | Hats 
-----------+---------+----------+-------+------ 
     1 | [email protected] |  1 |  3 | 1 
     2 | [email protected] |  2 |  0 | 0 
     3 | [email protected] |  3 |  1 | 0 
(3 rows) 

En fonction de votre commentaire, vous pouvez essayer d'utiliser tablefunc comme ceci:

CREATE EXTENSION tablefunc; 

SELECT * FROM crosstab 
(
    'SELECT orders_id, product_name, quantity FROM orders_items ORDER BY 1', 
    'SELECT DISTINCT product_name FROM orders_items ORDER BY 1' 
) 
AS 
(
     orders_id text, 
     TShirt text, 
     Jeans text, 
     Hat text 
); 

Mais je pense que vous pensez dans le mauvais sens sur SQL. Vous savez généralement quelles lignes vous voulez et vous devez le dire SQL. "Rotating tables" 90 degrés ne fait pas partie de SQL et devrait être évité.

+1

C'est génial, et fonctionne certainement. Mais ce que je recherche vraiment, c'est une requête comme celle-ci qui va évoluer jusqu'à ~ 30 noms de produits, où les noms de produits sont récupérés avec une requête comme 'select distinct (product_name) from order_items' – Joe