3

週末と休日の日付が保持される OffDays というテーブルがあります。製品が製造されるまでの時間 (日数) が保存される LeadTime というテーブルがあります。最後に、製品と注文日が保持される Order というテーブルがあります。

ストアド プロシージャやループを使用せずに、製品の製造がいつ終了するかを問い合わせることはできますか?

例えば:

  • OffDays には 2008-01-10、2008-01-11、2008-01-14 があります。
  • 製品 9 の LeadTime は 5 です。
  • 製品 9 の注文は 2008 年 1 月 9 日です。

私が探している計算はこれです:

  • 2008-01-09 1
  • 2008 年 1 月 10 日 x
  • 2008 年 1 月 11 日 x
  • 2008-01-12 2
  • 2008-01-13 3
  • 2008 年 1 月 14 日 ×
  • 2008-01-15 4
  • 2008-01-16 5

ストアド プロシージャを使用したり、アプリケーション コードで計算したりしなくても、クエリで 2008-01-16 を返すことができるかどうか疑問に思っています。

編集 (ストアド プロシージャ/ループ がない理由): ストアド プロシージャを使用できない理由は、それらがデータベースでサポートされていないためです。テーブル/データを追加することしかできません。このアプリケーションは、SQL クエリのみを制御できるサード パーティのレポート ツールです。

編集(現在のやり方): 私の現在の方法は、注文テーブルに計算された日付を保持するための追加の列があり、スケジュールされたタスク/ cronジョブがすべての注文で毎時間計算を実行することです。これは、いくつかの理由で理想的とは言えません。

4

8 に答える 8

2

最善の方法は、Calendar テーブルを使用することです。

http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.htmlを参照してください。

次に、クエリは次のようになります。

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。

于 2008-09-18T13:55:13.663 に答える
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 テーブルを生成するにはループを含むストアド プロシージャが必要ですが、通常のクエリには必要ありません。また、アプリケーション コードを使用して日数をカウントする場合よりも、サーバーへのラウンド トリップが少なくなります。

于 2008-09-18T14:04:37.773 に答える
1

アプリケーションコードで計算するだけです...はるかに簡単で、SQLで本当に醜いクエリを書く必要はありません

于 2008-09-18T13:53:40.517 に答える
1

here's one way - using the dateadd function.

I need to take this answer off the table. This isn't going to work properly for long lead times. It was simply adding the # of off days found in the lead time and pushing the date out. This will cause a problem when more off days show up in the new range.

-- 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
于 2008-09-18T14:42:06.170 に答える
0

なぜループの使用に反対するのですか?

//擬似コード

int leadtime = 5;
date order = 2008-01-09;
date finishdate = order;
while (leadtime > 0) {
finishdate.addDay();
if (!IsOffday(finishdate)) leadtime--;
}
return finishdate;

これは、ループしない方法を見つけるには単純すぎる関数のようです。

于 2008-09-18T13:59:39.470 に答える
0

うーん.. 1つの解決策は、年の初めからの非休日の数に基づいたオフセットを使用して日付のテーブルを保存することです。ジャンとしましょう。2日はお休みです。1/1/08 のオフセットは 1 (0 から開始する場合は 0) になります。カウントが 1/2/08 をスキップするため、1/3/08 のオフセットは 2 になります。そこからは簡単な計算です。注文日のオフセットを取得し、リード タイムを追加してから、計算されたオフセットを参照して終了日を取得します。

于 2008-09-18T14:03:54.267 に答える
0

1 つの方法 (別のテーブルを作成せずに) は、一種の上限関数を使用することです。オフデートごとに、サブクエリで、注文日と比較して、それより前に来る "オン日" の数を調べます。次に、リード タイムより短い最大数を取得します。それに対応する日付と残りを使用します。

このコードは 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;
于 2008-09-18T14:49:07.590 に答える
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

これは、休業日テーブル (注文番号 3) の最終日以降に終了する注文の結果を返さないため、時間通りに休業日を挿入するように注意する必要があります。注文は休業日に開始されないことが想定されています。

于 2008-09-18T18:22:44.643 に答える