鉴于以下表格:
shows:
title | basic_ticket_price
----------------+--------------------
Inception | $3.50
Romeo & Juliet | $2.00
performance:
perf_date | perf_time | title
------------+-----------+----------------
2012-08-14 | 00:08:00 | Inception
2012-08-12 | 00:12:00 | Romeo & Juliet
booking:
ticket_no | perf_date | perf_time | row_no | person_id
-----------+------------+-----------+--------+-----------
1 | 2012-08-14 | 00:08:00 | P01 | 1
2 | 2012-08-12 | 00:12:00 | O05 | 4
3 | 2012-08-12 | 00:12:00 | A01 | 2
另外一张桌子:座位,其中包含一个座位列表,其编号与预订时的row_no的座位名称相同。
使用此声明对预订的座位进行分组:
select count(row_no) AS row_no,
area_name
from seat
where exists (select row_no
from booking
where booking.row_no = seat.row_no)
group by area_name;
产生:
row_no | area_name
--------+--------------
1 | rear stalls
2 | front stalls
我现在如何使用count rows和area_name编写单个SQL语句来生成一个列表,显示节目名称,演出日期和时间以及每个区域预订座位数?
我试过这个:
select s.title,
perf_date,
perf_time,
count(row_no) AS row_no,
area_name
from shows s,
performance,
seat
where exists (select row_no
from booking
where booking.row_no = seat.row_no)
group by area_name,s.title,performance.perf_date,performance.perf_time;
但它显示了重复的行:
title | perf_date | perf_time | row_no | area_name
----------------+------------+-----------+--------+--------------
Romeo & Juliet | 2012-08-12 | 00:12:00 | 1 | rear stalls
Romeo & Juliet | 2012-08-14 | 00:08:00 | 2 | front stalls
Inception | 2012-08-12 | 00:12:00 | 1 | rear stalls
Inception | 2012-08-14 | 00:08:00 | 2 | front stalls
Inception | 2012-08-14 | 00:08:00 | 1 | rear stalls
Inception | 2012-08-12 | 00:12:00 | 2 | front stalls
Romeo & Juliet | 2012-08-14 | 00:08:00 | 1 | rear stalls
Romeo & Juliet | 2012-08-12 | 00:12:00 | 2 | front stalls
(8 rows)
任何帮助解决这个问题都将受到赞赏。
答案 0 :(得分:2)
您应该考虑将列perf_date date
和perf_time time
合并到一个timestamp
列中:
perf_timestamp timestamp
如果您需要时间戳中的date
或time
,只需将其投射为:
SELECT perf_timestamp::time;
SELECT perf_timestamp::date;
我通常建议使用代理主键。 “节目”(电影片名)的名称不是自然键 - 它不是唯一的。或者,正如@user_unknown已经提到的:开始时间对于性能来说不是实用的主键。您可以使用serial列。整个设置看起来像这样:
-- show:
CREATE TEMP TABLE show (
show_id serial PRIMARY KEY
,title text
,basic_ticket_price money -- or numeric
);
INSERT INTO show (title, basic_ticket_price) VALUES
('Inception', 3.50)
,('Romeo & Juliet', 2.00);
-- performance:
CREATE TEMP TABLE performance (
performance_id serial PRIMARY KEY
,show_id int REFERENCES show(show_id) ON UPDATE CASCADE
,perf_start timestamp
);
INSERT INTO performance (show_id, perf_start) VALUES
(1, '2012-08-14 00:08')
,(2, '2012-08-12 00:12');
-- seat:
CREATE TEMP TABLE seat (
row_no text PRIMARY KEY
,area_name text
);
INSERT INTO seat (row_no, area_name) VALUES
('P01', 'rear stalls')
,('O05', 'front stalls')
,('A01', 'front stalls');
-- booking:
CREATE TEMP TABLE booking (
ticket_id serial PRIMARY KEY
,performance_id int REFERENCES performance(performance_id) ON UPDATE CASCADE
,row_no text REFERENCES seat(row_no) ON UPDATE CASCADE
,person_id int -- REFERENCES ?
);
INSERT INTO booking (performance_id, row_no, person_id) VALUES
(1, 'P01', 1)
,(2, 'O05', 4)
,(2, 'A01', 2);
然后您的查询可能如下所示:
SELECT p.perf_start
,sh.title
,s.area_name
,count(*) booked
FROM booking b
JOIN seat s USING (row_no)
JOIN performance p USING (performance_id)
JOIN show sh USING (show_id)
GROUP BY 1,2,3
ORDER BY 1,2,3;
结果:
perf_start | title | area_name | booked
---------------------+----------------+--------------+-------
2012-08-12 00:12:00 | Romeo & Juliet | front stalls | 2
2012-08-14 00:08:00 | Inception | rear stalls | 1
答案 1 :(得分:0)
您的行不会重复。请注意结果中date
和area_name
的差异。这对我来说都很好。
答案 2 :(得分:0)
在每个效果条目上,查找所有预订。在这些预订中,链接到座位表以确定区域名称。然后,简单的COUNT(*)按每个节目/区域的标准分组。
SELECT
p.perf_date,
p.perf_time,
p.title,
s.area_name,
COUNT(*) as SeatsSold
from
performance p
JOIN booking b
ON p.perf_date = b.perf_date
AND p.perf_time = b.perf_time
JOIN seat s
ON b.row_no = s.row_no
group by
p.perf_date,
p.perf_time,
p.title,
s.area_name