使用 DEFAULT 值准备 MySQL INSERT/UPDATE 语句
Posted
技术标签:
【中文标题】使用 DEFAULT 值准备 MySQL INSERT/UPDATE 语句【英文标题】:Preparing a MySQL INSERT/UPDATE statement with DEFAULT values 【发布时间】:2011-01-28 16:52:16 【问题描述】:引用 mysql INSERT 手册 - 更新也是如此:
使用关键字 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
,则采取相应的行动。
我很确定有更好的方法来做到这一点。有没有其他人遇到过类似的情况?
【问题讨论】:
由于 PDO 将您的值作为要输入的字符串处理,如果可能的话,您可能需要稍微更改代码。您可能会更改它以便输入...execute(array('\'value1\'', 'DEFAULT'))
,但我猜 PDO 正在使用 mysql_real_escape_string()
等为您处理这些值。这会破坏该功能。您可能只需将其直接插入到 prepare()
参数中。
为什么不在INSERT
语句中包含您设置为默认值以外的值的列?
问题在于UPDATE
和一个空的提交输入。我需要将其设为默认值,例如 ''
设置为新值时的日期字段不是 0000-00-00
。
【参考方案1】:
尝试改变这个:
$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)
【讨论】:
谁会想要其他值,但无论如何都是默认值。【参考方案2】:我知道的唯一“解决方法”是使用 Coalesce() 和 Default(fieldname)
例如
$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
【讨论】:
Default(x) 可以是DEFAULT,如果要在同一列中为该列设置默认值,则无需提及列名。它容易出错。更新 t SET x = 默认值; 好主意!不完美,但胜过我的解决方案! @Frank:当用作 Coalesce() 的参数时,它必须是 Default(fieldname)。 遗憾的是,如果未在每列上设置默认值,它会给出General error: 1364 Field 'column1' doesn't have a default value
您当然只能在具有默认值的字段上使用Coalesce(val, default(x))
-thingy。你不能把它扔在那里... anywhere ;-) 但这只有在你的脚本在运行时构建/组装那些(任意)语句时才重要,然后你仍然可以使用 TABLE_INFORMATION_SCHEMA 来找出一个字段是否有默认值。【参考方案3】:
我尝试回复 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,并且不会触发“列没有默认值”错误。
当然你可以修改为不需要数据库参数
【讨论】:
我认为它不会在性能方面保持优势。 AFAIK mysql 不会缓存函数的结果,因此您将为插入查询中的每一行和每一列调用查询。事先通过 PHP 获取默认值要好得多,但正如我已经得出的结论,我在这里学到的教训是根本不要指望默认的 mysql 值。我仍然会给你一个 +1 的努力。 根据文档,DETERMINISTIC 关键字告诉 mysql 该函数始终返回具有相同参数的相同值,因此我相信它会缓存结果。但是我没有广泛品尝它,我在一个小型的内网中使用它,速度没有任何明显的下降。【参考方案4】:我认为它正在编写字符串'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);
【讨论】:
$pdoParam = FALSE;
应该实现什么?默认为PARAM_STR
。以上是关于使用 DEFAULT 值准备 MySQL INSERT/UPDATE 语句的主要内容,如果未能解决你的问题,请参考以下文章
我可以在 MySQL 中使用具有多个值的 DEFAULT 约束吗?我可以在下面的示例中添加更多默认值吗? [关闭]
_mysql_exceptions 错误(1064,“检查与您的 MySQL 服务器版本相对应的手册,以获取在 'default 附近使用的正确语法)值