我有一张名为OffDays的桌子,周末和假日日期都保存在这里。我有一个名为LeadTime的表,其中存储了要生产的产品的时间量(以天为单位)。最后,我有一个名为Order的表,其中保留了产品和订单日期。
是否可以在不使用存储过程或循环的情况下查询产品何时完成制造?
例如:
我正在寻找的计算是:
我想知道是否可以让查询返回2008-01-16而不必使用存储过程,或者在我的应用程序代码中计算它。
编辑(为什么没有存储过程/循环): 我无法使用存储过程的原因是数据库不支持它们。我只能添加额外的表/数据。该应用程序是第三方报告工具,我只能控制SQL查询。
编辑(我现在是怎么做的): 我当前的方法是在订单表中有一个额外的列来保存计算的日期,然后计划的任务/ cron作业每小时运行所有订单的计算。由于几个原因,这不太理想。
答案 0 :(得分:2)
最好的方法是使用Calendar表。
然后您的查询可能类似于:
SELECT c.dt, l.*, o.*, c.*
FROM [statistics].dbo.[calendar] c,
[order] o JOIN
lead l ON l.leadId = o.leadId
WHERE c.isWeekday = 1
AND c.isHoliday =0
AND o.orderId = 1
AND l.leadDays = (
SELECT COUNT(*)
FROM [statistics].dbo.Calendar c2
WHERE c2.dt >= o.startDate
AND c2.dt <= c.dt
AND c2.isWeekday=1
AND c2.isHoliday=0
)
希望有所帮助,
RB。
答案 1 :(得分:2)
您可以提前生成一个工作日表。
WDId | WDDate
-----+-----------
4200 | 2008-01-08
4201 | 2008-01-09
4202 | 2008-01-12
4203 | 2008-01-13
4204 | 2008-01-16
4205 | 2008-01-17
然后执行查询,例如
SELECT DeliveryDay.WDDate FROM WorkingDay OrderDay, WorkingDay DeliveryDay, LeadTime, Order where DeliveryDay.WDId = OrderDay.WDId + LeadTime.LTDays AND OrderDay.WDDate = '' AND LeadTime.ProductId = Order.ProductId AND Order.OrderId = 1234
您需要一个带循环的存储过程来生成WorkingDays表,但不需要常规查询。与使用应用程序代码计算天数相比,它到服务器的往返次数也更少。
答案 2 :(得分:1)
只需在应用程序代码中计算它......就更容易了,你不必在你的sql中编写一个非常难看的查询
答案 3 :(得分:1)
这是一种方法 - 使用dateadd函数。
我需要把这个答案从桌子上拿下来。这对于较长的交付周期来说无法正常工作。它只是添加了在提前期中找到的关闭天数并将日期推出。当在新范围内出现更多关闭天数时,这将导致问题。
-- Setup test
create table #odays (offd datetime)
create table #leadtime (pid int , ltime int)
create table [#order] (pid int, odate datetime)
insert into #odays
select '1/10/8'
insert into #odays
select '1/11/8'
insert into #odays
select '1/14/8'
insert into #Leadtime
values (3,5)
insert into #leadtime
values (9, 5)
insert into #order
values( 9, '1/9/8')
select dateadd(dd,
(select count(*)-1
from #odays
where offd between odate and
(select odate+ltime
from #order o
left join #leadtime l
on o.pid = l.pid
where l.pid = 9
)
),
odate+ltime)
from #order o
left join #leadtime l
on o.pid = l.pid
where o.pid = 9
答案 4 :(得分:0)
你为什么反对使用循环?
//一些伪代码
int leadtime = 5;
date order = 2008-01-09;
date finishdate = order;
while (leadtime > 0) {
finishdate.addDay();
if (!IsOffday(finishdate)) leadtime--;
}
return finishdate;
这似乎是一个太简单的功能,试图找到一种非循环方式。
答案 5 :(得分:0)
嗯..一个解决方案可能是存储一个日期表,其中的偏移量基于从年初开始的非关闭天数。让我们说吧。 2是休息日。 1/1/08的偏移量为1(如果你想从0开始则为0)。 1/3/08的偏移量为2,因为计数跳过1/2/08。从那里进行简单的计算。获取订单日期的偏移量,添加提前期,然后对计算的偏移量进行查找以获得结束日期。
答案 6 :(得分:0)
一种方式(不创建另一个表)使用一种天花板功能:对于每个offdate,在子查询中找出相对于订单日期有多少“on date”。然后取出小于提前期的最高数字。使用与之对应的日期加上余数。
此代码可能特定于PostgreSQL,如果那不是您正在使用的内容,那就很抱歉。
CREATE DATABASE test;
CREATE TABLE offdays
(
offdate date NOT NULL,
CONSTRAINT offdays_pkey PRIMARY KEY (offdate)
);
insert into offdays (offdate) values ('2008-01-10');
insert into offdays (offdate) values ('2008-01-11');
insert into offdays (offdate) values ('2008-01-14');
insert into offdays (offdate) values ('2008-01-18'); -- just for testing
CREATE TABLE product
(
id integer NOT NULL,
CONSTRAINT product_pkey PRIMARY KEY (id)
);
insert into product (id) values (9);
CREATE TABLE leadtime
(
product integer NOT NULL,
leaddays integer NOT NULL,
CONSTRAINT leadtime_pkey PRIMARY KEY (product),
CONSTRAINT leadtime_product_fkey FOREIGN KEY (product)
REFERENCES product (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
insert into leadtime (product, leaddays) values (9, 5);
CREATE TABLE "order"
(
product integer NOT NULL,
"start" date NOT NULL,
CONSTRAINT order_pkey PRIMARY KEY (product),
CONSTRAINT order_product_fkey FOREIGN KEY (product)
REFERENCES product (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
insert into "order" (product, "start") values (9, '2008-01-09');
-- finally, the query:
select e.product, offdate + (leaddays - ondays)::integer as "end"
from
(
select c.product, offdate, (select (a.offdate - c."start") - count(b.offdate) from offdays b where b.offdate < a.offdate) as ondays, d.leaddays
from offdays a, "order" c
inner join leadtime d on d.product = c.product
) e
where leaddays >= ondays
order by "end" desc
limit 1;
答案 7 :(得分:0)
这是PostgreSQL语法,但应该很容易翻译成其他SQL方言
--Sample data
create table offdays(datum date);
insert into offdays(datum)
select to_date('2008-01-10','yyyy-MM-dd') UNION
select to_date('2008-01-11','yyyy-MM-dd') UNION
select to_date('2008-01-14','yyyy-MM-dd') UNION
select to_date('2008-01-20','yyyy-MM-dd') UNION
select to_date('2008-01-21','yyyy-MM-dd') UNION
select to_date('2008-01-26','yyyy-MM-dd');
create table leadtime (product_id integer , lead_time integer);
insert into leadtime(product_id,lead_time) values (9,5);
create table myorder (order_id integer,product_id integer, datum date);
insert into myorder(order_id,product_id,datum)
values (1,9,to_date('2008-01-09','yyyy-MM-dd'));
insert into myorder(order_id,product_id,datum)
values (2,9,to_date('2008-01-16','yyyy-MM-dd'));
insert into myorder(order_id,product_id,datum)
values (3,9,to_date('2008-01-23','yyyy-MM-dd'));
--Query
select order_id,min(finished_date)
FROM
(select mo.order_id,(mo.datum+lead_time+count(od2.*)::integer-1) as finished_date
from
myorder mo
join leadtime lt on (mo.product_id=lt.product_id)
join offdays od1 on (mo.datum<od1.datum)
left outer join offdays od2 on (mo.datum<od2.datum and od2.datum<od1.datum)
group by mo.order_id,mo.datum,lt.lead_time,od1.datum
having (mo.datum+lead_time+count(od2.*)::integer-1) < od1.datum) tmp
group by 1;
--Results :
1 2008.01.16
2 2008.01.22
对于将在offdays表(订单号3)的最后一个日期之后完成的订单,不会返回结果,因此您必须注意按时插入工作日。假设订单执行不要在休息日开始。