Bagaimana saya bisa meningkatkan pernyataan SQL saya dengan hasil mingguan dengan minggu dimulai pada hari Kamis atau hari lain dalam seminggu?

8

Saya seorang pemula, dan saya tidak dapat menemukan cara yang baik untuk melakukan ini di mana saja. Saya memiliki tabel database yang berisi statistik yang direkam pada berbagai waktu sepanjang minggu. Minggu pelaporan dimulai pada hari Kamis. Tabel berisi kolom datestamp (tanggal) yang menyimpan ketika data direkam.

Saya perlu menarik data selama satu minggu tertentu (minggu pelaporan dimulai pada Kamis). Saya telah menulis pertanyaan berikut:

   SELECT * 
FROM `table` 
WHERE 1 = CASE 
  WHEN WEEKDAY(NOW()) = 0 THEN DATEDIFF(NOW(),`date`) BETWEEN -2 AND 4
  WHEN WEEKDAY(NOW()) = 1 THEN DATEDIFF(NOW(),`date`) BETWEEN -1 AND 5
  WHEN WEEKDAY(NOW()) = 2 THEN DATEDIFF(NOW(),`date`) BETWEEN -0 AND 6
  WHEN WEEKDAY(NOW()) = 3 THEN DATEDIFF(NOW(),`date`) BETWEEN -6 AND 0
  WHEN WEEKDAY(NOW()) = 4 THEN DATEDIFF(NOW(),`date`) BETWEEN -5 AND 1
  WHEN WEEKDAY(NOW()) = 5 THEN DATEDIFF(NOW(),`date`) BETWEEN -4 AND 2
  WHEN WEEKDAY(NOW()) = 6 THEN DATEDIFF(NOW(),`date`) BETWEEN -3 AND 3
END

Ini tampaknya bekerja pada pengujian awal. Tapi saya tidak yakin itu cara terbaik untuk melakukannya. Saya tidak tahu banyak tentang kinerja MySQL, tetapi akan ada lebih dari seratus ribu catatan untuk disaring. Apakah permintaan ini sangat lambat karena jumlah kondisi yang diperiksa?

Fungsi SEKARANG () digunakan ketika menarik laporan terbaru - namun, itu beberapa kasus saya perlu melakukan laporan untuk minggu lain - jadi saya akan mengganti tanggal lain ke tempat itu.

Selain itu, melakukannya dengan cara ini membutuhkan penulisan ulang kueri jika minggu pelaporan berubah - katakanlah hari awal berubah menjadi Rabu.

Saya tidak dapat menggunakan fungsi MINGGU () karena Anda hanya dapat memulai seminggu di Sun atau Mon dengan itu.

Setiap ide untuk meningkatkan kueri ini sangat dihargai!

Catatan Lain: Saat ini menggunakan MariaDB 5.3.

James Lee Vann
sumber

Jawaban:

5

Berikut ini adalah kueri yang saya tulis untuk memberi Anda hari Kamis terbaru dan hari Rabu yang berakhir

SELECT thuwk_beg + INTERVAL 0 second thu_beg,
thuwk_beg + INTERVAL 604799 second wed_end
FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A;

Berikut adalah contoh untuk hari ini, 2011-09-21

mysql> SELECT
    -> thuwk_beg + INTERVAL 0 second thu_beg,
    -> thuwk_beg + INTERVAL 604799 second wed_end
    -> FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
    -> FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
    -> FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A;
+---------------------+---------------------+
| thu_beg             | wed_end             |
+---------------------+---------------------+
| 2011-09-15 00:00:00 | 2011-09-21 23:59:59 |
+---------------------+---------------------+
1 row in set (0.00 sec)

Cukup ganti panggilan fungsi SEKARANG () dengan datetime apa pun yang Anda suka dan Anda akan memiliki minggu mulai Kamis sepanjang waktu untuk datetime yang Anda pilih.

Berikut adalah contoh lain menggunakan tanggal spesifik '2011-01-01'

