【问题标题】:SQL: Select a list of numbers from "nothing"SQL:从“无”中选择一个数字列表
【发布时间】:2013-07-16 10:00:57
【问题描述】:

什么是从包含数字列表的“无”中选择关系的快速/可读方法。我想通过设置开始值和结束值来定义哪些数字。我正在使用 Postgres SQL 和 SQLite,并且会对可在两个/多个平台上运行的通用解决方案感兴趣。

期望的输出关系:

# x
  0
  1
  2
  3
  4

我知道我可以从“无”中选择单行:SELECT 0,1,2,3,4 但这会将值选择为列而不是行,并且需要在查询中指定所有值,而不是仅使用我的开始和结束值:@ 987654324@和4。

在 Postgres 中,您有一个特殊的 generate_series 函数用于这种情况:

SELECT * FROM generate_series(0,4) x;

这很好用,但不是标准的。我也可以想象一些使用临时表的复杂解决方案,但我想要一些通用且简单的东西,例如:

SELECT * FROM [0..4]

也许使用SEQUENCE 语句或SELECT 0 和SELECT 4 的某种神奇组合?

【问题讨论】:

  • 您不妨使用最多 1,000 的数字,我会说——也许在桌子上放一个索引。否则,创建 numbers_to_1000、numbers_to_1000000 等视图来封装这些交叉连接。
  • @Juve,你能接受一些答案还是发布你的答案并接受它?
  • 当我开始寻找时,我惊讶于这个看似简单的任务实现起来有多么尴尬。这是一篇有更多可能性的文章(但它表明 PostgreSQL 中没有什么比 GENERATE_SERIES() 更重要):blog.jooq.org/2013/11/19/…
  • 很多想法不适用于 BigQuery 等只读环境。

标签: sql sqlite postgresql sequence


【解决方案1】:

在 SQL 服务器(和 PostgreSQL)中,我会使用递归公用表表达式:SQL Server,PostgreSQL

with recursive Numbers as (
    select 0 as Number
    union all
    select Number + 1
    from Numbers
    where Number < 4
)
select Number
from Numbers

SQL FIDDLE EXAMPLE

但是,据我所知,SQLite 中没有 WITH。

所以,可能的解决方案是

  • 创建一个用户定义的函数(this 可能会有所帮助)
  • 创建一个表格,其中包含从 0 到您需要的最大数量的数字,然后像这样从中选择:

    select Number from Numbers where Number >= 0 and Number <= 4
    

【讨论】:

  • 递归 CTE 也可以在 Postgres 中工作(事实上,这是唯一的“标准”方式——因为现在几乎所有现代 DBMS 都支持递归 CTE)
  • 是的,我刚刚尝试帮助使用 SQLite,因为他知道如何在 PostgreSQL 中进行操作,但是谢谢,我会编辑答案
  • 虽然递归 CTE 可以在大多数现代 DBMS 中工作,但它已被证明为 a very inefficient way of generating a sequence。我认为数字表是迄今为止最好的方法。
  • @GarethD 是的,在我的生产代码中,我使用数字表来表示未知的数字范围、日期
  • 谢谢,对于“数字表”的提示,一些进一步的研究表明您可以从这个基表交叉连接更多范围。 (查看我的编辑)
【解决方案2】:

在 PostgreSQL 和 SQLite 中执行此操作的简单方法如下:

sqlite> select 1 union select 2 union select 3;
1
2
3

它应该适用于大多数 RDBMS 系统,但您必须在 Oracle 中使用 IIRC:

select 1 from dual union select 2 from dual union select 3 from dual;

但是我没有 Oracle DB 来测试它。

【讨论】:

    【解决方案3】:

    感谢所有回答! 在讨论之后,我意识到使用numbers table 并不太复杂,并且在两个/许多平台上都运行良好且快速:

    CREATE TABLE integers (i integer);
    INSERT INTO integers (i) VALUES (0);
    INSERT INTO integers (i) VALUES (1);
    ...
    INSERT INTO integers (i) VALUES (9);
    SELECT (hundreds.i * 100) + (tens.i * 10) + units.i AS x
    FROM integers AS units
      CROSS JOIN integers AS tens
      CROSS JOIN integers AS hundreds
    

    您只需创建此表一次,即可在需要一系列数字时使用它。

    【讨论】:

      【解决方案4】:

      其他一些替代方案(在 postgres 中尝试过,但应该与其他人一起使用)

      select (0) as count union values (1),(2),(3),(4),(5)

      用代码扩展这个 sql 将是直截了当的。

      【讨论】:

        【解决方案5】:

        这对我来说适用于 MS SQL。这有点作弊,因为它要求您要查询的表的行数至少与您要返回的数字数量一样多。在我的例子中,我只想要一个包含五个优先级的列表,我可以将其绑定到一个下拉列表 - 但鉴于其他相关 UI 元素的工作方式,它必须来自 SQL:

        SELECT WDPRIORITY, 
               CAST('Priority ' + LTRIM(STR(WDPRIORITY)) AS CHAR(16)) AS TXPRIORITY
          FROM (
                 SELECT TOP 5 ROW_NUMBER() OVER(ORDER BY WDVALUE ASC) AS WDPRIORITY
                   FROM VMIPRS
               ) AS VMPRIORITY
        

        【讨论】:

          【解决方案6】:

          如果数量有限,我会选择:

          SELECT
              *
          FROM (VALUES (1),(2), (3))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-04
            • 1970-01-01
            • 2021-12-30
            • 1970-01-01
            • 2010-10-03
            • 2013-02-18
            相关资源
            最近更新 更多