您好我是SQL的初学者,尤其是postgresql。 我有一张看起来像这样的表:
ID | Entity | Startdate | enddate
------| ------ | ------ | ------
1 | Hospital |2013-01-01 |2013-01-31
1 | Clinic |2013-02-01 |2013-04-30
1 | Hospital |2013-05-01 |2013-05-31
在这种情况下,我想做的是,开始和结束日期超过一个月,以便将其分解,所以上表是这样的:
ID | Entity | Startdate | enddate
------| ------ | ------ | ------
1 | Hospital |2013-01-01 |2013-01-31
1 | Clinic |2013-02-01 |2013-02-29
1 | Clinic |2013-03-01 |2013-03-31
1 | Clinic |2013-04-01 |2013-04-30
1 | Hospital |2013-05-01 |2013-05-31
如果您注意到第2,3和4行已按月分解,并且ID和实体也已重复。
有关如何在postgresql中运行此任何建议将不胜感激。
P.S道歉我正试图弄清楚如何正确创建上面的表格。遇到困难时,数字和单词之间的管道是表格中的线条。 希望它不要太混乱。
答案 0 :(得分:0)
这样做的一种方法是创建一个end_of_month函数,如下所示:
CREATE FUNCTION end_of_month(date)
RETURNS date AS
$BODY$
select (date_trunc('month', $1) + interval '1 month' - interval '1 day')::date;
$BODY$
LANGUAGE sql IMMUTABLE STRICT
COST 100;
然后你可以得到一个像这样的UNIONS字符串:
SELECT
id,
entity,
startdate,
least(end_of_month(startdate),enddate) enddate
from hospital
union
SELECT
id,
entity,
startdate,
least(end_of_month((startdate + interval '1 month')::date),enddate) enddate
from hospital
union
id,
entity,
startdate,
least(end_of_month((startdate + interval '1 month')::date),enddate) enddate
from hospital
ORDER BY startdate,enddate
这种方法的问题在于你需要拥有尽可能多的工会!
另一种方法是使用游标。
编辑
想到另一个(更好的)非游标解决方案。创建月末日期表。然后你可以简单地做:
select h.id,
h.entity,
h.startdate,
least(h.enddate, m.enddate) enddate
from hospital h
INNER JOIN monthends m
ON m.enddate > h.startdate and m.enddate <= end_of_month(h.enddate)
ORDER BY startdate, enddate
答案 1 :(得分:0)
以下是如何根据数据克隆行的示例:
-- Demo data begin
with t(i,x,y) as (values
(1, '2013-02-03'::date, '2013-04-27'::date),
(2, current_date, current_date))
-- Demo data end
select
*,
greatest(x, z)::date as x1, least(y, z + '1 month - 1 day'::interval)::date as y1
from
t,
generate_series(date_trunc('month', x)::date, date_trunc('month', y)::date, '1 month') as z;
┌───┬────────────┬────────────┬────────────────────────┬────────────┬────────────┐ │ i │ x │ y │ z │ x1 │ y1 │ ╞═══╪════════════╪════════════╪════════════════════════╪════════════╪════════════╡ │ 1 │ 2013-02-03 │ 2013-04-27 │ 2013-02-01 00:00:00+02 │ 2013-02-03 │ 2013-02-28 │ │ 1 │ 2013-02-03 │ 2013-04-27 │ 2013-03-01 00:00:00+02 │ 2013-03-01 │ 2013-03-31 │ │ 1 │ 2013-02-03 │ 2013-04-27 │ 2013-04-01 00:00:00+03 │ 2013-04-01 │ 2013-04-27 │ │ 2 │ 2017-08-27 │ 2017-08-27 │ 2017-08-01 00:00:00+03 │ 2017-08-27 │ 2017-08-27 │ └───┴────────────┴────────────┴────────────────────────┴────────────┴────────────┘
只需删除Demo data
阻止,然后用您的表/列名称替换t
,x
和y
。
说明:
least()
和greatest()
函数相应地返回最小和最大元素。 Link
generate_series(v1,v2,d)
函数会返回以v1
开头的一系列值,而不是v2
与步骤d
的最大值。 Link
'1 month - 1 day'::interval
- interval
数据类型表示法,<value>::<datatype>
表示显式类型转换,SQL标准等效项为cast(<value> as <datatype>)
。 Link和link
date_trunc()
函数将日期/时间戳值截断为指定的精度。 Link