mysql> SELECT
    -> thuwk_beg + INTERVAL 0 second thu_beg,
    -> thuwk_beg + INTERVAL 604799 second wed_end
    -> FROM (SELECT (DATE('2011-01-01') - INTERVAL daysbacktothursday DAY) thuwk_beg
    -> FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
    -> FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE('2011-01-01') dt) AAAA) AAA) AA) A;
+---------------------+---------------------+
| thu_beg             | wed_end             |
+---------------------+---------------------+
| 2010-12-30 00:00:00 | 2011-01-05 23:59:59 |
+---------------------+---------------------+
1 row in set (0.00 sec)

Permintaan tablereferensi Anda hari ini akan menyerupai sesuatu seperti ini:

SELECT * from `table`,
(SELECT thuwk_beg + INTERVAL 0 second thu_beg,
thuwk_beg + INTERVAL 604799 second wed_end
FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A) M
WHERE `date` >= thu_beg
AND `date` <= wed_end;

Cobalah !!!

UPDATE 2011-09-22 16:27 EDT

Ini adalah permintaan saya untuk menandai Thu-Wed.

SELECT thuwk_beg + INTERVAL 0 second thu_beg,
thuwk_beg + INTERVAL 604799 second wed_end
FROM (SELECT (DATE(NOW()) - INTERVAL daysbacktothursday DAY) thuwk_beg
FROM (SELECT SUBSTR('3456012',wkndx,1) daysbacktothursday
FROM (SELECT DAYOFWEEK(dt) wkndx FROM (SELECT DATE(NOW()) dt) AAAA) AAA) AA) A;

