-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path5.2.sql
186 lines (177 loc) · 4.5 KB
/
5.2.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
/* Top 3 animals of each species with the largest number of checkups, including species with less than 3 animals */
-- Number of checkups per animal
SELECT species,
name,
COUNT (*) AS number_of_checkups
FROM routine_checkups
GROUP BY species,
name
ORDER BY species,
number_of_checkups DESC;
-- Reference.species table
SELECT *
FROM reference.species;
-- Include species with no checkups (or no animals for that matter...)
SELECT s.species,
rc.name,
COUNT (rc.checkup_time) AS number_of_checkups
-- Can't use * in order to return 0 for species with no checkups
FROM reference.species AS s
LEFT OUTER JOIN -- Include species with no checkups...
routine_checkups AS rc
ON s.species = rc.species
GROUP BY s.species,
rc.name
ORDER BY s.species,
number_of_checkups DESC;
-- Subquery solution
WITH animal_checkups
AS
(
SELECT s.species,
rc.name, -- For species with no checkups
COUNT (checkup_time) AS number_of_checkups
FROM reference.species AS s
LEFT OUTER JOIN
routine_checkups AS rc
ON s.species = rc.species
GROUP BY s.species,
rc.name
)
-- SELECT * FROM animal_checkups ORDER BY species, number_of_checkups DESC;
, add_count_of_more_checked_animalss
AS
(
SELECT *,
( SELECT COUNT (*)
FROM animal_checkups AS ac2
WHERE ac2.species = ac1.species
AND
ac2.number_of_checkups > ac1.number_of_checkups
) AS number_of_more_checked_animals
FROM animal_checkups AS ac1
)
-- SELECT * FROM add_count_of_more_checked_animalss ORDER BY species, number_of_checkups DESC;
SELECT species,
name,
number_of_checkups
FROM add_count_of_more_checked_animalss
WHERE number_of_more_checked_animals < 3
ORDER BY species,
number_of_checkups DESC;
-- Corrected for ties
WITH animal_checkups
AS
(
SELECT s.species,
rc.name, -- For species with no checkups
COUNT (checkup_time) AS number_of_checkups
FROM reference.species AS s
LEFT OUTER JOIN
routine_checkups AS rc
ON s.species = rc.species
GROUP BY s.species,
rc.name
)
-- SELECT * FROM animal_checkups ORDER BY species, number_of_checkups DESC;
, add_count_of_more_checked_animalss
AS
(
SELECT *,
( SELECT COUNT (*)
FROM animal_checkups AS ac2
WHERE ac2.species = ac1.species
AND
(
ac2.number_of_checkups > ac1.number_of_checkups
OR
(
ac2.number_of_checkups = ac1.number_of_checkups -- Tie breaker
AND
ac2.name < ac1.name -- Unique per species, guarantees no ties
)
)
) AS number_of_more_checked_animals
FROM animal_checkups AS ac1
)
-- SELECT * FROM add_count_of_more_checked_animalss ORDER BY species, number_of_checkups DESC;
SELECT species,
name,
number_of_checkups
FROM add_count_of_more_checked_animalss
WHERE number_of_more_checked_animals < 3
ORDER BY species,
number_of_checkups DESC;
-- Solution with ROW_NUMBER
WITH animal_checkups
AS
(
SELECT s.species,
rc.name, -- For species with no checkups
COUNT (checkup_time) AS number_of_checkups
FROM reference.species AS s
LEFT OUTER JOIN
routine_checkups AS rc
ON s.species = rc.species
GROUP BY s.species,
rc.name
)
, include_row_number_by_number_of_chekcups
AS
(
SELECT *,
ROW_NUMBER ()
OVER ( PARTITION BY Species
ORDER BY number_of_checkups DESC,
name
) AS row_number
FROM animal_checkups
)
-- SELECT * FROM include_row_number_by_number_of_chekcups ORDER BY species, number_of_checkups DESC;
SELECT species,
name,
number_of_checkups
FROM include_row_number_by_number_of_chekcups
WHERE row_number <= 3
ORDER BY species,
number_of_checkups DESC;
/* Performance wise,
Subquery: cost = 60654..60655
Window function: cost = 143..186
*/
-- NTILE
SELECT species,
name,
admission_date,
NTILE (10)
OVER (ORDER BY admission_date) AS ten_segments,
NTILE (30)
OVER (ORDER BY admission_date) AS thirty_segments,
NTILE (30)
OVER (PARTITION BY Species
ORDER BY admission_date) AS thirty_segments_per_species
FROM Animals
ORDER BY species,
admission_date;
--------------------------
-- Alternative solution --
--------------------------
SELECT s.species,
animal_checkups.name,
COALESCE (animal_checkups.number_of_checkups, 0) AS number_of_checkups
FROM reference.species AS s
LEFT OUTER JOIN LATERAL
(
SELECT rc.species,
rc.name,
COUNT (*) AS number_of_checkups
FROM routine_checkups AS rc
WHERE s.species = rc.species
GROUP BY rc.species,
rc.name
ORDER BY rc.species,
number_of_checkups DESC,
name
LIMIT 3 OFFSET 0
) AS animal_checkups
ON TRUE;