Календарь из MySQL

Календарь из MySQL

Наткнулась как-то в сообществе ru_perl на календарь на текущий месяц, выводимый одним SQL запросом. Очень понравилось, хочу поделиться (:

Тут я приведу выкладки из самого поста, надеюсь, копирайты указывать не надо. Ну и добавлю краткие сведения об операторах и функциях.

Сначала навыбираем циферок с запасом:

SELECT n, n +7, n +14, n +21, n +28, n +35 
FROM ( 
SELECT 1 AS n
UNION ALL SELECT 2 
UNION ALL SELECT 3 
UNION ALL SELECT 4 
UNION ALL SELECT 5 
UNION ALL SELECT 6 
UNION ALL SELECT 7 
) AS t;

+---+-----+------+------+------+------+
| n | n+7 | n+14 | n+21 | n+28 | n+35 |
+---+-----+------+------+------+------+
| 1 |   8 |   15 |   22 |   29 |   36 |
| 2 |   9 |   16 |   23 |   30 |   37 |
| 3 |  10 |   17 |   24 |   31 |   38 |
| 4 |  11 |   18 |   25 |   32 |   39 |
| 5 |  12 |   19 |   26 |   33 |   40 |
| 6 |  13 |   20 |   27 |   34 |   41 |
| 7 |  14 |   21 |   28 |   35 |   42 |
+---+-----+------+------+------+------+

Оператор UNION используется для объединения работы нескольких SELECTов. Имя или псевдоним колонки, запрошенный в первом SELECT используется потом для выводимого результата. Типы данных в каждом из запросов должны совпадать, в противном случае в зависимости от версии масика либо подбирается больший, либо обрезаются остальные. ALL означает, что будут выбраны все записи, а не только уникальные. В нашем запросе это не обязательно.
Также тут используется именование подзапроса (as t) после FROM. Это обязательно, т.к. все таблицы во FROM-клаузе должны быть поименованы. У меня этот кусок запроса временами глючил на локально установленном масике (через phpmyadmin), выдавая #1146 - Table 'mysql.t' doesn't exist.
Вернемся к календарю. Ограничим число дней в последнем столбце. Для этого нам надо знать число дней в месяце SELECT DAYOFMONTH(LAST_DAY(NOW())).
NOW выдает сегодняшнюю дату, LAST_DAY возвращает последнее число месяца для заданной даты в виде YYYY-MM-DD, DAYOFMONTH дает номер дня в месяце.

SELECT n, n+7, n+14, n+21, 
CASE WHEN n+28 > ld.maxn THEN NULL ELSE n +28 END AS 'n+28', 
CASE WHEN n+35 > ld.maxn THEN NULL ELSE n +35 END AS 'n+35' 
FROM (
SELECT 1 AS n
UNION ALL SELECT 2 
UNION ALL SELECT 3 
UNION ALL SELECT 4 
UNION ALL SELECT 5 
UNION ALL SELECT 6 
UNION ALL SELECT 7 
) AS t, 
( SELECT DAYOFMONTH(LAST_DAY(NOW( ))) AS maxn ) AS ld;

+---+-----+------+------+------+------+
| n | n+7 | n+14 | n+21 | n+28 | n+35 |
+---+-----+------+------+------+------+
| 1 |   8 |   15 |   22 | NULL | NULL |
| 2 |   9 |   16 |   23 | NULL | NULL |
| 3 |  10 |   17 |   24 | NULL | NULL |
| 4 |  11 |   18 |   25 | NULL | NULL |
| 5 |  12 |   19 |   26 | NULL | NULL |
| 6 |  13 |   20 |   27 | NULL | NULL |
| 7 |  14 |   21 |   28 | NULL | NULL |
+---+-----+------+------+------+------+

Осталось нашаманить, чтобы месяц не всегда начинался с понедельника. Вот так мы узнаем день недели первого дня, с учетом буржуазного обычая функции DAYOFWEEK начинать неделю с воскресенья:

SELECT CASE WHEN DAYOFWEEK( DATE_FORMAT( NOW( ) , '%Y-%m-01' ) ) =1 THEN 7 
ELSE DAYOFWEEK( DATE_FORMAT( NOW( ) , '%Y-%m-01' ) )-1 END AS fn;

Собираем вместе:

SELECT CASE WHEN n-fn >0 THEN n-fn ELSE NULL END AS week1, 
n+7-fn AS week2, n+14-fn AS week3, n+21-fn AS week4, 
CASE WHEN n-fn+28 > ld.maxn THEN NULL ELSE n-fn+28 END AS week5, 
CASE WHEN n-fn+35 > ld.maxn THEN NULL ELSE n-fn+35 END AS week6
FROM (
SELECT 1 AS n
UNION ALL SELECT 2 
UNION ALL SELECT 3 
UNION ALL SELECT 4 
UNION ALL SELECT 5 
UNION ALL SELECT 6 
UNION ALL SELECT 7 
) AS t, 
( SELECT DAYOFMONTH(LAST_DAY(NOW( ))) AS maxn ) AS ld, 
( SELECT CASE WHEN DAYOFWEEK( DATE_FORMAT( NOW( ) , '%Y-%m-01' ) )=1 THEN 6 
ELSE DAYOFWEEK( DATE_FORMAT( NOW( ), '%Y-%m-01' ) )-2 END AS fn ) AS fd;

И получаем желанный результат:

+-------+-------+-------+-------+-------+-------+
| week1 | week2 | week3 | week4 | week5 | week6 |
+-------+-------+-------+-------+-------+-------+
|  NULL |     2 |     9 |    16 |   23  |  NULL |
|  NULL |     3 |    10 |    17 |   24  |  NULL |
|  NULL |     4 |    11 |    18 |   25  |  NULL |
|  NULL |     5 |    12 |    19 |   26  |  NULL |
|  NULL |     6 |    13 |    20 |   27  |  NULL |
|  NULL |     7 |    14 |    21 |   28  |  NULL |
|  1    |     8 |    15 |    22 |  NULL |  NULL |
+-------+-------+-------+-------+-------+-------+

Теги: 

Добавить комментарий

Filtered HTML

  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешённые HTML-теги: <a> <em> <i> <strong> <b> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <br>
  • Строки и параграфы переносятся автоматически.

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.
CAPTCHA
CAPTCHA на основе изображений
Введите код с картинки