-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.sql
More file actions
188 lines (153 loc) · 4.85 KB
/
script.sql
File metadata and controls
188 lines (153 loc) · 4.85 KB
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
-- Delete tables if they exist
DROP
TABLE IF EXISTS Completions;
DROP
TABLE IF EXISTS Players;
DROP
TABLE IF EXISTS Levels;
-- Create tables
CREATE TABLE Players (
PlayerId INT,
Name VARCHAR(50)
);
CREATE TABLE Levels (
LevelId INT,
LevelName VARCHAR(50)
);
CREATE TABLE Completions (PlayerId INT, LevelId INT);
-- Insert 7 players
INSERT INTO Players
VALUES
(1, 'Alex'),
(2, 'Beth'),
(3, 'Carl'),
(4, 'Diana'),
(5, 'Erik'),
(6, 'Fiona'),
(7, 'Greg');
-- Insert 3 levels
INSERT INTO Levels
VALUES
(1, 'Forest'),
(2, 'Cave'),
(3, 'Castle');
-- Insert completions: 3 players complete all levels, 4 players with different
patterns INSERT INTO Completions
VALUES
-- Alex, Beth, Carl: Completed all 3 levels
(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(3, 2),
(3, 3),
-- Diana: Only completed Forest
(4, 1),
-- Erik: Completed Forest and Cave
(5, 1),
(5, 2),
-- Fiona: Only completed Castle
(6, 3),
-- Greg: Completed Forest and Castle
(7, 1),
(7, 3);
SELECT PlayerId FROM Completions WHERE LevelId = 1 -- Forest completers
UNION
SELECT PlayerId FROM Completions WHERE LevelId = 2; -- Cave completers
-- Note: Fiona (6) is excluded - Only completed Castle (Level=3)
SELECT p.PlayerId, p.Name, l.LevelId, l.LevelName
FROM Players p CROSS JOIN Levels l
ORDER BY p.PlayerId, l.LevelId;
-- Result: 7 players × 3 levels = 21 total combinations
-- Shows every player paired with every level (whether completed or not)
SELECT PlayerId FROM Completions WHERE LevelId = 1 -- Forest completers
INTERSECT
SELECT PlayerId FROM Completions WHERE LevelId = 2; -- Cave completers
-- Excluded players:
-- Diana (4): Only completed Forest (Level=1)
-- Fiona (6): Only completed Castle (Level=3)
-- Greg (7): Completed Forest and Castle (Levels=1,3)
SELECT PlayerId FROM Completions WHERE LevelId = 1 -- Forest completers
EXCEPT
SELECT PlayerId FROM Completions WHERE LevelId = 2; -- Cave completers
-- Excluded players:
-- Alex (1), Beth (2), Carl (3), Erik (5) have completed Level=2
-- Fiona (6) has not completed Level=1
SELECT PlayerId
FROM Completions
WHERE LevelId = 1
AND PlayerId NOT IN (
SELECT PlayerId FROM Completions WHERE LevelId = 2
);
SELECT c1.PlayerId
FROM (SELECT DISTINCT PlayerId FROM Completions WHERE LevelId = 1) c1
LEFT JOIN (SELECT DISTINCT PlayerId FROM Completions WHERE LevelId = 2) c2
ON c1.PlayerId = c2.PlayerId
WHERE c2.PlayerId IS NULL;
-- This filters for players who exist in Forest (c1) but have NO match in Cave (c2)
-- LEFT JOIN keeps all c1 records, setting c2 fields to NULL when no match exists
SELECT DISTINCT PlayerId
FROM Completions c1
WHERE c1.LevelId = 1 -- Forest completers
AND NOT EXISTS (
SELECT 1 -- The existence of a row matters not the value of it
FROM Completions c2
WHERE c2.PlayerId = c1.PlayerId
AND c2.LevelId = 2 -- Cave completers
);
-- Find players where there does NOT exist a level that they did NOT complete.
SELECT p.PlayerId, p.Name
FROM Players p
WHERE NOT EXISTS ( -- does NOT exist a level
SELECT 1 -- The existence of a row matters not the value of it
FROM Levels l
WHERE NOT EXISTS ( -- did NOT complete
SELECT 1
FROM Completions c
WHERE c.PlayerId = p.PlayerId
AND c.LevelId = l.LevelId
)
);
-- If we add 'Difficulty' column in our Level table, then we can address:
-- Find players who completed ALL HARD levels
SELECT p.PlayerId, p.Name
FROM Players p
WHERE NOT EXISTS ( -- First NOT EXISTS can filter levels
SELECT 1
FROM Levels l
WHERE l.Difficulty = 'HARD' -- CONDITION IN FIRST NOT EXISTS
AND NOT EXISTS ( -- Second NOT EXISTS checks completion
SELECT 1
FROM Completions c
WHERE c.PlayerId = p.PlayerId
AND c.LevelId = l.LevelId
)
);
SELECT p.PlayerId, p.Name
FROM Players p
JOIN Completions c ON p.PlayerId = c.PlayerId
JOIN Levels l ON c.LevelId = l.LevelId
GROUP BY p.PlayerId, p.Name
HAVING COUNT(DISTINCT c.LevelId) = (SELECT COUNT(*) FROM Levels);
-- Why DISTINCT matters: If completions table had duplicates
-- (player completed same level twice), we'd still count correctly
SELECT p.PlayerId, p.Name
FROM Players p
WHERE NOT EXISTS ( -- Empty Set
SELECT LevelId FROM Levels -- All Levels
EXCEPT
SELECT LevelId FROM Completions c WHERE c.PlayerId = p.PlayerId -- Their Completions
);
SELECT PlayerId, Name
FROM Players
WHERE PlayerId IN (
SELECT c.PlayerId
FROM Completions c
WHERE c.LevelId IN (SELECT LevelId FROM Levels) -- Filter valid levels
GROUP BY c.PlayerId -- Group by player
HAVING COUNT(DISTINCT c.LevelId) = (SELECT COUNT(*) FROM Levels) -- Count = total
);
-- DISTINCT is crucial - prevents counting duplicate completions