返回年份数组作为年份范围

Posted

技术标签:

【中文标题】返回年份数组作为年份范围【英文标题】:Return array of years as year ranges 【发布时间】:2013-07-08 17:58:38 【问题描述】:

我正在尝试查询包含character varying[] 年份列的表,并将这些年份作为逗号分隔的年份范围字符串返回。年份范围将由数组中存在的连续年份确定,不连续的年份/年份范围应以逗号分隔。

数据类型是character varying[] 而不是integer[] 的原因是因为一些值包含ALL 而不是年份列表。我们可以省略这些结果。

到目前为止,我几乎没有运气解决这个问题,因为我什至不确定从哪里开始。

谁能给我一些指导或提供一个有用的例子来说明如何解决诸如挑战之类的问题?

years_table 示例

+=========+============================+
| id      | years                      |
| integer | character varying[]        |
+=========+============================+
| 1       | ALL                      |
| 2       | 1999,2000,2010,2011,2012 |
| 3       | 1990,1991,2007           |
+---------+----------------------------+

输出目标:

示例 SQL 查询:

SELECT id, [year concat logic] AS year_ranges
FROM years_table WHERE 'ALL' NOT IN years

结果:

+====+======================+
| id | year_ranges          |
+====+======================+
| 2  | 1999-2000, 2010-2012 |
| 3  | 1990-1991, 2007      |
+----+----------------------+

【问题讨论】:

是什么决定了 1999-2000 年与 2010-2012 年之间的跳跃?假设我没有忽略某些内容,我认为您需要更清楚地解释范围。 抱歉,我已经修改了介绍性句子,并留下了一些非常需要的细节。已编辑。本质上,我正在尝试从连续的年份范围中创建年份范围。 2000,2001,2002 将返回 2000-2002。不连续的年/年范围将返回以逗号分隔。例如:2000,2002 将返回 2000, 20022000,2001,2002,2005,2006,2008 将返回 2000-2002, 2005-2006, 2008 我必须跑一会儿,但立即想到的一个想法是使用 LAG 或 LEAD postgresql.org/docs/current/static/functions-window.html 【参考方案1】:
SELECT id, string_agg(year_range, ', ') AS year_ranges
FROM (
   SELECT id, CASE WHEN count(*) > 1
               THEN min(year)::text || '-' ||  max(year)::text 
               ELSE min(year)::text
              END AS year_range
   FROM  (
      SELECT *, row_number() OVER (ORDER BY id, year) - year AS grp
      FROM  (
         SELECT id, unnest(years) AS year
         FROM  (VALUES (2::int, '1999,2000,2010,2011,2012'::int[])
                      ,(3,      '1990,1991,2007')
               ) AS tbl(id, years)
         ) sub1
      ) sub2
   GROUP  BY id, grp
   ORDER  BY id, min(year)
   ) sub3
GROUP  BY id
ORDER  BY id

产生完全所需的结果。

如果您处理一组 varchar (varchar[],只需将其转换为 int[],然后再继续。这似乎是完全合法的形式:

years::int[]

将内部子选择替换为生产代码中源表的名称。

 FROM  (VALUES (2::int, '1999,2000,2010,2011,2012'::int[])
              ,(3,      '1990,1991,2007')
       ) AS tbl(id, years)

->

FROM  tbl

由于我们处理的是一个自然升序的数字(年份),我们可以使用快捷方式来形成连续年份的组(形成一个范围)。我从行号中减去年份本身(按年份排序)。对于连续的年份,行号和年份都增加 1 并产生相同的 grp 数字。否则,将开始一个新的范围。

在手册here 和here 中详细了解窗口函数

在这种情况下,plpgsql 函数可能会更快。你必须测试。这些相关答案中的示例:Ordered count of consecutive repeats / duplicatesROW_NUMBER() shows unexpected values

【讨论】:

It fails it I add this value: ,(4, '2010,2011') @JoshuaBurns:注意修复。 啊哈,看来你最近的更新搞定了:sqlfiddle.com/#!12/a1227/14 先生真是太棒了。非常感谢您花时间提供这样一个简洁的例子。现在是时候了解更多关于row_number() OVER 的信息了。 :) @JoshuaBurns:我添加了手册链接,让您开始使用窗口功能。【参考方案2】:

SQL Fiddle不是您要求的输出格式,但我认为它可能更有用:

select id, g, min(year), max(year)
from (
    select id, year,
        count(not g or null) over(partition by id order by year) as g
    from (
        select id, year,
            lag(year, 1, 0) over(partition by id order by year) = year - 1 as g
        from (
            select id, unnest(years)::integer as year
            from years
            where years != 'ALL'
        ) s
    ) s
) s
group by 1, 2

【讨论】:

以上是关于返回年份数组作为年份范围的主要内容,如果未能解决你的问题,请参考以下文章

Iphone:如何将年份添加到当前日期并将其作为字符串返回,格式为 2011-11-20

日期之间的日期,忽略年份

RDBMS:计算并打印返回日期、返回月份和返回年份 [关闭]

在excel中检查年份=年份的问题

使用给定的参考年份计算给定日期的周数

BootStrap 年份范围