【问题标题】:Update with Where, Order by and Limit does not work更新 Where、Order by 和 Limit 不起作用
【发布时间】:2018-09-26 07:58:26
【问题描述】:

我正在使用 SQLite 3。

当我输入以下查询时

UPDATE MyTable Set Flag = 1 WHERE ID = 5 Order By OrderID DESC LIMIT 1;

我总是会得到一个错误:

排序依据附近,语法错误

我无法弄清楚我的查询有什么问题

【问题讨论】:

  • 我不知道sqlite,但我猜limit 1不能用于更新。无论如何,这里的逻辑是什么?您有 N 个 OrderID=5 的行,并且您只希望其中一个任意获得 flag=1?
  • @GeorgeMenoutis,是的,会有多条 ID = 5 的记录,我会按 OrderID 对它们进行排序,只有 OrderID 最大的一条会被更新。
  • 显示PRAGMA compile_options;的输出
  • @alancc 我已经根据您在 MajidVahidkhoo 答案下的 cmets 发布了我的答案,希望对您有所帮助。不过,您应该用您在 cmets 中写的内容更新您最初的问题 - 供未来的读者参考。

标签: sql sqlite sql-update


【解决方案1】:

要在 UPDATE 或 DELETE 语句中使用 LIMIT 和 ORDER BY,您必须做两件事:

  • 从源代码构建 sqlite3.c 合并的自定义版本,并使用 --enable-update-limit 选项对其进行配置。
  • 将自定义 sqlite3.c 编译到您的项目中,并将 SQLITE_ENABLE_UPDATE_DELETE_LIMIT 定义为 1。

【讨论】:

  • 感谢您的解决方案。这似乎有点复杂。
  • 是否有一种解决方法可以在UPDATE或DELETE中支持ORDER BY和LIMIT,而无需重新编译sqlite3.c?
【解决方案2】:

“Order By OrderID DESC LIMIT 1”用于选择排名靠前的结果 所以你应该在选择查询中使用它。 你应该做一个子查询,你首先得到 id 然后更新它:

UPDATE  MyTable 
SET Flag = 1 
WHERE (ID,OrderID) IN (SELECT ID,OrderID
FROM MyTable 
WHERE ID = 5 
ORDER BY OrderID DESC LIMIT 1);

Demo

【讨论】:

  • 你的答案是最好的。唯一的问题是可能有多行 ID 相同但 OrderID 不同。这就是为什么我需要找出具有特定 ID 的行以及最大 OrderID 并更新它的原因。使用 ID 和订单 ID,我可以识别唯一的行。仅使用 ID,我可能会获得多行,而只有一个具有最大 OrderID 的行是我要更新的行。
  • 我写了一个查询:UPDATE MyTable SET Flag = 1 WHERE (ID = 5) AND (OrderID IN (SELECT OrderID FROM MyTable WHERE ID = 5 Order by OrderID DESC LIMIT 1));对吗?
  • 这个答案没有任何意义,因为它相当于UPDATE MyTable SET Flag=1 WHERE ID = 5——ID = 5 的每一行都将被更新,而不是 OrderID 最高的那一行
  • Demo 请与使用 ROWID/tuple 的方法进行比较 - stackoverflow.com/a/52558111/5070879
  • @alancc,对不起,我忘了选择 OrderId,现在,它的工作。
【解决方案3】:

你可以使用ROWID:

UPDATE MyTable 
SET Flag = 1 
WHERE ROWID IN (SELECT ROWID FROM MyTable WHERE ID = 5 
                ORDER BY OrderID DESC LIMIT 1);

db<>fiddle demo

(ID,OrderID)元组:

UPDATE  MyTable 
SET Flag = 1 
WHERE (ID, ORDERID) IN (SELECT  ID, ORDERID FROM MyTable WHERE ID = 5 
                        ORDER BY OrderID DESC LIMIT 1);

db<>fiddle demo2


