Drupal数据库API查询 - 如果存在则为row.update,否则为row.insert

时间:2011-04-28 21:36:33

标签: mysql drupal upsert

我一直在尝试在drupal中运行一个查询,如果它们已经存在则会更新条目,如果没有,则插入一个新条目。代码现在看起来像这样:

db_query("IF EXISTS (SELECT %d FROM {uc_posten_packages.pid})
UPDATE {uc_posten_packages} SET title = '%s', label = '%s', cost = '%d', length = '%d', width ='%d', height = '%d', weight = '%d'  WHERE pid = %d
ELSE
INSERT INTO {uc_posten_packages} VALUES ('%d', '%s', '%s', '%d', '%d', '%d', '%d', '%d')",$id, $title, $label, $rate, $length, $width, $height, $weight, $id, $id, $title, $label, $rate, $length, $width, $height, $weight);

我看不出为什么该查询会抛出错误。错误中的所有数字都是正确的

...near 'IF EXISTS (SELECT 1 FROM uc_posten_packages.pid) UPDATE uc_posten_packages ' at line 1 query:
IF EXISTS (SELECT 1 FROM uc_posten_packages.pid) UPDATE uc_posten_packages SET title = 'vfbv', label = 'bbv', cost = '22', length = '232', width ='22', height = '22', weight = '22' WHERE pid = 1 ELSE INSERT INTO uc_posten_packages VALUES ('1', 'vfbv', 'bbv', '22', '232', '22', '22', '22')

这个查询是否有效和/或是否有更好的方法在drupal中处理这个问题?

4 个答案:

答案 0 :(得分:6)

你正在寻找的是被称为“upsert”(更新否则插入),并且有一个drupal函数:db_merge。好在这里写一下:http://drupal.org/node/310085

drupal_write_record()不会自动执行“upsert”。它总是根据您传入的内容插入或更新,但不能同时插入或更新。

答案 1 :(得分:4)

[2013年1月更新]

这个答案指的是Drupal的旧版本,而不是当前的稳定版本。请通过添加这样的更新部分以及更多最新信息来编辑此答案,因为我不再使用Drupal或继续其API更改。

-semperos

[/ 2013年1月更新]

您有几个选项,即drupal_write_record或运行示例查询并测试结果。这不应该在您的问题中的单个SQL查询中完成。

drupal_write_record(首选方法)

函数drupal_write_record允许您指定要处理的表以及包含该表的每个列/字段的数据的对象(或关联数组)。如果您已经拥有要更新的行的主键,则将其作为函数的第三个参数包含在内,drupal_write_record将自动使用SQL UPDATE命令。否则,默认为INSERT。例如:

drupal_write_record('uc_posten_packages', array('title'  => "Foobar",
                                      'label'  => "foobar",
                                      'cost'   => 10,
                                      'length' => 100,));

这将INSERT包含该信息的新记录。如果您包含了array($pid)的第三个参数,其中$pid是充当表的主键的字段的名称,则它将执行更新。

此函数仅在您使用hook_schema定义的表时才有效,对于任何具有数据库表的正确开发的Drupal模块都应如此。由于此函数使用模式来确保正确地写入数据库,因此应尽可能使用此函数(或者当不存在其他更具体的函数时,例如node_save用于节点对象)。

测试查询

您可以使用db_result(db_query("SELECT..."))运行示例查询。如果没有找到结果,它将返回一个空字符串,在PHP中计算结果为false,因此您的代码可能如下所示:

if (db_result(db_query("SELECT * FROM {uc_posten_packages} WHERE pid = %d", $pid))) {
  // UPDATE
} else {
  // INSERT
}

答案 2 :(得分:1)

根据drupal_write_record,操作是UPDATEINSERT,您需要知道在提交交易之前是否存在记录。这不是drupal_write_record()所做的。此函数只检查它的参数并相应地发出更新或插入。所以真的没办法来判断该函数是INSERT还是UPDATE

解决方案是使用db_merge()查询,它是一个相对较新的SQL ANSI标准,完全符合我的需要(在MySQL的情况下,它在原子事务中执行)。

$return_value = db_merge('mytable')
            ->key(array('id' => $key))
            ->fields($fields)
            ->updateFields(array(
                'updatedon' => $now,
            ))
            ->execute();

返回值是一个整数,对于插入返回1,对于更新返回2。

答案 3 :(得分:0)

这是替换语法的一个愚蠢的例子。

mysql> create table test (
    -> id int,
    -> a int,
    -> b int,
    -> unique (id)
    -> ) engine = myisam;
Query OK, 0 rows affected (0.01 sec)

mysql> replace into test (id,a,b) values (1,4,2);
Query OK, 1 row affected (0.00 sec)

mysql> replace into test (id,a,b) values (2,10,3);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+------+------+------+
| id   | a    | b    |
+------+------+------+
|    1 |    4 |    2 |
|    2 |   10 |    3 |
+------+------+------+
2 rows in set (0.00 sec)

mysql> replace into test (id,a,b) values (1,5,5);
Query OK, 2 rows affected (0.00 sec)

mysql> select * from test;
+------+------+------+
| id   | a    | b    |
+------+------+------+
|    1 |    5 |    5 |
|    2 |   10 |    3 |
+------+------+------+
2 rows in set (0.00 sec)

希望它可以帮助你。