【问题标题】:How to write this specific query in mysql?如何在mysql中编写这个特定的查询?
【发布时间】:2015-10-28 17:01:04
【问题描述】:

我有一段 SQL 代码取自 SQL Server 下的 ELMAH 存储过程:

DELETE FROM [ELMAH_Error]
WHERE ErrorId NOT IN (SELECT TOP 100 ErrorId FROM ELMAH_Error ORDER BY TimeUtc DESC)

我现在迁移一个网站改用mysql,不知道怎么翻译这段代码。

我必须在这段代码之后添加翻译:

CREATE DEFINER=`b43638b86659eb`@`%` PROCEDURE `elmah_LogError`(
    IN ErrorId CHAR(36), 
    IN Application varchar(60), 
    IN Host VARCHAR(30), 
    IN Type VARCHAR(100), 
    IN Source VARCHAR(60), 
    IN Message VARCHAR(500), 
    IN User VARCHAR(50), 
    IN AllXml TEXT, 
    IN StatusCode INT(10), 
    IN TimeUtc DATETIME
)
    MODIFIES SQL DATA
BEGIN
    INSERT INTO `elmah_error` (
        `ErrorId`, 
        `Application`, 
        `Host`, 
        `Type`, 
        `Source`, 
        `Message`, 
        `User`, 
        `AllXml`, 
        `StatusCode`, 
        `TimeUtc`
    ) VALUES (
        ErrorId, 
        Application, 
        Host, 
        Type, 
        Source, 
        Message, 
        User, 
        AllXml, 
        StatusCode, 
        TimeUtc
    );
END

我尝试在 END 语句之前添加@Sick 的响应,但 SQL Workbench(通过 alter procedure 命令)看不到它。

谢谢

【问题讨论】:

    标签: mysql sql tsql elmah


    【解决方案1】:

    Sql Server TOP 的等效项在 Mysql 中是 Limit 并且应该在查询的末尾

    DELETE FROM `ELMAH_Error`
    WHERE ErrorId NOT IN (SELECT ErrorId 
                          FROM `ELMAH_Error`
                          ORDER BY TimeUtc DESC LIMIT 100)
    

    【讨论】:

    • 这接近正确,尽管您应该在表名周围使用反引号而不是方括号 ([...])。
    • @EdCottrell - 是的,错过了 :)
    • 谢谢@Sick。我更新了我的问题,向您展示我在尝试您的解决方案时遇到的困难。
    • 好的,我有理由。 MySql 版本不支持 LIMIT。尝试了 Gordon 的代码,这个被接受了。
    【解决方案2】:

    如果表真的很大,那么在 MySQL 中截断通常比删除快得多。比如:

    lock tables ELMAH_Error write;
    create temporary table cpy_ELMAH_Error 
       select * from ELMAH_Error order by TimeUtc DESC LIMIT 100;
    truncate table ELMAH_Error;
    insert into  ELMAH_Error select * from cpy_ELMAH_Error;
    drop table cpy_ELMAH_Error;
    unlock tables;
    

    【讨论】:

    • 谢谢。它现在并不大,它会增长到达到 100 条记录。之后,DELETE 将确保不超过 100。
    【解决方案3】:

    如果您有兴趣,还有一种更简单的方法:

    set @N=0;
    delete from ELMAH_Error where (@N:=@N+1) > 101 order by TimeUtc DESC;
    

    【讨论】:

    • 我仍在寻找解决方案。我试过你的,它什么也没删除。有什么想法吗?
    【解决方案4】:

    MySQL 在某些子查询中不支持limit。如果是这种情况,则使用显式连接:

    DELETE e
        FROM ELMAH_Error e LEFT JOIN
             (SELECT ErrorId
              FROM ELMAH_Error
              ORDER BY TimeUtc DESC
              LIMIT 100
             ) ee
             ON ee.ErrorId = e.ErrorId
        WHERE ee.ErrorId IS NULL;
    

    编辑:

    上面的代码假定ErrorId 在表中是唯一的并且没有NULL 值。如果这不是真的,那么查询将不起作用。 (注意:假设名为 Id 的列是唯一的且不为 null 的假设似乎非常合理。)

    DELETE e
        FROM ELMAH_Error e LEFT JOIN
             (SELECT TimeUtc
              FROM ELMAH_Error
              ORDER BY TimeUtc DESC
              LIMIT 100
             ) ee
             ON ee.TimeUtc = e.TimeUtc
        WHERE ee.TimeUtc IS NULL;
    

    【讨论】:

    • MySql 服务器接受此代码。我检查了生成错误没有被破坏。它不是。关于删除记录,我将能够在错误堆积后检查它是否有效。在此期间,我会将您的解决方案标记为答案。
    • 看来还是有问题。此代码在我的错误表中只保留一个条目!有什么想法吗?
    • @NicolasCadilhac 。 . .当最近的 100 行都具有相同的 ErrorId 时,会发生这种情况。
    • 嗯,没有。起初,桌子是空的。然后,在保存第一个条目后,添加新条目会删除前一个条目。另外,我想 Elmah 不会创建具有相同 ErrorIds 的条目(无论如何它们都是 guid)。
    • @NicolasCadilhac 。 . .此代码应该可以工作,除非您在 ELMAH_Error 中有重复或 NULL 值。
    猜你喜欢
    • 2011-09-13
    • 2019-09-21
    • 1970-01-01
    • 2014-07-27
    • 2012-02-03
    • 2015-10-19
    • 1970-01-01
    • 2017-06-13
    相关资源
    最近更新 更多