使用DEFAULT值准备MySQL INSERT / UPDATE语句

时间:2010-03-17 17:44:39

标签: php mysql pdo prepared-statement default-value

引用MySQL INSERT手册 - 同样适用于UPDATE:

  

使用关键字DEFAULT将列显式设置为其默认值。这使得编写INSERT语句更容易,这些语句将值分配给除了几列之外的所有列,因为它使您能够避免编写不包含表中每列的值的不完整VALUES列表。否则,您必须写出与VALUES列表中每个值对应的列名列表。

所以,简而言之,如果我写

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

插入了将column2设置为其默认值的新行 - 无论它是什么 -

但是,如果我在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,则相应地执行操作。

我很确定有更好的方法可以做到这一点。有其他人遇到类似情况吗?

4 个答案:

答案 0 :(得分:8)

我知道的唯一“解决方法”是使用Coalesce()Default(fieldname)

E.g。

$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

答案 1 :(得分:1)

我试过回答VolkerK的答案,但无法找到答案。 :(我对这一切都不熟悉。

无论如何,我创建了一个与他的COALESCE想法结合使用的mysql函数

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,并且不会触发“Column has no default value”错误。

当然,您可以将其修改为不需要数据库参数

答案 2 :(得分:0)

尝试更改此内容:

$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)

答案 3 :(得分:0)

我认为它正在写字符串'DEFAULT'因为它被pdo转义所以有bindvalue的参数,你可以指定给定值的类型,这样你就可以发送没有引号的null,它将是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);