如果您需要为每个 ID 批量执行此操作(SQLite 3.25.0):

WITH cte AS (
  SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY OrderID DESC) AS rn FROM tab
)
UPDATE tab
SET Flag = 1
WHERE (ID, OrderID) IN (
       SELECT ID, OrderID
       FROM cte
       WHERE rn = 1
      );

【讨论】:

  • 非常感谢。我相信使用 ROWID 比使用 (ID, OrderID) 对更快。所以我把你的解决方案作为答案,给你50声望。
【解决方案4】:

Order By 语句在更新查询中不起作用。 你必须使用替代方式

UPDATE MyTable Set Flag = 1 WHERE ID = 5 
and OrderId = (select max(OrderId) from MyTable where Id = 5);

如果您使用了上述查询,它将起作用。

【讨论】:

    【解决方案5】:

    简介

    下面我将介绍两种解决方案来解决问题并执行正确的UPDATE。每个解决方案的末尾都有一个关于示例数据的实时示例。

    • First 不需要您输入任何 id 并通过为每个 id 选择最新的 orderid 并将其更改为 flag 来处理整个表格987654331@

    • 第二要求您输入id,并且仅适用于在运行中更新id

    我个人会选择 first 解决方案,但我不确定您的要求,因此发布了两种可能性。

    第一个解决方案 - 更新整个表

    解释在这里,代码向下滚动。

    为此,我们将使用Row Value 构造(id, orderid),就像第二个解决方案一样。 它将根据orderid 找到最新的行,并仅更新给定(id, orderid) 对的那一行。更多信息包含在第二个解决方案的解释中。

    我们还需要模拟row_number 函数来分配每一行的排名编号,找出每个id 的哪一行有最新的orderid,然后标记为1,以便能够只提取那些更新。这将允许我们在一个语句中为不同的 id 更新多行。 SQLite 将具有此功能 built in version 3.2.5 但现在,我们将使用子查询。

    要生成行号,我们将使用这个:

    select 
      *, 
      (select count(*) from mytable m1 where m1.id = m2.id and m1.orderid >= m2.orderid) as rn
    from mytable m2
    

    然后我们只需要过滤rn = 1上的输出,我们就有了我们需要的东西。

    也就是说,整个 UPDATE 语句将如下所示:

    代码

    update mytable
    set flag = 1
    where (id,orderid) in (
      select id, orderid
      from (
        select *, (select count(*) from mytable m1 where m1.id = m2.id and m1.orderid >= m2.orderid) as rn
        from mytable m2
        ) m
      where 
        m.rn = 1
        and m.id = mytable.id
      );
    

    现场演示

    这里是 db fiddle,可以根据示例数据查看此解决方案。


    第二种解决方案 - 只更新一个 ID

    如果您知道要更新您的 ID 并希望只为一个 id 运行 UPDATE 语句,那么这将起作用:

    代码

    update mytable
    set flag = 1
    where (id,orderid) in (
      select id, orderid
      from mytable
      where id = 5
      order by orderid desc
      limit 1
      );
    

    说明

    (id, orderid) 是一个名为Row Value 的结构,SQLite 会从左到右比较标量值。

    来自文档的示例:

    SELECT (1,2,3) = (1,2,3) -- outputs: 1
    

    现场演示

    这里是 db fiddle,可以根据示例数据查看此解决方案。

    【讨论】:

      【解决方案6】:

      SQL

      UPDATE MyTable
      SET Flag = 1
      WHERE ID = 5
      AND OrderID IN (SELECT OrderID
                      FROM MyTable
                      WHERE ID = 5
                      ORDER BY OrderID DESC
                      LIMIT 1);
      

      演示

      SQLFiddle 演示:http://sqlfiddle.com/#!5/6d596/2

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-06
        • 1970-01-01
        • 2014-01-09
        • 1970-01-01
        • 2017-09-12
        相关资源
        最近更新 更多