-
Notifications
You must be signed in to change notification settings - Fork 1
/
tasks.sql
539 lines (445 loc) · 12.7 KB
/
tasks.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
USE retreat;
SET SQL_mode='';
-- TABLES
SELECT * FROM customer_addresses;
SELECT * FROM customers;
SELECT * FROM cabins;
SELECT * FROM cabin_facilities;
SELECT * FROM extras;
SELECT * FROM bookings;
SELECT * FROM cabins_booked;
SELECT * FROM extras_booked;
-- VIEWS
SELECT * FROM contact_details;
SELECT * FROM cabin_details;
SELECT * FROM cabins_booked_details;
SELECT * FROM extras_booked_details;
SELECT * FROM extras_total;
SELECT * FROM cabin_total;
SELECT * FROM cost_of_holiday;
---------------------------------------------------------------------------------------
-- TASK 1 - VIEW WITH JOINS
-- Using any type of the joins, create a view that combines multiple tables in a
-- logical way.
---------------------------------------------------------------------------------------
-- VIEW 1
-- Some customers live at the same address so addresses had to be kept separate from
-- names and moved into a separate table to reduce data redundancy and keep the table
-- in 3NF. A view has been created to see all of their contact details, including their
-- addresses, in one place. A left join is used here in case there are random addresses
-- listed in the customer_addresses table that aren't associated with a customer.
CREATE VIEW contact_details AS
SELECT
c.cust_id AS customer_id,
c.f_name AS first_name,
c.l_name AS last_name,
c.email AS email,
c.phone AS phone,
a.line1 AS address_line1,
a.line2 AS address_line2,
a.town AS town,
a.county AS county,
a.p_code AS postcode
FROM
customers AS c
LEFT JOIN
customer_addresses AS a ON c.add_id = a.add_id;
SELECT * FROM contact_details;
-- VIEW 2
-- To ensure the database was in 3NF, cabin facilities had to be kept in a separate table
-- from cabin nightly rates. This is because the nightly rate is dependent on the cabin
-- facilities (e.g. if a cabin gets a hot tub then the nightly rate will increase). 3NF
-- requires that there are no such situations (known as transitive functional dependencies)
-- in a table. The following view shows all the information we have about a cabin all in
-- one place.
CREATE VIEW cabin_details AS
SELECT
c.cab_id,
c.cabin_name,
c.night_rate,
f.capacity,
f.hot_tub,
f.lake_view,
f.forest_view
FROM
cabins AS c
INNER JOIN
cabin_facilities AS f
ON c.cab_id = f.cab_id;
SELECT * FROM cabin_details;
-- VIEW 3
-- Adds cabin details onto cabin bookings.
CREATE VIEW cabins_booked_details AS
SELECT
cab_bk.cab_bk_id AS cabin_booking_id,
c.f_name,
c.l_name,
c.phone,
cd.cab_id,
cd.cabin_name,
cd.capacity,
cd.hot_tub,
cd.lake_view,
cd.forest_view,
cab_bk.chk_in,
cab_bk.chk_out,
cab_bk.nights AS nights,
cd.night_rate,
cab_bk.nights * cd.night_rate AS total_price,
cab_bk.bk_id
FROM
cabins_booked AS cab_bk
INNER JOIN
cabin_details AS cd
ON cd.cab_id = cab_bk.cab_id
INNER JOIN
bookings AS b
ON b.bk_id = cab_bk.bk_id
INNER JOIN
customers AS c
ON c.cust_id = b.cust_id
ORDER BY
cab_bk_id;
SELECT * FROM cabins_booked_details;
-- VIEW 4
-- Adds extra activity details onto extra activity bookings.
CREATE VIEW extras_booked_details AS
SELECT
ex_bk_id AS extra_booking_id,
c.f_name,
c.l_name,
c.phone,
e.ex_id,
e.item,
ex_bk.date_of_activity,
ex_bk.quantity,
e.price AS activity_price,
e.price * ex_bk.quantity AS total_price,
ex_bk.bk_id
FROM
extras AS e
INNER JOIN
extras_booked AS ex_bk
ON e.ex_id = ex_bk.ex_id
INNER JOIN
bookings AS b
ON b.bk_id = ex_bk.bk_id
INNER JOIN
customers AS c
ON c.cust_id = b.cust_id
ORDER BY
extra_booking_id;
SELECT * FROM extras_booked_details;
-- VIEW 5, 6 & 7
-- Find the total price for bookings (using views already made). I had trouble with this
-- as some people didn't book any extra activities. This meant that they had null values
-- in the total price of extras booked. I managed to get around this using COALESCE. A
-- left join is required here.
CREATE VIEW cabin_total AS
SELECT
cbd.bk_id,
SUM(cbd.total_price) AS cabin_total
FROM
cabins_booked_details AS cbd
GROUP BY
cbd.bk_id
ORDER BY
cbd.bk_id;
CREATE VIEW extras_total AS
SELECT
ebd.bk_id,
SUM(ebd.total_price) AS extras_total
FROM
extras_booked_details AS ebd
GROUP BY
ebd.bk_id
ORDER BY
bk_id;
CREATE VIEW cost_of_holiday AS
SELECT DISTINCT
ct.bk_id,
ct.cabin_total,
et.extras_total,
COALESCE(ct.cabin_total + et.extras_total, ct.cabin_total, et.extras_total) AS holiday_total
FROM
cabin_total AS ct
LEFT JOIN
extras_total AS et
ON ct.bk_id = et.bk_id
GROUP BY
ct.bk_id;
-- NOTE: requires SET SQL_mode='';
SELECT * FROM cost_of_holiday;
---------------------------------------------------------------------------------------
-- TASK 2 - STORED FUNCTIONS
-- In your database, create a stored function that can be applied to a
-- query in your DB.
---------------------------------------------------------------------------------------
-- SCENARIO:
-- Every now and again I run a sale. This gives people 5% off the total cost of their
-- holiday. The following function can be run during the sale to find the final price
-- the customer needs to pay.
DELIMITER //
CREATE FUNCTION discounted_price(input_amount DECIMAL(7,2))
RETURNS DECIMAL(7,2)
DETERMINISTIC
BEGIN
DECLARE output_amount DECIMAL(7,2);
SET output_amount = input_amount - 5 / 100 * input_amount;
RETURN output_amount;
END//
DELIMITER ;
-- Example:
SELECT
cst.bk_id,
cst.holiday_total,
discounted_price(cst.holiday_total) AS total_after_discount
FROM
cost_of_holiday AS cst;
---------------------------------------------------------------------------------------
-- TASK 3 - SUBQUERY
-- Prepare an example query with a subquery to demonstrate how to
-- extract data from your DB for analysis.
---------------------------------------------------------------------------------------
-- SCENARIO 1:
-- Patricia Vaughn has phoned up to check if the cabin she has booked has a hot tub.
-- To find this information out, we can use the following query.
SELECT f.hot_tub
FROM cabin_facilities AS f
WHERE cab_id IN(
SELECT cab_bk.cab_id
FROM cabins_booked AS cab_bk
WHERE bk_id IN(
SELECT b.bk_id
FROM bookings AS b
WHERE cust_id IN(
SELECT c.cust_id
FROM customers AS c
WHERE f_name = 'Patricia'
AND l_name = 'Vaughn'
)
)
)
;
-- The results return a "1", meaning that Patricia Vaughn has booked one cabin and it
-- does have a hot tub! This was a bit long-winded. Would be better to have a view with
-- more info in one place and query that instead.
-- SCENARIO 2:
-- Find out where the customers are visiting from in July.
SELECT a.county
FROM customer_addresses AS a
WHERE add_id IN(
SELECT c.add_id
FROM customers AS c
WHERE cust_id IN(
SELECT b.cust_id
FROM bookings AS b
WHERE bk_id IN(
SELECT cab_bk.bk_id
FROM cabins_booked AS cab_bk
WHERE month(cab_bk.chk_in) = 07
)
)
)
GROUP BY a.county
;
-- Data exported as csv file to explore with Tableau.
---------------------------------------------------------------------------------------
-- TASK 4 - STORED PROCEDURE
-- In your database, create a stored procedure and demonstrate how it runs.
---------------------------------------------------------------------------------------
-- SCENARIO 1:
-- The staff need to know how many bikes, kayaks and SUPs to get out of the shed each
-- morning in order to have them ready for when the customers arrive.
DELIMITER //
CREATE PROCEDURE bikes_needed(on_date DATE)
BEGIN
SELECT
SUM(ex_bk.quantity) AS total_bikes_required
FROM
extras_booked AS ex_bk
WHERE ex_id IN (
SELECT e.ex_id
FROM extras AS e
WHERE e.item = 'bicycle hire')
AND ex_bk.date_of_activity = on_date;
END//
DELIMITER ;
DELIMITER //
CREATE PROCEDURE kayaks_needed(on_date DATE)
BEGIN
SELECT
SUM(ex_bk.quantity) AS total_kayaks_required
FROM
extras_booked AS ex_bk
WHERE ex_id IN (
SELECT e.ex_id
FROM extras AS e
WHERE e.item = 'kayak hire')
AND ex_bk.date_of_activity = on_date;
END//
DELIMITER ;
DELIMITER //
CREATE PROCEDURE sups_needed(on_date DATE)
BEGIN
SELECT
SUM(ex_bk.quantity) AS total_sups_required
FROM
extras_booked AS ex_bk
WHERE ex_id IN (
SELECT e.ex_id
FROM extras AS e
WHERE e.item = 'sup hire')
AND ex_bk.date_of_activity = on_date;
END//
DELIMITER ;
-- Examples:
CALL bikes_needed('2020-07-18');
CALL kayaks_needed('2020-07-04');
CALL sups_needed('2020-07-22');
-- SCENARIO 2:
-- Find all bookings that are checking in today.
DELIMITER //
CREATE PROCEDURE checking_in(check_in_date DATE)
BEGIN
SELECT
cbd.f_name AS first_name,
cbd.l_name AS last_name,
cbd.phone,
cbd.cab_id AS cabin_id,
cbd.cabin_name,
cbd.chk_in AS check_in_date,
cbd.chk_out AS check_out_date
FROM
cabins_booked_details AS cbd
WHERE
cbd.chk_in = check_in_date;
END//
DELIMITER ;
CALL checking_in('2020-07-03');
-- SCENARIO 4:
-- Find out who is checking out today so I know where to send housekeeping.
DELIMITER //
CREATE PROCEDURE checking_out(check_out_date DATE)
BEGIN
SELECT
cbd.f_name AS first_name,
cbd.l_name AS last_name,
cbd.phone,
cbd.cab_id AS cabin_id,
cbd.cabin_name,
cbd.chk_in AS check_in_date,
cbd.chk_out AS check_out_date
FROM
cabins_booked_details AS cbd
WHERE
cbd.chk_out = check_out_date;
END//
DELIMITER ;
CALL checking_out('2020-07-19');
---------------------------------------------------------------------------------------
-- TASK 5 - TRIGGERS
-- In your database, create a trigger and demonstrate how it runs.
---------------------------------------------------------------------------------------
-- SCENARIO:
-- I've created a column in the cabins_booked tables that contains the number of nights
-- calculated from the check in and check out dates. However, if I insert a new cabin
-- booking, it doesn't automatically calculate the number of nights. I have written a
-- trigger that will do just that:
DELIMITER //
CREATE TRIGGER nights
BEFORE INSERT ON cabins_booked
FOR EACH ROW
BEGIN
SET new.nights = DATEDIFF(new.chk_out, new.chk_in);
END//
DELIMITER ;
-- Insert a cabin booking to check it worked:
INSERT INTO cabins_booked
(cab_id, chk_in, chk_out, bk_id)
VALUES
(5, '2020-08-07', '2020-08-15', 27);
-- We can see it has calulated that this new booking is 8 nights long:
SELECT * FROM cabins_booked;
---------------------------------------------------------------------------------------
-- TASK 6 - COMPLEX VIEW
-- Create a view that uses at least 3-4 base tables. Prepare and demonstrate a query
-- that uses the view to produce a logically arranged result set for analysis.
---------------------------------------------------------------------------------------
-- I have already created such views above. I will use one of them to query.
-- SCENARIO:
-- My yoga teacher has decided to go travelling in August. I want to find out who has
-- booked a yoga class in August and phone them up to let them know I have to cancel.
-- I will use the following view, here is a recap of what it contains:
SELECT * FROM extras_booked_details;
SELECT DISTINCT
eb.f_name AS first_name,
eb.l_name AS last_name,
eb.phone
FROM
extras_booked_details AS eb
WHERE
item LIKE 'yoga%'
AND
month(date_of_activity) = 08;
-- There are three customers who are going to be very disappointed - Darryl, Deanna
-- and Hayfa.
---------------------------------------------------------------------------------------
-- TASK 7 - QUERIES WITH GROUP BY
-- Prepare an example query with group by and having to demonstrate how to extract data
-- from your DB for analysis.
---------------------------------------------------------------------------------------
-- SCENARIO 1:
-- There has been a leak in cabin 11 so I will need to move all the bookings to another
-- cabin that will sleep the same number of people. Therefore, I want to find a list of
-- cabins that would be suitable.
-- A quick query shows that cabin 11 has a capacity of 4 people:
SELECT capacity FROM cabin_facilities
WHERE cab_id = 11;
SELECT
cd.cab_id,
cd.cabin_name,
cd.capacity,
cd.hot_tub,
cd.lake_view,
cd.forest_view
FROM
cabins_booked_details AS cd
GROUP BY
cd.cab_id
HAVING
cd.capacity >= 4
AND
cab_id <> 11;
-- SCENARIO 2:
-- I want to get an idea of which hot tubs are getting the most use so that I can plan
-- which ones will need maintance first. Therefore I need to find out which are the most
-- popular cabins with hot tubs, i.e. which cabins with hot tubs have the most bookings.
SELECT
cd.cab_id AS cabin_id,
cd.cabin_name,
cd.hot_tub,
COUNT(cd.cab_id)
FROM
cabins_booked_details AS cd
GROUP BY
cd.cab_id
HAVING
hot_tub = 1
ORDER BY
COUNT(cd.cab_id) DESC;
-- SCENARIO 3:
-- The retreat is opening up in July after COVID. I want to see when the first booking
-- is for each cabin.
SELECT DISTINCT
cbd.cab_id AS cabin_id,
cbd.cabin_name ,
cbd.chk_in
FROM
cabins_booked_details AS cbd
GROUP BY
cbd.cab_id
HAVING
month(cbd.chk_in) = 07
ORDER BY
cbd.chk_in;