Bagaimana dengan minggu-minggu lainnya ???

  • (SELECT SUBSTR('6012345',wkndx,1) apakah minggu dimulai Senin berakhir Sun
  • (SELECT SUBSTR('5601234',wkndx,1) Apakah minggu dimulai Sel berakhir Senin
  • (SELECT SUBSTR('4560123',wkndx,1) Apakah minggu mulai Rabu berakhir Sel
  • (SELECT SUBSTR('3456012',wkndx,1) Apakah minggu mulai Kamis mengakhiri Rabu
  • (SELECT SUBSTR('2345601',wkndx,1) Apakah minggu mulai Jumat mengakhiri Kamis
  • (SELECT SUBSTR('1234560',wkndx,1) Apakah minggu mulai Sabtu berakhir Jumat
  • (SELECT SUBSTR('0123456',wkndx,1) Apakah minggu mulai Sun mengakhiri Sat
RolandoMySQLDBA
sumber
1

Biarkan saya nyatakan kembali apa yang Anda minta untuk memastikan saya sudah benar:

Anda ingin menarik semua catatan selama 7 hari terakhir pada tanggal yang ditentukan?

Itu bisa terlihat seperti:

select * from table where `date` between $date - interval 7 day and $date

Penting untuk dicatat bahwa $ date bukan sintaks mysql literal tetapi hanya tempat penampung contoh untuk tanggal mulai yang Anda inginkan. Jika ini untuk pelaporan, saya membayangkan permintaan pada akhirnya akan dihasilkan dari beberapa skrip? Jika itu benar, mungkin lebih sederhana dalam bahasa itu dan kemudian meneruskan nilai literal sebagai bagian dari kueri yang dibuat.

Saya penggemar menjaga pertanyaan sesederhana mungkin jadi saya akan membiarkannya seperti itu. Saya akan memberikan ruang bagi orang lain untuk menyumbangkan jawaban untuk mencapai apa yang Anda inginkan dalam satu query SQL-fu.

Sunting: Setelah membaca ulang kiriman Anda, sepertinya Anda menggunakan jenis tanggal. Dalam hal ini, blok berikut dalam huruf miring mungkin redundan. Saya meninggalkannya di acara ini sangat membantu orang lain (dan karena saya meluangkan waktu untuk menulisnya :-)

Anda bilang Anda menggunakan "datestamp"? Secara teknis itu bukan tipe data Mysql. Apakah ini merupakan waktu, waktu, atau tanggal (waktu dan tahun juga ada tetapi dari konteks Anda, saya merasa itu tidak berlaku)? Saya bertanya karena Anda mungkin ingin menjadikannya hanya kolom tanggal daripada yang lain. Jika ini adalah pilihan yang tepat untuk Anda, Anda benar-benar bergantung pada perincian tentang bagaimana kolom digunakan dan tabel yang dipertanyakan. Jika tujuan satu-satunya adalah hanya untuk menarik catatan dalam rentang tanggal, terlepas dari waktu, maka tanggal pasti cara untuk pergi. Untuk satu, itu hanya diperlukan 3 byte, bukan 4 atau 8. Saya bisa menguraikan alasan lain Anda ingin menggunakan tanggal jika cocok dengan persyaratan penggunaan Anda (yaitu Anda tidak peduli tentang porsi waktu). Anda dapat menemukan detail tentang berbagai jenis di http://dev.mysql.com/doc/refman/5.0/id/datetime.html

http://dev.mysql.com/doc/refman/5.0/id/storage-requirements.html

Jika dan hanya jika Anda menggunakan tanggal secara spesifik, Anda dapat mempertimbangkan hal berikut:

Jalankan kueri dengan diawali dengan "jelaskan". Rincian tentang cara menafsirkan output dan apa yang terbaik dapat ditemukan di http://dev.mysql.com/doc/refman/5.0/id/explain-output.html

Setelah Anda menjelaskan perubahan permintaan menjadi

select * from table where date in ("N", "N+1"..."N+7")

di mana Anda menghitung semua tanggal yang Anda minati. Saya telah menemukan situasi di mana jelas MySQL tidak cukup pintar untuk secara efektif menggunakan kueri rentang (yaitu antara x dan y) ayat yang menyebutkan nilai spesifik untuk set kecil.

Yang mana pun kasus penggunaan Anda ingin memastikan bahwa kolom diindeks jika Anda membuat kueri pelaporan rutin berdasarkan nilainya.

atxdba
sumber
1

Bapak @Rolando jelas menjawab pertanyaan itu tetapi saya akan mengusulkan keputusan lain yang akan memungkinkan Anda untuk memanipulasi dan menyesuaikan kalender antara zona waktu dan kelompok paling penting berdasarkan minggu yang ditentukan dalam zona waktu berbeda

jadi, anggap saja mySQL Anda berjalan di server yang dikonfigurasi UTC dan Anda ingin memiliki kalender khusus yang 7 jam ke depan dan karenanya minggu Anda akan dimulai pada hari Sabtu jam 7 pagi

CREATE TABLE `wh_blur_calendar` (
  `date` timestamp NOT NULL ,
  `y` smallint(6) DEFAULT NULL,
  `q` tinyint(4) DEFAULT NULL,
  `m` tinyint(4) DEFAULT NULL,
  `d` tinyint(4) DEFAULT NULL,
  `w` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `wh_ints` (
  `i` tinyint(4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into wh_ints values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);

sekarang bergabung dengan Cartesian populer yang seharusnya mengisi meja Anda:

INSERT INTO wh_blur_calendar (date)
SELECT DATE('2010-01-01 00:00:00 ') + INTERVAL a.i*10000 + b.i*1000 + c.i*100 + d.i*10 + e.i DAY
FROM wh_ints a JOIN wh_ints b JOIN wh_ints c JOIN wh_ints d JOIN wh_ints e
WHERE (a.i*10000 + b.i*1000 + c.i*100 + d.i*10 + e.i) < 10245
ORDER BY 1;

Mari kita perbarui jam:

update  db_wh_repo.wh_blur_calendar set date = date_add(date, interval 7 hour);

dan akhirnya mengatur minggu kalender Anda dengan cara yang khusus

UPDATE wh_blur_calendar
SET 
    y = YEAR(date),
    q = quarter(date),
    m = MONTH(date),
    d = dayofmonth(date),
    w = week(date_add((date), interval 1 day));

Percayalah, saya menghabiskan beberapa jam untuk membuat keputusan ini, tetapi keputusan ini memberi Anda begitu banyak kebebasan seandainya Anda ingin mengelompokkan hasil Anda berdasarkan zona waktu khusus dan definisi minggu.

ninjabber
sumber