我正在运行一个简单的查询,以便从我们的销售中获得每周收入
SELECT date_trunc('week', payment_date) AS week, sum(payment_amount)
FROM payment
WHERE payment_date BETWEEN '2010-jan-1' AND '2016-dec-31'
GROUP BY week
现在我需要每周的开始和结束日期为静态。一年中所有52周都需要计算,例如
Week 1: Jan 1-7
Week 2: Jan8-14
Week 3: Jan15-21
Week 4: Jan22-28
Week 5: Jan29-Feb4 and so forth
我做了一些调查并发现我需要使用payment_date
作为参数的用户定义函数并返回一周值。然后,我可以在上面的SQL查询中调用此函数,代替date_trunc()
函数。
如何使用增量循环为payment_date
分配周值?
我还可以在SQL查询的group by子句中使用此返回值吗?
由于我具有基本的SQL中间知识,因此我将高度赞赏一些详细示例的解释。
---------------编辑--------------
我现在尝试使用2个功能来考虑闰年,我仍然希望将3月4日纳入第9周。香港专业教育学院尝试使用& klin的功能并将其转换为SQL,我一直在" int'在第9行。我的代码如下。
创建或替换函数is_leap_year(int)
返回布尔语言sql为$$
select $1 % 4 = 0 and ($1 % 100 <> 0 or $1 % 400 = 0)
$$;
创建或替换函数week_no(timestamp)
将int language sql作为$ body $
返回声明 y int; day_shift int; 开始
y = extract(year from $1);
day_shift = 1 + (is_leap_year(y) and $1 > make_date(y, 2, 28))::int;
return ((extract(doy from $1)::int)- day_shift) / 7+ 1;
端
$ $体;
选择week_no(payment_date)作为week_number,sum(payment_amount)
从付款p加入pay_event pe on p.payment_event_id = pe.payment_event_id
其中payment_date介于&#39; 2016-jan-1&#39;和&#39; 2017-jan-1&#39; 和pe.payment_event_type_id!= 2
按周数分组
按week_number排序
答案 0 :(得分:1)
首先,您的要求存在问题。
现在我需要每周的开始和结束日期为静态。
他们不可能。闰年发生了。 2月29日将每四年中的开始和结束日期改变一年,或者您需要允许一周有八天。
一年中所有52周都需要定制。 。 。
我认为你的意思是所有52周都需要计算。但是52 * 7 = 364.你错过了一天。
我认为从日期计算周数的最简单表达式是(extract(doy from payment_date)::integer / 7) as week
。我不知道是否值得将它放入一个函数中。相反,我可能首先创建一个使用该表达式的视图。
但计算不会对2月29日做任何特别的事情,或者每年有超过52 * 7天的事实。
我认为你最好的选择是建立一个表而不是使用计算。
create table weeks (
calendar_date date primary key,
week_num integer not null
check (week_num between 1 and 53)
);
使用此日期填充2016年和2017年,并使用计算周,为我们提供一个起点。 (2016年是闰年。)
insert into weeks
select
('2016-01-01'::date + (n || ' days')::interval)::date as calendar_date
, extract(doy from ('2016-01-01'::date + (n || ' days')::interval)::date)::integer / 7 + 1 as calencar_week
from generate_series (0, 730) n;
让我们看看第9周。
select *
from weeks
where week_num = 9
order by calendar_date;
calendar_date week_num -- 2016-02-25 9 2016-02-26 9 2016-02-27 9 2016-02-28 9 2016-02-29 9 2016-03-01 9 2016-03-02 9 2017-02-25 9 2017-02-26 9 2017-02-27 9 2017-02-28 9 2017-03-01 9 2017-03-02 9 2017-03-03 9
2016年,计算第9周从2016-02-25到2016-03-02。 2017年,它从2016-02-25到2017-03-03。但是现在所有这些周数都在一个表中,你可以按照自己喜欢的方式调整它们。如果有意义的话,你甚至可以每年更改一次调整。
答案 1 :(得分:0)
通过将问题分解为月 - 日字符串,您可以在多年内使用相同的逻辑
mysql> SELECT "01-07" < "01-08";
+-------------------+
| "01-07" < "01-08" |
+-------------------+
| 1 |
+-------------------+
1 row in set (0.08 sec)
%m-%d
的简单日期格式用于将付款日期与您要分配的星期数据库进行比较。
要手动分配所有52周范围,您可以使用案例陈述:
SET @md_format="%m-%d";
SELECT
CASE
WHEN (date_format(`input_date`, @md_format) < "01-08") THEN 1
WHEN (date_format(`input_date`, @md_format) < "01-15") THEN 2
WHEN (date_format(`input_date`, @md_format) < "01-22") THEN 3
-- ... All other cases
ELSE 52
END;
See the docs for the syntax to define a function
函数将允许您执行以下操作:
SELECT week_bucket(payment_date) `week`, SUM(revenue) `revenue`
FROM my_table
WHERE week_bucket(payment_date) > 13
AND week_bucket(payment_date) < 15
GROUP BY `week`;
答案 2 :(得分:0)
以这样的方式使用doy
(一年中的某一天):
create or replace function week_no(date)
returns int language sql as $$
select ((extract(doy from $1)::int)- 1) / 7+ 1
$$;
with the_table(a_date) as (
values
('2017-01-01'::date),
('2017-01-07'),
('2017-01-08'),
('2017-01-14'),
('2017-01-15'),
('2017-01-22')
)
select extract(doy from a_date)::int as doy, week_no(a_date)
from the_table;
doy | week_no
-----+---------
1 | 1
7 | 1
8 | 2
14 | 2
15 | 3
22 | 4
(6 rows)
如果你想更正周数,以便3月4日总是在第9周(即使在闰年),使用这个方便的功能:
create or replace function is_leap_year(int)
returns boolean language sql as $$
select $1 % 4 = 0 and ($1 % 100 <> 0 or $1 % 400 = 0)
$$;
您的函数可能看起来像这样(我使用了plpgsql语言以获得更好的可读性,尽管这也可以编码为sql函数):
create or replace function week_no_corrected(date)
returns int language plpgsql as $$
declare
y int = extract (year from $1);
day_shift int = 1 + (is_leap_year(y) and $1 > make_date(y, 2, 28))::int;
begin
return ((extract(doy from $1)::int)- day_shift) / 7+ 1;
end;
$$;
with the_table(a_date) as (
values
('2016-03-03'::date),
('2016-03-04'),
('2016-03-05'),
('2017-03-03'),
('2017-03-04'),
('2017-03-05')
)
select a_date, week_no(a_date), week_no_corrected(a_date)
from the_table;
a_date | week_no | week_no_corrected
------------+---------+-------------------
2016-03-03 | 9 | 9
2016-03-04 | 10 | 9
2016-03-05 | 10 | 10
2017-03-03 | 9 | 9
2017-03-04 | 9 | 9
2017-03-05 | 10 | 10
(6 rows)
在SQL函数中,您不能使用变量,分配可能会被派生表替换:
create or replace function week_no_corrected(date)
returns int language sql as $$
select ((extract(doy from $1)::int)- day_shift) / 7 + 1
from (
select 1 + (is_leap_year(y) and $1 > make_date(y, 2, 28))::int as day_shift
from (
select extract (year from $1)::int as y
) s
) s
$$;