Подготовка инструкции MySQL INSERT/UPDATE с значениями DEFAULT

Цитата: Руководство MySQL INSERT - то же самое для UPDATE:

Используйте ключевое слово DEFAULT, чтобы явно указать значение столбца по умолчанию. Это упрощает запись инструкций INSERT, которые присваивают значения всем, кроме нескольких столбцов, потому что это позволяет избежать записи неполного списка VALUES, который не включает значение для каждого столбца в таблице. В противном случае вам нужно будет записать список имен столбцов, соответствующих каждому значению в списке VALUES.

Короче, если я пишу

INSERT INTO table1 (column1,column2) values ('value1',DEFAULT);

Вставляется новая строка с столбцом2, установленная как значение по умолчанию - независимо от того, что она может быть.

Однако, если я готовлю и выполняю инструкцию в PHP:

$statement = $pdoObject->
    prepare("INSERT INTO table1 (column1,column2) values (?,?)");
$statement->execute(array('value1','DEFAULT'));

Новая строка будет содержать "DEFAULT" в качестве ее текстового значения - если столбец способен сохранять текстовые значения.

Теперь я написал слой абстракции для PDO (мне это нужно) и обойти эту проблему, рассматривая возможность введения

const DEFAULT_VALUE = "randomstring";

Итак, я мог бы выполнять такие заявления:

$statement->execute(array('value1',mysql::DEFAULT_VALUE));

И затем в методе, который выполняет привязку, я бы прошел через значения, которые отправляются для привязки, и если некоторые из них равны self::DEFAULT_VALUE, действуйте соответственно.

Я уверен, что есть лучший способ сделать это. Кто-то еще сталкивался с подобными ситуациями?

Ответы

Ответ 1

Единственным "обходным решением", которое я знаю для этого, является использование Coalesce() и По умолчанию (имя_поля)

например.

$pdo = new PDO("mysql:host=localhost;dbname=test", 'localonly', 'localonly'); 
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$pdo->exec("
  CREATE TEMPORARY TABLE foo (
    id int auto_increment,
    x int NOT NULL DEFAULT 99,
    y DATETIME NOT NULL DEFAULT '2010-03-17 01:00:00',
    z varchar(64) NOT NULL DEFAULT 'abc',
    primary key(id)
  )
");


$stmt = $pdo->prepare('
  INSERT INTO
    foo
    (x,y,z)
  VALUES
    (
      Coalesce(:x, Default(x)),
      Coalesce(:y, Default(y)),
      Coalesce(:z, Default(z))
    )
');
$stmt->bindParam(':x', $x);
$stmt->bindParam(':y', $y);
$stmt->bindParam(':z', $z);


$testdata = array(
  array(null, null, null),
  array(1, null, 'lalala'),
  array(null, '2009-12-24 18:00:00', null)
);
foreach($testdata as $row) {
  list($x,$y,$z) = $row;
  $stmt->execute();
}
unset($stmt);
foreach( $pdo->query('SELECT id,x,y,z FROM foo', PDO::FETCH_NUM) as $row) {
  echo join(', ', $row), "\n";
}

печатает

1, 99, 2010-03-17 01:00:00, abc
2, 1, 2010-03-17 01:00:00, lalala
3, 99, 2009-12-24 18:00:00, abc

Ответ 2

Я попытался ответить на ответ VolkerK, но не смог найти.:( Я новичок во всем этом.

Во всяком случае, я создал функцию mysql для использования в сочетании с его идеей COALESCE

CREATE FUNCTION NULLDEFAULT(colname VARCHAR(64), tablename VARCHAR(64), dbname VARCHAR(64)) RETURNS longtext DETERMINISTIC READS SQL DATA
BEGIN
    DECLARE retval longtext;
    SELECT
        COLUMN_DEFAULT INTO retval 
    FROM
        information_schema.COLUMNS
    WHERE
        TABLE_NAME = tablename
    AND
        COLUMN_NAME = colname
    AND
        TABLE_SCHEMA = dbname;

    RETURN retval;
END

Вы бы использовали его следующим образом:

$stmt = $pdo->prepare("
  INSERT INTO
    foo
    (x,y,z)
  VALUES
    (
      Coalesce(:x, NULLDEFAULT('x', 'foo', 'database')),
      Coalesce(:y, NULLDEFAULT('y', 'foo', 'database')),
      Coalesce(:z, NULLDEFAULT('z', 'foo', 'database'))
    )
");

Это вернет null, если столбец не имеет значения по умолчанию, и не будет запускать "Столбец не имеет значения по умолчанию".

Конечно, вы можете изменить его, чтобы не требовать параметр базы данных

Ответ 3

Попробуйте изменить это:

$statement = $pdoObject->
    prepare("INSERT INTO table1 (column1,column2) values (?,?)");
$statement->execute(array('value1','DEFAULT'));

Для этого:

$statement = $pdoObject->
    prepare("INSERT INTO table1 (column1,column2) values (?,DEFAULT)");
$statement->execute(array('value1'));

Мне кажется, что ваш исходный код даст вам следующее:

INSERT INTO table1 (column1,column2) values ('value1','DEFAULT')

Мой код должен предоставить вам следующее:

INSERT INTO table1 (column1,column2) values ('value1',DEFAULT)

Ответ 4

Я думаю, что он пишет String 'DEFAULT', потому что он экранирован pdo, поэтому есть параметры для bindvalue, где вы можете указать тип заданного значения, чтобы вы могли отправить нуль без кавычек, и это будет PDO:: PARAM_NULL; а затем будут введены значения по умолчанию, но я не уверен, есть ли аналогичные параметры при связывании с execute

  if(is_int($param)){$pdoParam = PDO::PARAM_INT;}
      elseif(is_bool($param)){$pdoParam = PDO::PARAM_BOOL;}
      elseif(is_null($param)){ $pdoParam = PDO::PARAM_NULL;}
      elseif(is_string($param)){$pdoParam = PDO::PARAM_STR;}
                                    else{$pdoParam = FALSE;}
              $this->_query->bindValue($k,$param,$pdoParam);