变量日期格式查询

时间:2017-12-20 23:54:30

标签: sql postgresql date psql

我试图将从PostgreSQL表中提取的字符串(使用索引聚合数组)转换为正确格式化的日期以进行查询。我的问题是我的日期格式有所不同,包括YYYY,Mon YYYY和DD Mon YYYY。我的计划是创建日期范围以包含由模糊日期表示的所有可能时间。例如," 2000"将被转换为" 2000年1月1日"和" 2000年12月31日"并根据自定义输入日期范围进行测试。同样," 2014年2月"将更改为" 2014年2月1日"和" 2014年2月28日"。 (注意 - 我目前无法想办法考虑闰年)

我目前使用的方法涉及简单的字符串连接。但是,我需要能够区分字符串长度(这将指示日期格式),并且我努力将条件表达式合并到我的查询中。这就是我现在所得到的:

SELECT a.accession, string_agg(b.value, ' | ') AS bvalue_list, c.name, d.description, string_agg(e.value, ' | ') AS evalue_list, f.seqlen, f.residues 
FROM dbxref a INNER JOIN dbxrefprop b ON a.dbxref_id = b.dbxref_id
INNER JOIN biomaterial d ON b.dbxref_id = d.dbxref_id
INNER JOIN feature f ON d.dbxref_id = f.dbxref_id
INNER JOIN biomaterialprop e ON d.biomaterial_id = e.biomaterial_id
INNER JOIN contact c ON d.biosourceprovider_id = c.contact_id
GROUP BY a.accession, c.name, d.description, f.seqlen, f.residues
HAVING ((array_agg(b.value))[5] = 'source018' OR (array_agg(b.value))[5] = 'source015')
AND to_date('04 Jan ' || (array_agg(e.value))[3], 'DD Mon YYYY') BETWEEN '01 Jan 1999' AND '31 Jan 2000';

我为疯狂的查询语句道歉。我想完整地展示声明,因为它的怪癖(其中信息由" HAVING"条款处理,而不是" WHERE")。相关部分(最底行)归结为选择表示字符串格式的时间的索引聚合。我的搜索条件有意过滤掉了不符合所使用的连接方法的日期(不包括Mon YYYY和DD Mon YYYY日期)。我一直试图加入一个" CASE"条件,但我不确定是否/如何使其适合现有查询。

简化问题

我需要修改以下查询:

SELECT e.biomaterial_id, string_agg(e.value, ' | ') AS evalue_list
FROM biomaterialprop e
GROUP BY e.biomaterial_id;

产生:

 biomaterial_id |                  evalue_list                   
----------------+------------------------------------------------
              8 | NULL | Feb 2002 | Canada | T2
              4 | NULL | 03 Mar 2008 | Hainan, China | T2
              5 | nasal swab | Oct 2010 | Fujian, China | T1
             11 | nasal swab | 10 Apr 2014 | Nebraska, USA | T1
              3 | lung tissue | 01 Jan 2005 | Nebraska, USA | T2
             10 | lung tissue | 2005 | USA | T2
              9 | serum | 2001 | Ohio, USA | T1
              6 | serum | 2000 | Utah, USA | T1
              2 | serum | 01 Jan 2005 | Iowa, USA | T1
              7 | NULL | 02 Aug 1998 | Alberta, Canada | T2

我可以通过索引用(array_agg(e.value))[3]来选择日期字段。接下来我需要修改日期字符串并将它们插入到单独的输出列中。我认为它应该看起来像这样(目前没有工作):

SELECT e.biomaterial_id, string_agg(e.value, ' | ') AS evalue_list,
  CASE char_length((array_agg(e.value))[3])
    WHEN 11 
    THEN to_date((array_agg(e.value))[3], 'DD Mon YYYY')
    WHEN 8 
    THEN to_date('01 ' || (array_agg(e.value))[3], 'DD Mon YYYY')
    ELSE to_date('01 Jan ' || (array_agg(e.value))[3], 'DD Mon YYYY')
  END
  AS date1
  CASE char_length((array_agg(e.value))[3])
    WHEN 11 
    THEN to_date((array_agg(e.value))[3], 'DD Mon YYYY')
    WHEN 8 
    THEN last_day(to_date('01 ' || (array_agg(e.value))[3], 'DD Mon YYYY'))
    ELSE to_date('31 Dec ' || (array_agg(e.value))[3], 'DD Mon YYYY')
  END
  AS date2
FROM biomaterialprop e
GROUP BY e.biomaterial_id, date1, date2;

我试图从这个堆栈帖子中重现答案的查询结构: IF-THEN-ELSE statements in postgresql

Edit1 - 已经过了好几个月了,我想我至少对SQL更有能力。也就是说,我真的不满意这个旧的解决方案。任何其他建议或解决方案都会有所帮助。

演示包含时间信息的表格:

specimen_collection_date 
--------------------------
 01-Nov-2013
 2013
 2012
 04-Jul-2013
 16-Jan-2011
 Jan-2011
 2001
 Nov-2005

1 个答案:

答案 0 :(得分:0)

回答简化问题

代码:

create or replace function last_day(date) returns date as 'select 
cast(date_trunc(''month'', $1) + ''1 month''::interval as date) - 1' 
language sql;

SET search_path = chado;
SELECT specimen_collection_date,
  CASE
    WHEN char_length(specimen_collection_date) = 11
    THEN to_date(specimen_collection_date, 'DD Mon YYYY')
    WHEN char_length(specimen_collection_date) = 8 
    THEN to_date('01 ' || specimen_collection_date, 'DD Mon YYYY')
    ELSE to_date('01 Jan ' || specimen_collection_date, 'DD Mon YYYY')
  END
  AS date1,
  CASE
    WHEN char_length(specimen_collection_date) = 11 
    THEN to_date(specimen_collection_date, 'DD Mon YYYY')
    WHEN char_length(specimen_collection_date) = 8 
    THEN last_day(to_date('01 ' || specimen_collection_date, 'DD Mon YYYY'))
    ELSE to_date('31 Dec ' || specimen_collection_date, 'DD Mon YYYY')
  END
  AS date2
FROM prrsv_search_mv WHERE specimen_collection_date != '';

输出:

 specimen_collection_date |   date1    |   date2    
--------------------------+------------+------------
 01-Nov-2013              | 2013-11-01 | 2013-11-01
 2013                     | 2013-01-01 | 2013-12-31
 2012                     | 2012-01-01 | 2012-12-31
 04-Jul-2013              | 2013-07-04 | 2013-07-04
 16-Jan-2011              | 2011-01-16 | 2011-01-16
 Jan-2011                 | 2011-01-01 | 2011-01-31
 2001                     | 2001-01-01 | 2001-12-31
 Nov-2005                 | 2005-11-01 | 2005-11-30

因为PostgreSQL没有last_day函数,所以必须自定义(来源:https://www.postgresql.org/message-id/Pine.LNX.4.44.0309021522180.17073-100000%40kix.fsv.cvut.cz)。

Edit1 - 更新当前答案以匹配最近的问题编辑。