Архив за Сентябрь 2008

День программиста

12 сентября мировое сообщество “программеров”, а вместе с ними и все прогрессивное человечество отмечают День программиста — неофициальный праздник тех, кто посредством написания софта вдыхает “душу” в компьютерное “железо.

День программиста отмечается на 256-й день года. Число 256 (два в восьмой степени) выбрано потому, что это количество чисел, которые можно выразить с помощью одного байта. В високосные годы этот праздник попадает на 12 сентября, в невисокосные — на 13 сентября.

Как в MySQL при наличии некоторых данных изменить их, а при отсутствии - добавить?

Зачастую возникают ситуации, когда нужно при наличии определенной строки в таблице в MySQL изменить ее, а при ее отсутствии - добавить. Обычно решают такую задачу в два приема: сначала проверяют, есть ли данные (SELECT с нужными условиями), а затем в зависимости от полученного результата либо изменяют их (UPDATE), либо добавляют (INSERT).

Конструкция получается достаточно трудоемкая. В этом случае будет эффективнее использовать команду MySQL REPLACE. По синтаксису она эквивалентна INSERT:

REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name [(col_name,...)]
        VALUES (expression,...),(...),...
или REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...
или REPLACE [LOW_PRIORITY | DELAYED]
        [INTO] tbl_name
        SET col_name=expression, col_name=expression,...

Логика работы REPLACE такова: если в существующей строке есть поле, для которого построен индекс типа PRIMARY KEY или UNIQUE, с тем же значением, что и в новой строке, то старая строка удаляется, а новая - добавляется. Если строки с таким значением в указанном поле нет, то строка просто добавляется.

Есть еще вариант с использованием ON DUPLICATE KEY UPDATE:

INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        VALUES (expression,...),(...),...
        [ ON DUPLICATE KEY UPDATE col_name=expression, ... ]
или INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        SELECT ...
или INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name
        SET col_name=(expression | DEFAULT), ...
        [ ON DUPLICATE KEY UPDATE col_name=expression, ... ]

Если вы указываете ON DUPLICATE KEY UPDATE (новшество в MySQL 4.1.0), и производится вставка строки, которая вызывает ошибку дублирующегося первичного (PRIMARY) или уникального (UNIQUE) ключа, то вполняется UPDATE старой строки. Например:

INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1;

Если a определяется как UNIQUE и уже содержит 1, то тогда вышеуказанная команда будет аналогична следующей:

UPDATE table SET c=c+1 WHERE a=1;

Ссылки по теме:

Календарь на PHP

Основная проблема при формировании календаря заключается в том, что месяц, как правило, начинается с середины недели. Сам календарь представляет собой таблицу с количеством строк, равных количеству дней в неделе, и количеством столбцов, равных количеству недель в месяце, поэтому формирование календаря целесообразно проводить сразу в двухмерном массиве.

<?php
  setlocale ( LC_ALL, '' );
  // Название месяца
  echo '<h3>'.strftime( '%B' ).'</h3>';
  // Вычисляем число дней в текущем месяце
  $dayofmonth = date('t');
  // Счётчик для дней месяца
  $day_count = 1;

  // Первая неделя
  $num = 0;
  for( $i = 0; $i < 7; $i++ ) {
    // Вычисляем номер дня недели для числа
    $dayofweek = date('w', mktime(0, 0, 0, date('m'), $day_count, date('Y')));
    // Приводим к числа к формату 1 - понедельник, ..., 6 - суббота
    $dayofweek = $dayofweek - 1;
    if($dayofweek == -1) $dayofweek = 6;

    if($dayofweek == $i) {
      // Если дни недели совпадают, заполняем массив $week числами месяца
      $week[$num][$i] = $day_count;
      $day_count++;
    } else {
      $week[$num][$i] = '';
    }
  }

  // Последующие недели месяца
  while( true ) {
    $num++;
    for( $i = 0; $i < 7; $i++ ) {
      $week[$num][$i] = $day_count;
      $day_count++;
      // Если достигли конца месяца - выходим из цикла
      if( $day_count > $dayofmonth ) break;
    }
    // Если достигли конца месяца - выходим из цикла
    if( $day_count > $dayofmonth ) break;
  }
  // Какой сегодня день
  $today = date( 'j' );
  // Выводим содержимое массива $week в виде календаря
  echo '<table border="1" style="border-collapse:collapse" cellpadding="5" cellspacing="0">';
  for( $j = 0; $j < 7; $j++ ) {
    echo '<tr align="right">';
    for( $i = 0; $i < count($week); $i++ ) {
      if( !empty( $week[$i][$j] ) ) {
        if ( $week[$i][$j] == $today )
          echo '<td bgcolor="#DDDDDD">';
        else
          echo '<td>';
        // Если имеем дело с субботой и воскресеньем - подсвечиваем их
        if( $j == 5 || $j == 6 )
          echo '<span style="color:red">'.$week[$i][$j].'</span>';
        else
          echo $week[$i][$j];
        echo '</td>';
      } else {
        echo '<td>&nbsp;</td>';
      }
    }
    echo '</tr>';
  }
  echo '</table>';
?>

Чтобы изменить формат вывода календаря недель месяца с вертикального на горизонтальный - достаточно внести незначительные изменения в тот фрагмент кода, который отвечает за вывод сформированного массива в виде таблицы:

<?php
  setlocale ( LC_ALL, '' );
  // Название месяца
  echo '<h3>'.strftime( '%B' ).'</h3>';
  // Вычисляем число дней в текущем месяце
  $dayofmonth = date('t');
  // Счётчик для дней месяца
  $day_count = 1;

  // Первая неделя
  $num = 0;
  for( $i = 0; $i < 7; $i++ ) {
    // Вычисляем номер дня недели для числа
    $dayofweek = date('w', mktime(0, 0, 0, date('m'), $day_count, date('Y')));
    // Приводим к числа к формату 1 - понедельник, ..., 6 - суббота
    $dayofweek = $dayofweek - 1;
    if($dayofweek == -1) $dayofweek = 6;

    if($dayofweek == $i) {
      // Если дни недели совпадают, заполняем массив $week числами месяца
      $week[$num][$i] = $day_count;
      $day_count++;
    } else {
      $week[$num][$i] = '';
    }
  }

  // Последующие недели месяца
  while( true ) {
    $num++;
    for( $i = 0; $i < 7; $i++ ) {
      $week[$num][$i] = $day_count;
      $day_count++;
      // Если достигли конца месяца - выходим из цикла
      if( $day_count > $dayofmonth ) break;
    }
    // Если достигли конца месяца - выходим из цикла
    if( $day_count > $dayofmonth ) break;
  }
  // Какой сегодня день
  $today = date( 'j' );
  // Выводим содержимое массива $week в виде календаря
  echo '<table border="1" style="border-collapse:collapse" cellpadding="5" cellspacing="0">';
  for( $i = 0; $i < count($week); $i++ ) {
    echo '<tr align="right">';
    for( $j = 0; $j < 7; $j++ ) {
      if( !empty( $week[$i][$j] ) ) {
        if ( $week[$i][$j] == $today )
          echo '<td bgcolor="#DDDDDD">';
        else
          echo '<td>';
        // Если имеем дело с субботой и воскресеньем - подсвечиваем их
        if( $j == 5 || $j == 6 )
          echo '<span style="color:red">'.$week[$i][$j].'</span>';
        else
          echo $week[$i][$j];
        echo '</td>';
      } else {
        echo '<td>&nbsp;</td>';
      }
    }
    echo '</tr>';
  }
  echo '</table>';
?>