【问题标题】:mysql select rows with same ids and preserve their order?mysql选择具有相同ID的行并保留它们的顺序?
【发布时间】:2012-02-23 12:31:03
【问题描述】:

只是一个简单的问题:

我必须有一个包含多行的单个查询 - 有些行是相同的 - 并且必须在结果中保留行的顺序 -

对我指的是什么的一些想法:

SELECT id,date 
FROM items 
WHERE id IN (1,2,1,3) 
ORDER BY id=1 DESC,id=2 DESC,id=1 DESC,id=3 DESC;

不幸的是mysql结果是这样的:

1,2,3

不是 1,2,1,3

它删除了我必须在结果中显示在同一网页上的多个面板中的重复项 -

我真的不想一个接一个地循环遍历每个 id 以使它们以我想要的方式显示 -

有没有一种方法可以真正拥有一个查询,该查询将保留订单并根据请求提取行,无论其是否唯一 -

【问题讨论】:

  • 我觉得你的数据模型设计不太好。你有主键作为自增吗?
  • 是 - id 在 db 表中自动递增 -
  • 如果 id 是自动递增的,则不存在可能的重复行,所以你的意思是 WHERE id IN (1,2,1,3) - 你有 2 次 id = 1
  • 这是一个抽象的想法来描述我需要输出的结果 - 如果那令人困惑,那么我真诚的应用 -

标签: mysql select rows preserve


【解决方案1】:

您的查询将永远无法工作,因为IN 子句的值列表中的重复值将被忽略。 唯一的方法是使用UNION ALL

SELECT id, date FROM items where id = 1
UNION ALL
SELECT id, date FROM items where id = 2
UNION ALL
SELECT id, date FROM items where id = 1
UNION ALL
SELECT id, date FROM items where id = 3;

但坦率地说,我怀疑你的数据模型到目前为止已经搞砸了,它无法使用。

【讨论】:

  • 我同意你的最终观点
  • 这不是唯一的方式。还有其他的。
【解决方案2】:

试试

SELECT
    id,
    date
FROM items
WHERE id IN (1,2,1,3)
ORDER BY FIND_IN_SET(id, '1,2,1,3')

【讨论】:

  • 将排序 1,1,2,3,因为 FIND_IN_SET() 的值是 1,2,1,4
【解决方案3】:

另一种回答可疑问题的谨慎方式:

SELECT 
      items.id, 
      items.date 
FROM 
      items 
  JOIN
      ( SELECT 1 AS id, 1 AS ordering
      UNION ALL 
        SELECT 2, 2
      UNION ALL 
        SELECT 1, 3
      UNION ALL 
        SELECT 3, 4
      ) AS auxilary
    ON 
      auxilary.id = items.id 
ORDER BY 
      auxilary.ordering

