-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxt_ai_rand.sql
More file actions
2059 lines (1780 loc) · 79 KB
/
Copy pathxt_ai_rand.sql
File metadata and controls
2059 lines (1780 loc) · 79 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
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
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
-- AI generated random SQL exercises for me to practice
"""
1. Here's an exercise that combines JOIN and SELECT to simulate a real-world cybersecurity scenario:
Scenario: You have two tables, Users and Logins, that store user information and login activity respectively.
You need to detect any suspicious login attempts by identifying users who have logged in from different
countries within a short period of time.
Table Structures:
Users table:
- id (INT)
- username (VARCHAR)
- email (VARCHAR)
Logins table:
- id (INT)
- user_id (INT)
- login_time (DATETIME)
- country_code (VARCHAR)
SQL Exercise:
1. Create and populate the Users and Logins tables with sample data.
2. Write a SQL query that joins the Users and Logins tables and selects users who have logged in
from different countries within a specific time frame (e.g., 1 hour).
"""
-- First attempt
SELECT u.id, u.username, l.login_time, l.country_code
FROM users u
JOIN logins l ON u.id = l.user_id
JOIN logins l2 ON l.id = l2.id
WHERE l.id != l2.id
AND
-- Second attempt
SELECT u.id, u.username, u.email, l1.country_code as country1, l2.country_code as country2
FROM users u
JOIN logins l1 ON u.id = l1.user_id
JOIN logins l2 ON u.id = l2.user_id
WHERE l1.login_time BETWEEN DATE_SUB(l2.login_time, INTERVAL 1 HOUR) AND l2.login_time -- To subtract 1 hour from the l2.login_time
AND l1.country_code != l2.country_code;
""" Official Solution
SELECT u.id, u.username, u.email, l1.country_code as country_code1, l2.country_code as country_code2
FROM Users u
JOIN Logins l1 ON u.id = l1.user_id
JOIN Logins l2 ON u.id = l2.user_id
WHERE l1.id != l2.id
AND l1.login_time BETWEEN DATE_SUB(l2.login_time, INTERVAL 1 HOUR) AND l2.login_time
AND l1.country_code != l2.country_code
"""
"""
Scenario:
You are an Analyst at a social media company. You have access to a database with the following tables:
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR)
Exercise:
Write SQL queries to answer the following questions:
1. Identify users who have had more than 5 reports against their content in the last month:
- Show user_id, and the number of reports.
"""
-- First Attempt
SELECT reporting_user_id, COUNT(report_id) AS number_of_reports
FROM content_reports
WHERE report_date >= NOW() - INTERVAL 1 MONTH
GROUP BY reporting_user_id
HAVING number_of_reports > 5;
-- Second Attempt
SELECT a.user_id, COUNT(b.report_id) AS number_of_reports
FROM users a JOIN content_reports b ON a.user_id = b.reporting_user_id
JOIN content c ON b.content_id = c.content_id
WHERE report_date >= NOW() - INTERVAL 1 MONTH
GROUP BY a.user_id
HAVING number_of_reports > 5;
"""
2. Calculate the average time it takes to resolve a content report (i.e., go from 'Pending' to 'Reviewed', 'Actioned', or 'Dismissed'):
- Show the report_type and the average resolution time in days.
"""
-- First Attempt
SELECT report_type,
AVG(DATEDIFF(day, report_date, action_date)) AS avg_resolution_time_resolve
FROM content_report a
JOIN user_account_action b ON a.reporting_user_id = b.user_id
WHERE a.status IN ('Reviewed', 'Actioned', 'Dismissed')
GROUP BY report_type;
-- Second Attempt
SELECT report_type, AVG(DATEDIFF(DAY, report_date, report_date_status)) AS avg_resolution_time
FROM content_reports
WHERE status IN ('Reviewed', 'Actioned', 'Dismissed')
GROUP BY report_type;
"""
3. Find users who were suspended more than once for 'Hate Speech':
- Show user_id and the number of suspensions.
"""
-- First Attempt
SELECT a.user_id, COUNT(a.action_type) AS number_of_suspensions
FROM user_account_actions a
JOIN content_reports b ON a.user_id = b.reporting_user_id
WHERE a.action_type = 'Suspension'
AND b.report_type = 'Hate Speech'
GROUP BY a.user_id
HAVING number_suspensions > 1;
-- Second Attempt
SELECT user_id, COUNT(action_type) AS number_of_suspensions
FROM user_account_actions
WHERE action_type = 'Suspension'
AND reason = 'Hate Speech'
GROUP BY user_id
HAVING number_of_suspensions > 1;
"""
4. Analyze the trend of 'Spam' reports over the last quarter:
- Show the date (grouped by week) and the number of 'Spam' reports.
"""
-- First Attempt
SELECT report_date, COUNT(report_type) AS number_of_reports
FROM content_reports
WHERE report_type = 'Spam' AND report_date >= NOW() - INTERVAL 3 MONTH
GROUP BY report_date = INTERVAL 1 WEEK;
-- Second Attempt
SELECT DATE_TRUNC('week', report_date) AS week_start_date, -- Show the date (grouped by week)
COUNT(report_type) AS number_of_spam_reports
FROM content_reports
WHERE report_type = 'Spam' AND report_date >= NOW() - INTERVAL 3 MONTH
GROUP BY DATE_TRUNC('week', report_date) -- To group the reports by the beginning of the week. This is the standard way to group by week
ORDER BY week_start_date;
"""
5. Identify accounts created in the last year which are currently suspended and have had at least one content report marked as 'Actioned':
- Show the user_id, account_creation_date, and the number of 'Actioned' reports.
"""
-- First Attempt
SELECT a.user_id, a.account_creation_date, COUNT(b.status) AS number_of_actioned_reports
FROM users a JOIN content_reports b ON a.user_id = b.reporting_user_id
WHERE a.account_status = 'Suspended'
AND a.account_creation_date >= NOW() - INTERVAL 1 YEAR
AND b.status = 'Actioned'
GROUP BY a.user_id;
-- Second Attempt
SELECT a.user_id, a.account_creation_date, COUNT(c.content_id) AS number_of_reports
FROM users a
JOIN content_reports b ON a.user_id = b.reporting_user_id
JOIN content c ON b.content_id = c.content_id
WHERE a.account_status = 'Suspended'
AND a.account_creation_date >= NOW() - INTERVAL 1 YEAR
AND b.status = 'Actioned'
GROUP BY a.user_id, b.account_creation_date;
"""
Bonus Question:
6.Write a query that identifies users who have both reported abusive content and had actions taken against their accounts. This could help identify potential patterns of retaliatory reporting or users who are both victims and perpetrators of abuse.
- Show the user_id and the number of reports they made and the number of actions taken against their accounts.
"""
-- First Attempt
SELECT a.user_id, COUNT(b.report_id) AS number_of_reports, COUNT(c.action_id) AS number_of_actions_taken
FROM users a
LEFT JOIN content_reports b ON a.user_id = b.reporting_user_id
LEFT JOIN user_account_actions c ON a.user_id = c.user_id
WHERE b.reporting_user_id = c.user_id
GROUP BY a.user_id;
-- Second Attempt
SELECT a.user_id,
COUNT(DISTINCT b.report_id) AS number_of_reports,
COUNT(DISTINCT c.action_id) AS action_against
FROM users a
LEFT JOIN content_reports b ON a.user_id = b.reporting_user_id -- Join to get reports made by the user
LEFT JOIN user_account_actions c ON a.user_id = c.user_id -- Join to get actions agaiinst the user
WHERE b.report_id IS NOT NULL OR c.action_type IS NOT NULL
GROUP BY a.user_id;
"""
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
"""
Here's one exercise for you:
Exercise:
Based on the database schema provided, write a SQL query to identify users who have had more than 5 reports against their content in the last month.
Show the user_id and the number of reports.
"""
-- First Attempt
SELECT a.user_id, COUNT(b.report_id) AS number_reports
FROM users a
JOIN content b ON a.user_id = b.user_id
JOIN content_reports c ON b.content_id = c.content_id
WHERE b.report_date >= NOW() - INTERVAL 1 MONTH
GROUP BY a.user_id
HAVING number_reports > 5;
"""
Write a SQL query to find users who were suspended more than once for 'Hate Speech'.
Show the user_id and the number of suspensions.
"""
-- First attempt
SELECT a.user_id, COUNT(c.action_type) AS num_susp
FROM users a
JOIN content_reports b ON a.user_id = b.reporting_user_id
JOIN user_account_action c ON a.user_id = c.user_id
WHERE b.report_type = 'Hate Speech'
AND c.action_type = 'Suspension'
GROUP BY a.user_id
HAVING num_susp > 1;
-- Second attempt
SELECT user_id, COUNT(action_type) AS num_sus
FROM user_account_action
WHERE action_type = 'Suspension' AND reason = 'Hate Speech'
GROUP BY user_id
HAVING num_sus >1;
"""
Write a SQL query to analyze the trend of 'Spam' reports over the last quarter.
Show the date (grouped by week) and the number of 'Spam' reports for each week.
"""
-- First Attempt
SELECT DATE_TRUNC('week', report_date) AS week_start date, COUNT(report_type) AS rep_spam_week
FROM content_reports
WHERE report_type = 'Spam'
AND report_date >= NOW() - INTERVAL 3 MONTH
GROUP BY week_start_date
ORDER BY week_start_date;
"""
Write a SQL query to identify accounts created in the last year which are currently suspended and have had at least one content report marked as 'Actioned'.
Show the user_id, account_creation_date, and the number of 'Actioned' reports for each user.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First Attempt
SELECT user_id, account_creation_date, COUNT(c.status) AS num_report
FROM users a
JOIN content b ON a.user_id = b.user_id
JOIN content_reports c ON b.content_id = c.content_id
WHERE a.account_status = 'Suspended'
AND c.status = 'Actioned'
AND a.account_creation_date >= NOW() - INTERVAL 1 YEAR
GROUP BY a.user_id
HAVING num_report > 1;
-- Sample Solution
SELECT
a.user_id,
a.account_creation_date,
COUNT(c.status) AS num_reports
FROM
users a
JOIN
content b ON a.user_id = b.user_id
JOIN
content_reports c ON b.content_id = c.content_id
WHERE
a.account_status = 'Suspended'
AND c.status = 'Actioned'
AND a.account_creation_date >= NOW() - INTERVAL 1 YEAR
GROUP BY
a.user_id, a.account_creation_date -- Include account_creation_date in GROUP BY
HAVING
num_reports >= 1; -- Changed to >= 1 to include those with 1 or more Actioned reports
"""
Write a SQL query to identify users who have both reported abusive content and had actions taken against their accounts.
Show the user_id and the number of reports they made, and the number of actions taken against their accounts.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First Attempt
SELECT a.user_id, COUNT(b.report_id) AS num_rep, COUNT(c.action_id) AS num_act
FROM users a
LEFT JOIN content_reports b ON a.user_id = b.reporting_user_id
LEFT JOIN user_account_actions c ON a.user_id = c.user_id
WHERE b.report_type IS NOT NULL
OR c.action_type IS NOT NULL
GROUP BY a.user_id;
-- Sample solution
SELECT
u.user_id,
COUNT(DISTINCT cr.report_id) AS reports_made,
COUNT(DISTINCT uaa.action_id) AS actions_taken
FROM
users u
LEFT JOIN
content_reports cr ON u.user_id = cr.reporting_user_id
LEFT JOIN
user_account_actions uaa ON u.user_id = uaa.user_id
WHERE cr.report_id IS NOT NULL AND uaa.action_id IS NOT NULL
GROUP BY
u.user_id;
"""
Write a SQL query to identify the top 5 countries with the highest number of users who have had actions taken against their accounts.
Show the country and the number of users with actions taken.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First Attempt
SELECT a.country, COUNT(DISTINCT b.user_id) AS num_acc_act
FROM users a
LEFT JOIN user_account_actions b ON a.user_id = b.user_id
WHERE b.action_id IS NOT NULL
GROUP BY a.country
ORDER BY num_acc_act DESC
LIMIT 5;
"""
Write a SQL query to find the top 3 most common reasons for user account suspensions.
Show the reason and the number of suspensions for each reason.
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT reason, COUNT(action_type) AS num_susp
FROM user_account_actions
WHERE action_type = 'Suspension'
GROUP BY reason
ORDER BY num_susp DESC
LIMIT 3;
"""
Write a SQL query to find the weekly number of new user account creations for the past quarter.
Show the week starting date and the number of new accounts created in that week.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
"""
SELECT DATE_TRUNC('week', account_creation_date) AS week_start_date, COUNT(user_id) AS new_acc
FROM users
WHERE account_creation_date >= NOW() - INTERVAL 3 MONTH
GROUP BY week_start_date
ORDER BY new_acc DESC;
"""
Write a SQL query to identify the users who have the highest number of reports made by them.
Show the user ID and the number of reports made.
Limit the results to the top 10 users.
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT reporting_user_id, COUNT(report_id) AS num_rep
FROM content_reports
GROUP BY reporting_user_id
ORDER BY num_rep DESC
LIMIT 10;
"""
Write a SQL query to find the content that has received the most reports. Show the content_id and the number of reports for each content item, and limit the results to the top 10.
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT a.content_id, COUNT(report_id) AS num_repo
FROM content a
JOIN content_reports b ON a.content_id = b.content_id
GROUP BY a.content_id
ORDER BY num_repo DESC
LIMIT 10;
"""
Write a SQL query to identify users who have been reported for 'Harassment' at least once, but have not yet had any account actions (e.g., Suspension, Warning, Account Closure) taken against them.
Show the user_id, account_creation_date, and the number of 'Harassment' reports they've received.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT a.user_id, a.account_creation_date, COUNT(c.report_type) AS num_report
FROM users a
JOIN content b ON a.user_id = b.user_id
JOIN content_reports c ON b.content_id = c.content_id
LEFT JOIN user_account_actions d ON a.user_id = d.user_id
WHERE c.report_type = 'Harassment' AND d.action_type IS NULL
GROUP BY a.user_id, a.account_creation_date
ORDER BY a.user_id, a.account_creation_date
HAVING num_report >=1;
"""
Write a SQL query to identify the top 5 users who have made the most reports of 'Hate Speech'.
Show their user_id and the total number of 'Hate Speech' reports they have submitted.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT a.user_id, COUNT(c.report_type) AS num_rep
FROM users a
JOIN content b ON a.user_id = b.user_id
JOIN content_reports c ON a.user_id = c.reporting_user_id
WHERE c.report_type = 'Hate Speech'
GROUP by a.user_id
ORDER BY num_rep DESC
LIMIT 5;
"""
Write a SQL query to calculate the percentage of users who have had their account status changed to 'Suspended' within 30 days of their account creation.
Show the total number of users created in the last year, and the percentage of those users who were suspended within 30 days of creation.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First attempt (Incorrect)
SELECT COUNT(user_id) AS num_year, ((SELECT COUNT(user_id) AS acc_susp
FROM users
WHERE account_creation_date >= NOW() - INTERVAL 30 DAY
AND account_status = 'Suspended'
GROUP BY acc_sus)/100)*10 AS pct_acc_sup
FROM users
WHERE account_creation_date >= NOW() - INTERVAL 1 YEAR
GROUP BY num_year;
-- ***Corrected query **Sample Solution** ----
SELECT
-- Total users created in the last year
(SELECT COUNT(user_id) FROM users WHERE account_creation_date >= NOW() - INTERVAL 1 YEAR) AS total_users_last_year,
-- Percentage calculation
(CAST(COUNT(DISTINCT u.user_id) AS DECIMAL) * 100.0 /
(SELECT COUNT(user_id) FROM users WHERE account_creation_date >= NOW() - INTERVAL 1 YEAR)) AS percentage_suspended
FROM
users u
JOIN
user_account_actions uaa ON u.user_id = uaa.user_id
WHERE
u.account_creation_date >= NOW() - INTERVAL 1 YEAR -- Account created in the last year
AND uaa.action_type = 'Suspension' -- Account was a suspension
AND uaa.action_date <= u.account_creation_date + INTERVAL 30 DAY -- Suspension within the first 30 days after creation
AND uaa.action_date >= u.account_creation_date; -- Ensure that the action date is not before acccount creation date
-- Another attempts
"""
Write a SQL query to calculate the percentage of users who have had their account status changed to 'Suspended' within 30 days of their account creation.
Show the total number of users created in the last year, and the percentage of those users who were suspended within 30 days of creation.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT (SELECT COUNT(user_id) FROM users WHERE account_creation_date >= NOW() - INTERVAL 1 YEAR) AS acc_created_year,
(CAST(COUNT(DISTINCT b.user_id) AS DECIMAL)*100 /
(SELECT COUNT(user_id) FROM users WHERE account_creation_date >= NOW() - INTERVAL 1 YEAR)) AS prct_susp
FROM users a
JOIN user_account_actions b ON a.user_id = b.user_id
WHERE
a.account_creation_date >= NOW() - INTERVAL 1 YEAR
AND b.action_type = 'Suspension'
AND b.action_date <= a.account_creation_date + INTERVAL 30 DAY
AND b.action_date >= a.account_creation_date;
"""
Write a SQL query to identify users who received a 'Warning' action, and then later received a more severe action ('Suspension' or 'Account Closure').
Show the user_id, the action_date of their initial 'Warning', and the action_date of their subsequent 'Suspension' or 'Account Closure'. Ensure that the severe action occurred after the warning.
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First attempt
SELECT user_id,
action_date,
(SELECT action_date FROM user_account_actions WHERE action_type = 'Warning' ) AS after_warning
FROM user_account_ations
WHERE after_warning <
(SELECT action_date
FROM user_account_actions
WHERE action_type IN ('Suspension', 'Account Closure'));
-- Sample Solution
SELECT DISTINCT
w.user_id,
w.action_date AS warning_date,
sa.action_date AS severe_action_date
FROM
user_account_actions w -- Alias for the 'Warning' actions
JOIN
user_account_actions sa ON w.user_id = sa.user_id -- Join to find severe actions for the *same* user
WHERE
w.action_type = 'Warning' -- Filter for the initial warning
AND sa.action_type IN ('Suspension', 'Account Closure') -- Filter for the subsequent severe action
AND sa.action_date > w.action_date; -- Ensure the severe action happened *after* the warning
-- Another attempt
"""
Write a SQL query to identify users who received a 'Warning' action, and then later received a more severe action ('Suspension' or 'Account Closure').
Show the user_id, the action_date of their initial 'Warning', and the action_date of their subsequent 'Suspension' or 'Account Closure'. Ensure that the severe action occurred after the warning.
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT a.user_id, a.action_date, b.action_date
FROM user_account_actions a
JOIN user_account_actions b ON a.user_id = b.user_id
WHERE a.action_type = 'Warning'
AND b.action_type IN ('Suspension', 'Account Closure')
AND a.action_date < b.action_date;
"""
Write a SQL query to identify users who reported content that was later determined to be not abusive (i.e., the content_report's status was set to 'Dismissed').
Show the user_id of the reporting user and the report_id of the dismissed report.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First attempt(Incorrect)
SELECT a.reporting_user_id, b.report_id
FROM content_reports a
JOIN content_reports b ON a.report_id = b.report_id
WHERE a.report_date < b.report_date
AND a.status IN ('Pending', 'Reviewed', 'Actioned')
AND b.status = 'Dimissed';
-- Sample solution
SELECT
reporting_user_id,
report_id
FROM
content_reports
WHERE
status = 'Dismissed';
-- Another attempt (27-05-2025)
"""
Write a SQL query to identify users who reported content that was later determined to be not abusive (i.e., the content_report's status was set to 'Dismissed').
Show the user_id of the reporting user and the report_id of the dismissed report.
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT reporting_user_id, report_id
FROM content_reports
WHERE status = 'Dismissed';
"""
Write a SQL query to identify the top 3 content_type that have received the highest number of total reports.
Show the content_type and the total count of reports for each.
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT a.content_type, COUNT(b.report_id) AS num_rep
FROM content a
JOIN content_reports b ON a.content_id = b.content_id
GROUP BY a.content_type
ORDER BY num_rep DESC
LIMIT 3;
"""
Write a SQL query to find the user_id of accounts that were created in the last 6 months and have a current account_status of 'Active', but have no associated content reports (of any type) submitted against them within the last 3 months.
Show the user_id and their account_creation_date.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First attempt(Incorrect)
SELECT a.user_id, a.account_creation_date
FROM users a
JOIN user_account_actions b ON a.user_id = b.user_id
WHERE a.account_creation_date = NOW() - INTERVAL 6 MONTH
AND a.account_status = 'Active'
AND b.action_id IS NULL
AND b.action_date < NOW() - INTERVAL 3 MONTH
AND a.action_creation_date < b.action_date;
-- Sample Solution
SELECT
u.user_id,
u.account_creation_date
FROM
users u
LEFT JOIN
content c ON u.user_id = c.user_id -- Link users to their content
LEFT JOIN
content_reports cr ON c.content_id = cr.content_id
AND cr.report_date >= NOW() - INTERVAL 3 MONTH -- Only consider reports within the last 3 months for the join
WHERE
u.account_creation_date >= NOW() - INTERVAL 6 MONTH -- Accounts created in the last 6 months
AND u.account_status = 'Active' -- Account is currently active
AND cr.report_id IS NULL; -- No reports found for this user's content within the last 3 months
-- Another attempt
SELECT a.user_id, a.account_creation_date
FROM users a
LEFT JOIN content b ON a.user_id = b.user_id
LEFT JOIN content_reports c ON b.content_id = c.content_id
AND c.report_date >= NOW() - INTERVAL 3 MONTH
WHERE a.account_creation_date >= NOW() - INTERVAL 6 MONTH
AND a.account_status = 'Active'
AND c.report_id IS NULL;
"""
Write a SQL query to identify users who have submitted at least one content report, but have never had any account actions (e.g., 'Suspension', 'Warning', 'Account Closure') taken against their own account.
Show the user_id and the total number of reports they have made.
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
TABLE: user_account_actions: Contains records of actions taken against user accounts.
action_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
action_type (VARCHAR, e.g., 'Suspension', 'Warning', 'Account Closure')
action_date (DATE)
reason (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
SELECT a.user_id, COUNT(b.report_id) AS num_report
FROM users a
LEFT JOIN content_reports b ON a.user_id = b.reporting_user_id
LEFT JOIN user_account_actions c ON a.user_id = c.user_id
WHERE c.action_type IS NULL
GROUP BY a.user_id
ORDER BY num_report
HAVING num_report >= 1;
"""
2025-05-31
Exercise:
Write a SQL query to calculate the average number of content reports submitted by users who have submitted at least one report.
The result should be a single numerical value (the average).
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)
status (VARCHAR, e.g., 'Pending', 'Reviewed', 'Actioned', 'Dismissed')
"""
-- First Attempt (INCORRECT)
SELECT AVG(COUNT(content_id))
FROM content_reports
HAVING COUNT(content_id) >=1;
-- Sample Solution
SELECT
AVG(reports_made) AS average_reports_per_active_reporter
FROM (
SELECT
reporting_user_id,
COUNT(report_id) AS reports_made
FROM
content_reports
GROUP BY
reporting_user_id
HAVING
COUNT(report_id) >= 1 -- Ensures we only consider users who submitted at least one report
) AS subquery_user_reports;
-- Second Attempt
SELECT AVG(num_report) AS avg_num_rep_users
FROM (SELECT reporting_user_id, COUNT(report_id) AS num_report
FROM content_reports
GROUP BY reporting_user_id
HAVING num_report >=1
) AS num_user_report;
"""
TABLE: users: Contains user information.
user_id (INT, Primary Key)
account_creation_date (DATE)
country (VARCHAR)
account_status (VARCHAR, e.g., 'Active', 'Suspended', 'Closed')
TABLE: content
content_id (INT, Primary Key)
user_id (INT, Foreign Key referencing users.user_id)
content_type (VARCHAR, e.g., 'Video', 'Post', 'Comment')
creation_date (DATE)
TABLE: content_reports: Contains reports of potentially abusive content.
report_id (INT, Primary Key)
content_id (INT, Foreign Key referencing a content table - not included here for simplicity)
reporting_user_id (INT, Foreign Key referencing users.user_id, users who made the report)
report_type (VARCHAR, e.g., 'Harassment', 'Hate Speech', 'Spam')
report_date (DATE)
report_status_date (DATE)