2010-01-11 3 views
0

J'utilisais mysql très bien jusqu'à ce que je mette une de mes applications rails à heroku et que je devais changer. Presque tout fonctionne comme prévu sauf que j'ai une requête qui fait quelque chose de totalement funky.mysql pivot vers un tableau croisé dynamique postgres

Ceci est le postgres, mais sous mysql il est la plupart du temps identique excepté le EXTRAIT DOW et certains groupes par additions, mais ce n'est pas le problème, le problème est-il utilisé pour SUM les jours de la semaine listés, maintenant il résume la table entière ... et aussi l'AVG est éteint car il obtient également la table moy et pas les jours énumérés.

Existe-t-il un moyen d'obtenir une somme des jours énumérés sans avoir à faire un autre choix, quelque chose qui me manque? ... Je voudrais éviter de faire SELECT (SELECT ...) comme SUBQUERY juste pour obtenir une somme des colonnes.

Merci

SELECT rooms.name, rooms.id, 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -3 THEN (availables.price*1) ELSE 0 END) AS day1, 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -2 THEN (availables.price*1) ELSE 0 END) AS day2, 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -1 THEN (availables.price*1) ELSE 0 END) AS day3, 
(AVG(availables.price)*1) AS avg, 
(SUM(availables.price)*1) * 2 AS sum, 
MAX((SIGN(spots)-1) + 2) AS beds 
FROM availables 
INNER JOIN rooms 
ON availables.room_id=rooms.id 
WHERE availables.room_id = '1818' AND availables.price > 0 
GROUP BY rooms.id, rooms.name 
+0

Ne pourriez-vous simplement ajouter une clause where pour filtrer les résultats des 3 derniers jours? –

+0

Qu'est-ce que "spots"? –

+0

points est le nombre de places disponibles ... 2 lits restants, etc – holden

Répondre

0

Désolé, j'ai inclus ce que la sortie ressemble à:

+------+--------+------------+-------+-------+-------+------+---------------------+ 
| id | sum | name  | day1 | day2 | day3 | beds | avg     | 
+------+--------+------------+-------+-------+-------+------+---------------------+ 
| 1819 | 131.52 | 8 Bed Dorm | 21.92 | 21.92 | 21.92 | 2 | 21.8980952380952381 | 
+------+--------+------------+-------+-------+-------+------+---------------------+ 

Et l'entrée:

+----+-------+-------+------------+---------+---------------------------+---------------------------+ 
| id | price | spots | bookdate | room_id | created_at    | updated_at    | 
+----+-------+-------+------------+---------+---------------------------+---------------------------+ 
| 1 | 27.72 | 1  | 2009-09-14 | 1  | 2009-09-11 15:32:22 +0200 | 2009-09-11 15:32:22 +0200 | 
+----+-------+-------+------------+---------+---------------------------+---------------------------+ 

Ci-dessous fonctionne et fait ce que je veux qu'il, à l'exception du avgs mais c'est vraiment en désordre ... comme je ne pouvais pas comprendre comment additionner d'une autre manière sans obtenir des sommes de toutes les nuits au lieu de seulement 2-5 ... soit 120 $ vs 20,512 $. La solution ci-dessous consistait à faire le même MAX que ci-dessus pour les jours pivotés ... jour1 jour2 ... et juste faire la même chose pour les ajouter ensemble.

La jointure n'est pas importante, c'est seulement pour tirer le nom de la pièce.

SELECT rooms.name, rooms.id, 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -3 THEN (availables.price*1) ELSE 0 END) AS day1, 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -2 THEN (availables.price*1) ELSE 0 END) AS day2, 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -1 THEN (availables.price*1) ELSE 0 END) AS day3, 
(MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -3 THEN (availables.price*1) ELSE 0 END) + 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -2 THEN (availables.price*1) ELSE 0 END) + 
MAX(CASE WHEN (EXTRACT(DOW FROM availables.bookdate) - EXTRACT(DOW FROM DATE '2010-01-20')) = -1 THEN (availables.price*1) ELSE 0 END)) *1 * 2 AS sum, 
(AVG(availables.price)*1) AS avg, 
MAX((SIGN(spots)-1) + 2) AS beds 
FROM availables 
INNER JOIN rooms 
ON availables.room_id=rooms.id 
WHERE availables.room_id = '1819' AND availables.price > 0 
GROUP BY rooms.id, rooms.name 
2

Vous ne dites pas ce que le schéma est, donc je prétendais toutes les données se trouvaient dans une table, en omettant la jointure. Il ne devrait pas être difficile de remplacer "stuff" avec votre jointure.

J'ai créé une table simple à se substituer à votre inscription:

wayne=# \d stuff 
          Table "pg_temp_1.stuff" 
    Column |  Type  |      Modifiers 
----------+---------------+---------------------------------------------------- 
id  | integer  | not null default nextval('stuff_id_seq'::regclass) 
room_id | integer  | not null 
bookdate | date   | not null 
price | numeric(10,2) | not null 
Indexes: 
    "stuff_pkey" PRIMARY KEY, btree (id) 

Ajout de quelques données à elle:

wayne=# select * from stuff; 
id | room_id | bookdate | price 
----+---------+------------+------- 
    1 |  1 | 2010-01-11 | 60.00 
    2 |  1 | 2010-01-10 | 60.00 
    3 |  2 | 2010-01-10 | 55.00 
    4 |  2 | 2010-01-09 | 55.00 
    5 |  3 | 2010-01-09 | 70.00 
    6 |  3 | 2010-01-08 | 70.00 
(6 rows) 

Et voici une requête pour les deux derniers jours complets, plus aujourd'hui, groupés par date, avec nombre, somme et prix moyen.

wayne=# select bookdate, count(*), sum(price), avg(price) from stuff \ 
where bookdate >= date_trunc('day', now()) - interval '2 days' \ 
group by bookdate order by bookdate; 
    bookdate | count | sum |   avg 
------------+-------+--------+--------------------- 
2010-01-09 |  2 | 125.00 | 62.5000000000000000 
2010-01-10 |  2 | 115.00 | 57.5000000000000000 
2010-01-11 |  1 | 60.00 | 60.0000000000000000 
(3 rows) 
1

Tout ce que vous avez à faire est de limiter les résultats aux 3 derniers jours. Cela empêchera le avg/somme d'être réalisée sur toute la table ... Ajouter ceci à votre requête existante (prise de Wayne, qui a obtenu un +1 pour l'effort)

AND availables.bookdate >= date_trunc('day', now()) - interval '2 days' 
+0

un seul problème avec cela est que je n'ai pas de données pour tous les jours, certains jours peuvent ne pas avoir de données pour des semaines. Pas de semaines probables, mais possible. ;-( – holden

+0

LIMIT ne fait rien, car il doit venir après le groupe par .. à moins qu'il y ait une autre façon dont je manque ... – holden

Questions connexes