Saya akan menunjukkan ide seperti itu berdasarkan apa yang paling masuk akal bagi saya dan cara saya menjawab jika pertanyaannya sama seperti di sini:
Pertama, mari kita asumsikan kumpulan data seperti itu, kita akan memberi nama tabel logins
:
+---------+---------------------+
| user_id | login_timestamp |
+---------+---------------------+
| 1 | 2015-09-29 14:05:05 |
| 2 | 2015-09-29 14:05:08 |
| 1 | 2015-09-29 14:05:12 |
| 4 | 2015-09-22 14:05:18 |
| ... | ... |
+---------+---------------------+
Mungkin ada kolom lain, tapi kami tidak mempermasalahkannya.
Pertama-tama kita harus menentukan batas minggu itu, untuk itu kita bisa menggunakan ADDDATE()
. Dikombinasikan dengan gagasan bahwa tanggal hari ini-hari ini adalah hari kerja (DAYOFWEEK()
MySQL ), adalah tanggal minggu.
Misalnya:Jika hari ini Rabu tanggal 10, Wed - 3 = Sun
, jadi 10 - 3 = 7
, dan kita dapat mengharapkan hari Minggu menjadi tanggal 7.
Kita bisa mendapatkan WeekStart
dan WeekEnd
stempel waktu seperti ini:
SELECT
DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1-DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") WeekStart,
DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7-DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59") WeekEnd;
Catatan:di PostgreSQL ada DATE_TRUNC()
fungsi yang mengembalikan awal unit waktu tertentu, diberi tanggal, seperti awal minggu, bulan, jam, dan sebagainya. Tapi itu tidak tersedia di MySQL.
Selanjutnya, mari kita gunakan WeekStart dan WeekEnd untuk mengeklik kumpulan data kita, dalam contoh ini saya hanya akan menunjukkan cara memfilter, menggunakan tanggal kode keras:
SELECT *
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'
Ini akan mengembalikan kumpulan data kami yang terpotong, dengan hanya hasil yang relevan:
+---------+---------------------+
| user_id | login_timestamp |
+---------+---------------------+
| 2 | 2015-09-29 14:05:08 |
| 1 | 2015-09-29 14:05:12 |
+---------+---------------------+
Kami kemudian dapat mengurangi set hasil kami menjadi hanya user_id
s, dan menyaring duplikat. lalu hitung, begini:
SELECT COUNT(DISTINCT user_id)
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'
DISTINCT
akan menyaring duplikat, dan count hanya akan mengembalikan jumlahnya.
Jika digabungkan menjadi:
SELECT COUNT(DISTINCT user_id)
FROM `logins`
WHERE login_timestamp
BETWEEN DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00")
AND DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59")
Ganti CURDATE()
dengan stempel waktu apa pun untuk mendapatkan jumlah login pengguna minggu itu.
Tapi saya perlu memecah ini menjadi beberapa hari, saya mendengar Anda menangis. Tentu saja! dan begini caranya:
Pertama, mari kita terjemahkan stempel waktu kita yang terlalu informatif menjadi hanya data tanggal. Kami menambahkan DISTINCT
karena kami tidak keberatan pengguna yang sama masuk dua kali pada hari yang sama. kami menghitung pengguna, bukan login, bukan? (perhatikan kita mundur ke sini):
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d")
FROM `logins`
Ini menghasilkan:
+---------+-----------------+
| user_id | login_timestamp |
+---------+-----------------+
| 1 | 2015-09-29 |
| 2 | 2015-09-29 |
| 4 | 2015-09-22 |
| ... | ... |
+---------+-----------------+
Kueri ini, akan kami bungkus dengan satu detik, untuk menghitung kemunculan setiap tanggal:
SELECT `login_timestamp`, count(*) AS 'count'
FROM (SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d") AS `login_timestamp` FROM `logins`) `loginsMod`
GROUP BY `login_timestamp`
Kami menggunakan hitungan dan pengelompokan untuk mendapatkan daftar berdasarkan tanggal, yang mengembalikan:
+-----------------+-------+
| login_timestamp | count |
+-----------------+-------+
| 2015-09-29 | 1 +
| 2015-09-22 | 2 +
+-----------------+-------+
Dan setelah semua kerja keras, keduanya digabungkan:
SELECT `login_timestamp`, COUNT(*)
FROM (
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d") AS `login_timestamp`
FROM `logins`
WHERE login_timestamp BETWEEN DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") AND DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59")) `loginsMod`
GROUP BY `login_timestamp`;
Akan memberi Anda rincian login harian per hari dalam minggu ini. Sekali lagi, ganti CURDATE()
untuk mendapatkan minggu yang berbeda.
Adapun pengguna sendiri yang masuk, mari gabungkan hal yang sama dalam urutan yang berbeda:
SELECT `user_id`
FROM (
SELECT `user_id`, COUNT(*) AS `login_count`
FROM (
SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`) `logins`
GROUP BY `user_id`) `logincounts`
WHERE `login_count` > 6
Saya memiliki dua pertanyaan dalam, yang pertama adalah logins
:
SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`
Akan memberikan daftar pengguna, dan hari-hari ketika mereka masuk, tanpa duplikat.
Kemudian kita memiliki logincounts
:
SELECT `user_id`, COUNT(*) AS `login_count`
FROM `logins` -- See previous subquery.
GROUP BY `user_id`) `logincounts`
Akan mengembalikan daftar yang sama, dengan hitungan berapa banyak login yang dimiliki setiap pengguna.
Dan terakhir:PILIH user_id
DARI logincounts
-- Lihat subquery sebelumnya.WHERE login_count
> 6
Filter kami yang tidak login 7 kali, dan hapus kolom tanggal.
Ini agak panjang, tapi saya pikir ini penuh dengan ide dan saya pikir itu pasti membantu menjawab dengan cara yang menarik dalam wawancara kerja. :)