› MySQL 5.5 Community Server
› MySQL 5.6 Community Server
› Percona Configuration Wizard
› XtraBackup 搭建主从复制
Great Sites on MySQL
› Percona
› MySQL Performance Blog
› Severalnines
推荐管理工具
› Sequel Pro
› phpMyAdmin
推荐书目
› MySQL Cookbook
MySQL 相关项目
› MariaDB
› Drizzle
参考文档
› http://mysql-python.sourceforge.net/MySQLdb.html
billgreen1
V2EX  ›  MySQL

怎样使得 MySQL 当记录不存在时插入,当记录存在时更新?

  •  
  •   billgreen1 · Dec 16, 2015 · 6899 views
    This topic created in 3937 days ago, the information mentioned may be changed or developed.

    表
    ID,date,code,prediction, fact
    ID 自动增长, primary key
    当 date 和 code 确定,能确定这一条记录。

    目的:
    每天更新昨日预测结果和发布次日预测。
    假设今天是 2015-12-15 ,记录应该如下:
    ID date code prediction fact
    1 2015-12-15 000001 1 1
    2 2015-12-15 000002 1 -1
    3 2015-12-16 000001 1 NULL
    4 2015-12-16 000002 1 NULL

    2015-12-16 这天的工作就是:
    1. 根据今天的 fact 结果,更新本日的记录。
    2. 发布 2015-12-17 这天的记录。

    目前的做法: 删除日期大于等于 2015-12-16 的所有记录,然后插入新的记录。

    遇到的问题:
    1. 2015-12-16 的 prediction 是 2015-12-15 这日做出的,如果 12-16 这一日的预测模型变了, prediction 也会跟着变。会让人觉得我是在修改昨日预测,这样不好。
    2. 有时候我要多次运行程序,先删除再添加会让 ID 显得很奇怪。

    希望的做法(这两条 SQL 我都不是太会写,我用的 sqlalchemy):
    1. 直接插入,如果表里有当前(date,code),则更新这条记录。 OR
    2. 直接更新,如果表里没有当前( date,code)则进行插入。

    或者有更好的方法?

    谢谢

    24 replies  •  2015-12-16 16:33:08 +08:00
    mahone3297
        1
    mahone3297  
       Dec 16, 2015   ❤️ 1
    replace
    eoo
        2
    eoo  
       Dec 16, 2015 via Android
    $SQL="SELECT `phone` FROM `17wo` WHERE `phone`='{$phone}'";



    $mysqli_r=$mysqli->query($SQL);



    //如果用户存在则只更新 COOKIE

    if($mysqli_r->fetch_array()){



    $SQL="UPDATE `17wo` SET `phone`='{$phone}',`password`='{$password}' WHERE `phone`='{$phone}'";



    if($mysqli->query($SQL)){

    echo $phone.' 帐号更新成功!';

    }else{

    echo $phone.' 帐号更新失败!';

    }



    }else{//否则添加用户

    $SQL="INSERT INTO `17wo` (`phone`,`password`,`state`,`zctime`) VALUES ('{$phone}','{$password}',0,'{$zctime}')";



    if($mysqli->query($SQL)){

    echo $phone.' 成功加入自动签到!';

    }else{

    echo $phone.' 加入自动签到失败!';

    }



    }
    snailsir
        3
    snailsir  
       Dec 16, 2015
    我想答案你自己已经说出来了
    bonfirenosedoyou
        4
    bonfirenosedoyou  
       Dec 16, 2015   ❤️ 1
    1.replace
    2.ignore
    3.on duplicate key update
    laoyuan
        5
    laoyuan  
       Dec 16, 2015
    你需要一个 unique 字段,值是 md5(date, code) ,然后先 insert ignore 再 update
    这样子稳也不麻烦,相信你的服务器没紧张到要把两条查询压缩成一条半的程度。
    replace 不行, replace 是先删再增, ID 会变
    laoyuan
        6
    laoyuan  
       Dec 16, 2015
    看来最佳方案就是添加 md5(date, code) unique 字段加 @groot 提到的 on duplicate key update
    daniellu
        7
    daniellu  
       Dec 16, 2015
    @groot +1 正解
    incompatible
        8
    incompatible  
       Dec 16, 2015
    @eoo 这代码不怕 sql 注入?
    wawehi
        9
    wawehi  
       Dec 16, 2015
    INSERT INTO xxx ON DUPLICATE KEY UPDATE xxx
    xujif
        10
    xujif  
       Dec 16, 2015
    @laoyuan 还需要 md5 ?直接 unique[date,code]不行吗
    lyragosa
        11
    lyragosa  
       Dec 16, 2015
    on duplicate key 正解
    defunct9
        12
    defunct9  
       Dec 16, 2015
    唉:
    statsd 中用的一段,-678 是这个表中永远都不会有的一个值。
    表结构:
    ======================================
    CREATE TABLE `gauges_statistics` (
    `timestamp` BIGINT NOT NULL ,
    `name` VARCHAR(255) NOT NULL ,
    `value` INT(11) NOT NULL ,
    PRIMARY KEY (`timestamp`,`name`) )
    ======================================
    语句:
    insert into `gauges_statistics` select "+time_stamp+", '"+gaugeName+"', "+gaugeValue+" from dual where (select if(max(value),max(value),-678) from `gauges_statistics` where name = '"+gaugeName+"') = -678 OR (select value from `gauges_statistics` where name = '"+gaugeName+"' order by timestamp desc limit 0,1) <> "+gaugeValue+";"
    laoyuan
        13
    laoyuan  
       Dec 16, 2015
    @xujif 嗯这样更省事,我习惯 md5 了。。其实我不知道 unique key 可以多个字段蛤蛤
    ynztyl10
        14
    ynztyl10  
       Dec 16, 2015
    可以先 google 的
    billgreen1
        15
    billgreen1  
    OP
       Dec 16, 2015
    多谢以上各位。
    最终方案是:
    alter table mytable
    add constraint date_code_unique
    Unique(date,code);

    然后就可以使用 insert ... on duplicate key update
    eoo
        16
    eoo  
       Dec 16, 2015 via Android
    @incompatible 自己写的联通一起沃自动签到程序 代码前端,因为考虑到 一起沃转流量是需要 短信验证码的 而且一起沃的密码是独立性的 没什么危害性 过不过滤都无所谓了。
    Perrie
        17
    Perrie  
       Dec 16, 2015
    同比较常用的是 on duplicate key update 以及 replace
    kchum
        18
    kchum  
       Dec 16, 2015
    @eoo 有木有考虑开源 17wo 到脚本啊?
    eoo
        19
    eoo  
       Dec 16, 2015 via Android
    TaMud
        20
    TaMud  
       Dec 16, 2015
    "insert into s_cmd(cmd_str,hosts) select ?,? from dual where not exists(select id from s_cmd where hosts=? and cmd_str=? limit 1) ";
    TaMud
        21
    TaMud  
       Dec 16, 2015
    insert into select where not exists()
    TaMud
        22
    TaMud  
       Dec 16, 2015
    不要忘了 limit 1
    lixiaoxie
        23
    lixiaoxie  
       Dec 16, 2015
    REPLACE INTO t_xxx (date,code,prediction,fact) VALUES (xx,xx,xx,xx);
    Chrics
        24
    Chrics  
       Dec 16, 2015
    ORM 框架大部分都内置这个功能的吧?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1076 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 23:37 · PVG 07:37 · LAX 16:37 · JFK 19:37
    ♥ Do have faith in what you're doing.