简体   繁体   English

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

[英]Drupal database API query - row.update if exists, else row.insert

I've been trying to run a query in drupal that'll update entries if they already exists or insert a new entry if it doesnt.我一直在尝试在 drupal 中运行一个查询,如果它们已经存在则更新条目,如果不存在则插入一个新条目。 The code looks like this at the moment:代码现在看起来像这样:

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

I can't see why that query throws me an error.我不明白为什么该查询会引发错误。 All the numbers in the error are correct错误中的所有数字都是正确的

...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')

Should this query work and/or is there some better way dealing with this in drupal?这个查询是否应该工作和/或在 drupal 中是否有更好的方法来处理这个问题?

What you're looking for is cordially called an "upsert" (update otherwise insert), and there is a drupal function for just this: db_merge.您正在寻找的是亲切地称为“upsert”(否则更新插入),并且有一个 drupal function 就是这个:db_merge。 Good write-up here: http://drupal.org/node/310085在这里写得很好: http://drupal.org/node/310085

drupal_write_record() does not automatically perform an "upsert." drupal_write_record() 不会自动执行“upsert”。 It always either inserts or updates based on what you pass in only, but not both.它总是根据您传入的内容进行插入或更新,但不能同时进行。

[UPDATE Jan 2013] [2013 年 1 月更新]

This answer refers to an older version of Drupal than the current stable release.此答案指的是 Drupal 的旧版本,而不是当前稳定版本。 Please edit this answer by adding an update section like this with more up-to-date information, as I no longer work with Drupal or keep up with its API changes.请通过添加这样的更新部分来编辑此答案,其中包含更多最新信息,因为我不再使用 Drupal 或跟上其 API 更改。

-semperos -森佩罗斯

[/UPDATE Jan 2013] [/2013 年 1 月更新]

You have a couple of options, namely drupal_write_record or running a sample query and testing for results.您有几个选项,即drupal_write_record或运行示例查询并测试结果。 This shouldn't be done in a single SQL query as in your question.这不应该像您的问题那样在单个 SQL 查询中完成。

drupal_write_record (Preferred Method) drupal_write_record(首选方法)

The function drupal_write_record allows you to specify the table you want to deal with and an object (or associate array) which contains data for each column/field of that table. function drupal_write_record允许您指定要处理的表和包含该表的每个列/字段的数据的 object(或关联数组)。 If you already have the primary key for the row you're trying to update, then you include it as a third parameter to the function, and drupal_write_record will automatically use the SQL UPDATE command.如果您已经拥有要更新的行的主键,则将其作为第三个参数包含在 function 中, drupal_write_record将自动使用 SQL UPDATE命令。 Otherwise, it defaults to INSERT .否则,它默认为INSERT For example:例如:

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

This will INSERT a new record with that information.这将使用该信息INSERT一条新记录。 If you had included a third argument of array($pid) where $pid was the name of the field that acts as primary key for the table, it would have performed an update instead.如果您包含了array($pid)的第三个参数,其中$pid是充当表的主键的字段的名称,那么它将执行更新。

This function will only work if the table you're dealing with was defined using hook_schema , which should be true of any properly developed Drupal module that has database tables.这个 function 仅在您正在处理的表是使用hook_schema定义的情况下才有效,这对于任何正确开发的具有数据库表的 Drupal 模块都应该是正确的。 Since this function uses the schema to ensure it's writing to the database correctly, you should use this function when possible (or when no other more specific functions exist, eg node_save for node objects).由于此 function 使用架构来确保其正确写入数据库,因此您应该尽可能使用此 function(或者当不存在其他更具体的功能时,例如node_save用于节点对象)。

Test Query测试查询

You can just run a sample query using db_result(db_query("SELECT...")) .您可以使用db_result(db_query("SELECT..."))运行示例查询。 It returns an empty string if no results are found, which evaluates to false in PHP, so your code could look like:如果没有找到结果,它会返回一个空字符串,在 PHP 中计算结果为 false,因此您的代码可能如下所示:

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

According to drupal_write_record the operation was an UPDATE or an INSERT you need to know whether the record existed or not before committing the transaction.根据drupal_write_record操作是UPDATEINSERT您需要在提交事务之前知道记录是否存在。 This is not what drupal_write_record() does.这不是 drupal_write_record() 所做的。 This function just checks it's arguments and issues an update or an insert accordingly.这个 function 只是检查它的 arguments 并相应地发出更新或插入。 So there is really no way to tell if the function did an INSERT or an UPDATE .所以真的没有办法判断 function 是否执行了INSERTUPDATE

The solution is using db_merge() query, it is a relatively new SQL ANSI standard that does exactly what I needed (and in the case of MySQL does it in an atomic transaction).解决方案是使用db_merge()查询,它是一个相对较新的 SQL ANSI 标准,它完全符合我的需要(在 MySQL 的情况下,它是在原子事务中完成的)。

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

The return value is an integer returning 1 for inserts and 2 for updates.返回值是 integer,返回 1 表示插入,2 表示更新。

This is a silly example of replace syntax.这是替换语法的一个愚蠢示例。

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)

Hope it could help you.希望它可以帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM