【问题标题】:UPDATE/INSERT based on if a row exists根据行是否存在更新/插入
【发布时间】:2012-07-19 11:00:34
【问题描述】:

处理一些 postgreSQL 查询。正如我在上一个问题中所说..我对 SQL 逻辑的了解非常有限..

我有这个插入一行的查询。

$timestamp = date('Y-m-d G:i:s.u');
$check_time = "start"; //can also be stop
$check_type = "start_user"; //can also be stop_user

$insert_query = "INSERT INTO production_order_process_log (
production_order_id, 
production_order_process_id, 
$check_time, 
$check_type) 
    VALUES (
'$production_order_id', 
'$production_order_process_id', 
'$timestamp', 
'$user')
";

不幸的是,每次都添加一个新行。我想添加条件 SQL 以便

如果 production_order_process_id 不存在,请按照上面查询中的说明执行 INSERT。也就是说,添加包含所有新信息的新行

但如果production_order_process_id 确实存在并且check_typestop_user,则更新行以用$timestamp 填充列stop 并用$user 填充列stop_user

我知道这很复杂。或者,至少对我来说是^^非常感谢您的帮助!

【问题讨论】:

标签: php sql postgresql


【解决方案1】:

这通常称为MERGE 或 upsert。 PostgreSQL 没有明确支持此操作。

我在 PostgreSQL 中看到的关于MERGE 主题的最佳文章是this one by depesz

【讨论】:

  • 为什么合并比使用条件逻辑测试字段是否为NULL更好?谢谢!
  • 所以如果starti 是NULL,我将$timestamp 放入其中,但如果它有值,我将其放入stop...
  • @thomas 并发,基本上。想想你正在检查的记录的并发更改会做什么。如果你小心的话,你可以使用SELECT ... FOR UPDATE if 来避免这种情况,但它并非在所有情况下都有效。
【解决方案2】:

在插入类型 ON DUPLICATE KEY UPDATE 之后...

【讨论】:

  • 是的,但不要忘记为要用作键的列提供 INDEX 或 UNIQUE INDEX
【解决方案3】:

使用MERGE 声明

这里是用法

MERGE INTO table [[AS] alias]
USING [table-ref | query]
ON join-condition
[WHEN MATCHED [AND condition] THEN MergeUpdate | DELETE]
[WHEN NOT MATCHED [AND condition] THEN MergeInsert]

MergeUpdate is
UPDATE SET { column = { expression | DEFAULT } |
          ( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) }
[, ...]
(yes, there is no WHERE clause here)

MergeInsert is
INSERT [ ( column [, ...] ) ]
    { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] )
[, ...]}
(no subquery allowed)

如果您搜索它,我相信您会找到更多文章/示例。

【讨论】:

    【解决方案4】:

    如果您可以创建一个存储过程并在插入新记录时调用。

        DELIMITER $$
    
        DROP PROCEDURE IF EXISTS `DB`.`InsertNewRow` $$
        CREATE PROCEDURE `db`.`InsertNewRow` ()
        BEGIN
    
        DECLARE V_EXIST INT DEFAULT 0;
        DECLARE   V_check_type VARCHAR(20);
    
    
        SELECT production_order_process_id,check_type INTO V_EXIST,V_check_type FROM production_order_process_log;
    
        IF V_EXIST=0 THEN
    
          INSERT INTO production_order_process_log (
          production_order_id,
          production_order_process_id,
          $check_time,
          $check_type)
            VALUES (
          '$production_order_id',
          '$production_order_process_id',
          '$timestamp',
          '$user');
    
        ELSEIF V_check_type='stop_user' THEN
    
    
          /* UPDATE QUERY HERE */
    
        END IF;
        END $$
    
        DELIMITER ;         
    

    【讨论】:

    • 不幸的是,存储过程将不得不等到我可以将此数据库迁移到 mySQL 或 msSQL 之类的东西中。本周早些时候让我的服务器技术人员尝试安装 postgresql PDO 软件包导致了一些相当大的问题。我知道它们包含在 PHP for mySQL 中。虽然 postgre 已经为我工作了很长时间,但我已经等不及要使用 mySQL了!
    【解决方案5】:

    只需在插入内容中添加 WHERE CLAUSE:

    INSERT INTO production_order_process_log   
               (  production_order_id, production_order_process_id, check_time, check_type)
        VALUES ( '$production_order_id', '$production_order_process_id', '$timestamp', '$user')
    WHERE NOT EXISTS ( SELECT *
            FROM production_order_process_log nx
            --
            --  assuming production_order_id is the Primary Key, here
            --
            WHERE nx.production_order_id = '$production_order_id'
            );
    

    更新:我对参数和 VALUE() 感到困惑。下面的片段在没有参数的情况下工作,但是 立即值:

    INSERT INTO tmp.production_order_process_log
               (  production_order_id, production_order_process_id, check_time, check_type)
        SELECT 1, 2, '2012-07-19 12:12:12', 'Lutser'
    WHERE NOT EXISTS ( SELECT *
            FROM tmp.production_order_process_log nx
            --
            --  assuming production_order_id is the Primary Key, here
            --
            WHERE nx.production_order_id = 1
            );
    

    (您必须稍作更改才能重新添加参数)

    【讨论】:

    • 我很抱歉,但这只是有点在我的脑海里。 production_order_id 是生产订单的主键。 nx是什么?抱歉,如果真的是基本的混乱>
    • nx 是子查询的相关名称(又名别名)。子查询测试是否存在一行(对于 production_order_id=1)并返回 True 或 False。是的:这真的很基本。并且:postgres 支持这种语法。 (我测试过了!)
    • 如果再次添加参数(对不起,我不懂PHP),不要忘记将文字'1'替换为$1;也在子查询中。
    猜你喜欢
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 2017-04-27
    • 1970-01-01
    • 2014-05-05
    相关资源
    最近更新 更多