【问题标题】:Ordering by the order of values in a SQL IN() clause按 SQL IN() 子句中的值顺序排序
【发布时间】:2010-09-28 15:30:23
【问题描述】:

我想知道是否有可能(可能是更好的方法)按 IN() 子句中的值顺序进行排序。

问题是我有 2 个查询,一个获取所有 ID,第二个获取所有信息。第一个创建我希望第二个排序的 ID 的顺序。 ID 以正确的顺序放在 IN() 子句中。

所以它会是这样的(非常简化):

SELECT id FROM table1 WHERE ... ORDER BY display_order, name

SELECT name, description, ... WHERE id IN ([id's from first])

问题在于第二个查询返回的结果与将 ID 放入 IN() 子句的顺序不同。

我发现的一个解决方案是将所有 ID 放入带有自动递增字段的临时表中,然后将其加入第二个查询中。

还有更好的选择吗?

注意:由于第一个查询是“由用户”运行的,而第二个查询是在后台进程中运行的,因此无法使用子查询将二合一查询组合在一起。 p>

我正在使用 MySQL,但我认为让它注意其他数据库的选项可能会很有用。

【问题讨论】:

    标签: mysql sql sql-order-by


    【解决方案1】:

    我只是尝试这样做是我们没有 FIELD() 的 MS SQL Server:

    SELECT table1.id
    ... 
    INNER JOIN
        (VALUES (10,1),(3,2),(4,3),(5,4),(7,5),(8,6),(9,7),(2,8),(6,9),(5,10)
        ) AS X(id,sortorder)
            ON X.id = table1.id
        ORDER BY X.sortorder
    

    请注意,我也允许复制。

    【讨论】:

      【解决方案2】:

      使用MySQL的FIELD()函数:

      SELECT name, description, ...
      FROM ...
      WHERE id IN([ids, any order])
      ORDER BY FIELD(id, [ids in order])
      

      FIELD() 将返回等于第一个参数的第一个参数的索引(第一个参数本身除外)。

      FIELD('a', 'a', 'b', 'c')

      将返回 1

      FIELD('a', 'c', 'b', 'a')

      将返回 3

      如果您以相同的顺序将 id 粘贴到 IN() 子句和 FIELD() 函数中,这将完全符合您的要求。

      【讨论】:

      • @Vojto 按任意顺序排序很慢。这是最好的,因为不能保证INFIELD 参数相等。通过使用这些附加知识,在程序代码中执行此操作可能会更快。当然,如果您考虑到服务器性能,将这种负担放在客户端而不是服务器上可能更明智。
      • sqlite 呢?
      • 我需要看下一个答案才能让它工作,看不懂你的语法,我试着用[],然后用(),没有必要,只是id分开用逗号
      【解决方案3】:

      如果您想使用 MS SQL Server 2008+ 中查询输入的值对查询进行任意排序,可以通过动态创建表并像这样进行连接来完成(使用 OP 中的命名法)。

      SELECT table1.name, table1.description ... 
      FROM (VALUES (id1,1), (id2,2), (id3,3) ...) AS orderTbl(orderKey, orderIdx) 
      LEFT JOIN table1 ON orderTbl.orderKey=table1.id
      ORDER BY orderTbl.orderIdx
      

      如果您将 VALUES 语句替换为执行相同操作但在 ANSI SQL 中的其他语句,那么这应该适用于任何 SQL 数据库。

      注意: 在查询大于 100 条左右的记录集时,需要创建表中的第二列(orderTbl.orderIdx)。我最初没有 orderIdx 列,但发现结果集大于 100 时,我必须按该列显式排序;无论如何,在 SQL Server Express 2014 中。

      【讨论】:

      • 这个问题是关于 MySQL...不确定您的查询是否适用于 MySQL。
      • @Darryl,它不会。但是,当您在谷歌上搜索如何按 IN 子句排序时,这篇文章是最高结果,所以我想我不妨在这里发布它,一般方法适用于所有符合 ANSI 的 SQL 服务器(只需将 VALUES 语句替换为标准创建表的方法)。
      • 注意,这对我有用,但只有在我将 orderTbl.orderKeyorderTbl.orderIndex 的引用替换为 orderKeyorderIndex 之后
      【解决方案4】:

      我认为您应该设法以一种您只需进行联接的方式存储您的数据,这将是完美的,所以没有黑客和复杂的事情发生。

      例如,我有一个“最近播放”的曲目 ID 列表,在 SQLite 上我只是这样做:

      SELECT * FROM recently NATURAL JOIN tracks;
      

      【讨论】:

      • 哦,我希望生活就这么简单:)
      【解决方案5】:

      使用 MySQL FIND_IN_SET 函数:

        SELECT * 
          FROM table_name 
         WHERE id IN (..,..,..,..) 
      ORDER BY FIND_IN_SET (coloumn_name, .., .., ..);
      

      【讨论】:

        【解决方案6】:

        Ans 获取排序数据。

        SELECT ...
        FROM ...
        ORDER  BY FIELD(user_id,5,3,2,...,50)  LIMIT 10
        

        【讨论】:

          【解决方案7】:
          SELECT ORDER_NO, DELIVERY_ADDRESS 
          from IFSAPP.PURCHASE_ORDER_TAB 
          where ORDER_NO in ('52000077','52000079','52000167','52000297','52000204','52000409','52000126') 
          ORDER BY instr('52000077,52000079,52000167,52000297,52000204,52000409,52000126',ORDER_NO)
          

          真的很棒

          【讨论】:

          • 在 Oracle 上为我工作。快捷方便。谢谢。
          【解决方案8】:

          对于 Oracle,John 使用 instr() 函数的解决方案有效。这是可行的稍微不同的解决方案- SELECT id FROM table1 WHERE id IN (1, 20, 45, 60) ORDER BY instr('1, 20, 45, 60', id)

          【讨论】:

            【解决方案9】:

            请参阅以下如何获取已排序的数据。

            SELECT ...
              FROM ...
             WHERE zip IN (91709,92886,92807,...,91356)
               AND user.status=1
            ORDER 
                BY provider.package_id DESC 
                 , FIELD(zip,91709,92886,92807,...,91356)
            LIMIT 10
            

            【讨论】:

              【解决方案10】:

              IN子句描述了一组值,而集合没有顺序。

              display_order 列上加入并排序的解决方案是最接近正确的解决方案;其他任何东西都可能是特定于 DBMS 的 hack(或者正在使用标准 SQL 中的 OLAP 函数做一些事情)。当然,连接是最接近可移植的解决方案(尽管使用display_order 值生成数据可能有问题)。请注意,您可能需要选择排序列;这曾经是标准 SQL 中的一项要求,尽管我相信它在不久前作为一项规则被放宽了(可能早在 SQL-92 之前)。

              【讨论】:

                【解决方案11】:

                想到的两个解决方案:

                1. order by case id when 123 then 1 when 456 then 2 else null end asc

                2. order by instr(','||id||',',',123,456,') asc

                instr() 来自 Oracle;也许您有 locate()charindex() 或类似的东西)

                【讨论】:

                【解决方案12】:

                我的第一个想法是编写一个查询,但您说这是不可能的,因为一个由用户运行,另一个在后台运行。您如何存储要从用户传递到后台进程的 ID 列表?为什么不把它们放在一个临时表中,用一列表示顺序。

                那么这个怎么样:

                1. 用户界面位运行并将值插入到您创建的新表中。它将插入 id、位置和某种工作编号标识符)
                2. 作业号被传递给后台进程(而不是所有的 id)
                3. 后台进程在步骤 1 中从表中进行选择,然后您加入以获取所需的其他信息。它使用 WHERE 子句中的作业编号并按职位列排序。
                4. 后台进程完成后,会根据作业标识符从表中删除。

                【讨论】:

                  【解决方案13】:

                  试一试:

                  SELECT name, description, ...
                  WHERE id IN
                      (SELECT id FROM table1 WHERE...)
                  ORDER BY
                      (SELECT display_order FROM table1 WHERE...),
                      (SELECT name FROM table1 WHERE...)
                  

                  WHERE 可能需要稍作调整才能使相关子查询正常工作,但基本原则应该是合理的。

                  【讨论】:

                  • 参见注释,并且如上所述,查询示例非常简化,因此我无法将它们组合成 1 个带有子查询的查询。
                  猜你喜欢
                  • 2011-01-12
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-11-30
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-02-15
                  • 1970-01-01
                  相关资源
                  最近更新 更多