mysql 数据透视表到 postgres 数据透视表

发布于 2024-08-17 04:04:44 字数 1099 浏览 4 评论 0原文

我一直很好地使用 mysql,直到我最近将我的一个 Rails 应用程序切换到 Heroku 并且不得不进行更改。几乎一切都按预期工作,除了我有一个查询做了一些完全时髦的事情。

这是postgres,但是在mysql下,除了EXTRACT DOW和一些group by添加之外,它基本上是相同的,但这不是问题,问题是它习惯了 对列出的一周中的天数进行求和,现在它对整个表求和...并且 AVG 也关闭,因为它还获取表平均值而不是列出的天数。

有没有办法获得列出的天数的总和,而不必进行另一个选择,这是我所缺少的?...我想避免仅仅为了获得总和而执行 SELECT ( SELECT ... ) as SUBQUERY列。

谢谢

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

I was using mysql just fine until I recently switched one of my rails apps to heroku and had to change over. Almost everything works as expected except I have one query which does something totally funky.

This is the postgres, but under mysql it is mostly identical except for the EXTRACT DOW and some group by additions, but that isn't the problem, the problem is it used to
SUM the days of the week listed, now it sums the entire table... and also the AVG is off since it also gets the table avg and not the days listed.

Is there a way to get a sum of the listed days without having to do another select, something i'm missing?... I would like to avoid doing SELECT ( SELECT ... ) as SUBQUERY just to get a sum of the columns.

Thanks

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

转身以后 2024-08-24 04:04:44

您没有说明架构是什么,所以我假装所有数据都在一张表中,省略了联接。用您的连接替换“stuff”应该不成问题。

我创建了一个简单的表来代表您的连接: 向

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)

其中添加了一些数据:

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)

这是最近两天加上今天的查询,按日期分组,包含计数、总和和平均价格。

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)

You didn't say what the schema is, so I pretended all of the data was in one table, omitting the join. It should be no trouble to replace "stuff" with your join.

I created a simple table to stand in for your join:

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)

Added some data to it:

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)

And here's a query for the last two full days, plus today, grouped by date, with count, sum and avg price.

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)
十年不长 2024-08-24 04:04:44

您所需要做的就是将结果限制为过去 3 天。这将阻止在整个表上执行平均值/求和...将此添加到您现有的查询中(取自 Wayne,他的努力获得了+1)

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

All you need to do is limit the results to the past 3 days. This will prevent the avg/sum from being performed on the entire table...Add this to your existing query (taken from Wayne, who got a +1 for the effort)

AND availables.bookdate >= date_trunc('day', now()) - interval '2 days'
许一世地老天荒 2024-08-24 04:04:44

抱歉,我应该包括输出的样子:

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

和输入:

+----+-------+-------+------------+---------+---------------------------+---------------------------+
| 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 |
+----+-------+-------+------------+---------+---------------------------+---------------------------+

下面可以工作并执行我想要的操作,除了平均值,但它真的很混乱......因为我无法弄清楚如何在任何其他中求和无需计算所有夜晚的总和,而只是 2-5 晚的总和...即 120 美元 vs 20,512 美元。下面的解决方案是对旋转天数执行与上面相同的 MAX...day1 day2...,然后执行相同的操作将它们加在一起。

加入并不重要,只是拉取房间的名称。

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

Sorry, I should have included what the output looks like:

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

And the input:

+----+-------+-------+------------+---------+---------------------------+---------------------------+
| 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 |
+----+-------+-------+------------+---------+---------------------------+---------------------------+

Below works and does what I want it to, except for the avgs but it's really messy... as I couldn't figure out how to sum in any other way without getting sums of all nights instead of just 2-5... ie $120 vs $20,512. The solution below was to do the same MAX as above for pivoted days... day1 day2... and just doing the same to add them together.

The join is not important, its only to pull the name of the room.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文