【讨论】:

    【解决方案4】:

    另一种方法(未经测试,但应该给你的想法):

    CREATE TEMPORARY TABLE tt (id INT, ai int unsigned auto_increment primary key);
    INSERT INTO tt (id) VALUES (1), (2), (1), (3);
    SELECT
        id,
        date
    FROM items JOIN tt USING (id)
    ORDER BY tt.ai;
    

    保持给定的顺序。

    【讨论】:

    • 与我的回答类似。但是您确实需要临时表上的 2 列。一种用于加盟,一种用于订购。
    • 糟糕,您确实有 2 列!值应为:VALUES (1), (2), (1), (3)
    • 我有 - 我的是 idai(用于自动增量),你的是 idordering。但是一个 temptable 可能对数据插入“更友好”,即。 e.查询更容易构建,具体取决于所使用的编程语言。
    • 这个建议会很痛苦,在不必要的地方使用临时表是多余的。
    • IMO 它不像构建包含数十个 UNION orgies 的查询那样痛苦......
    【解决方案5】:

    如果您想包含 id=1 的记录,并且只要您得到它们,顺序并不重要,您可以将查询拆分为两个查询,一个用于 (1,2,3) 并集所有其他查询 id=1 或直接执行:

    ... In (1,2)
    Union all
    ... In (1,3)
    

    例子:

      Select * from
      (Select case id when 1 then 1 when 2 then 2 as pseudocol, othercolumns
      From table where Id in (1,2)
      Union all
      Select case id when 1 then 3 when 3 then 4 as pseudocol, othercolumns
      From table where Id in (1,3)) t order by pseudocol
    

    【讨论】:

    • 顺序至关重要,伙计们。
    • 我作为最后一个选项编写的 union all 选项将按照您想要的顺序返回记录。你试过了吗?
    • 感谢 icarus - 我在 stmt 以上的 union 都有问题 - 它不会返回相同的订单 - 我必须有订单 - 所以结果都是有序的进出
    • Dude,然后在 select 语句中添加一个伪列,指示您想要的顺序,并为整个联合设置别名,并在此伪列上执行 order by。
    • @user1228311 检查我的最后一个例子
    【解决方案6】:

    不要做你想做的事,只需选择你需要的唯一行。在前端代码中,在 key=>value 结构中存储每个唯一行一次,其中 key 是项目 ID,value 是您需要的关于该项目的任何数据。

    一旦你有了它,你就可以使用前端逻辑以所需的顺序输出它们,包括重复。这将减少您尝试选择的冗余数据量。

    例如 这不是可用的代码 - 所需的确切语法取决于您的脚本语言

    -- setup a display order
    displayOrder= [1,2,1,3];
    
    -- select data from database, order doesn't matter here
    SELECT id,date 
    FROM items 
    WHERE id IN (displayOrder);
    
    
    -- cache the results in a key=> value array
    arrCachedRows = {};
    for (.... each db row returned ...) {
        arrCachedRows[id] = date;
    }
    
    -- Now output in desired order
    for (listIndex in displayOrder) {
        -- Make sure the index is cached
        if (listIndex exists in arrCachedRow) {
            echo arrCachedRows[listIndex ];
        }
    }
    

    如果您不顾我的警告仍坚持使用 UNION

    如果您违反上述建议,并且绝对必须按该顺序将它们放回 1 个查询中,则添加一个额外的行,该行将强制执行该行顺序。请参阅下面的查询,其中我使用变量 @subIndex 将递增值添加为 subIndex。这反过来又可以让您重新排序,它将按照请求的顺序。

    SELECT
        i.*
    FROM (
        SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 1
        UNION
        SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 2
        UNION
        SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 1
        UNION
        SELECT @subIndex:=@subIndex+1 AS subIndex, id, date FROM items where id = 3
    ) AS i,(SELECT @subIndex:=0) v
    ORDER BY i.subIndex
    

    或者更简洁的版本,将项目选择保留到外部并隐藏子索引

    SELECT
        items.*
    FROM items
    -- initialise variable
    INNER JOIN (SELECT @subIndex:=0) v
    -- create a meta-table with the ids desired in the order desired
    INNER JOIN (
        SELECT @subIndex:=@subIndex+1  AS subIndex, 1 AS id
        UNION
        SELECT @subIndex:=@subIndex+1  AS subIndex, 2 AS id
        UNION
        SELECT @subIndex:=@subIndex+1  AS subIndex, 1 AS id
        UNION
        SELECT @subIndex:=@subIndex+1  AS subIndex, 3 AS id
    ) AS i
    ON i.id = items.id
    -- order by the subindex from i
    ORDER BY i.`subIndex` ASC
    

    【讨论】:

    • 就像我说的那样——我真的不想一个接一个地循环遍历每个 id 来让它们以我想要的方式显示——
    • 您只需定义一次显示顺序。您可以通过使用 UNION 等来获得相同的效果,但是它的效率和可扩展性会降低。使用此方法,无论您添加多少个 id 到 displayOrder,它都会起作用。
    • 谢谢 simon - 我在 stmt 上的 union 都有问题 - 它不会返回相同的订单 - 我必须有订单 - 所以结果都是有序的 -
    • 所以,ORDER BY i.index ASC - 会生成新订单,看起来像,还是会保留原始订单?请澄清一下 - 谢谢!
    • @subIndex:=@subIndex+1 添加了一个递增的列,即 1、2、3、4,我在子查询 i 中将其命名为 subIndex。这在外部查询中被认为是静态的,因此是ORDER BY i.index ASC。只要包含ORDER BY i.subIndex ASCids 仍将按照您在构建的UNION 中指定的顺序排列。
    猜你喜欢
    • 2016-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-04
    • 2023-01-11
    • 2019-12-08
    • 2023-03-08
    相关资源
    最近更新 更多