2016-10-11 9 views
2

私は2つのクエリを持っています。各照会は、組織と顧客の間の合計発注数、および発注の受注総額を引き出します。クエリは日付範囲を除いて同一です。1つのSQLクエリで複数の日付範囲からデータを取得するにはどうすればよいですか?

SELECT org.organization_id, org.name, cust.name as customer, 
count(*) as num_orders, round (sum(cast(o.total_charge as real))) as receivables 
FROM 
organization as org, orders as o, organization as cust, reconcile_order as ro 
WHERE org.organization_id = o.shipper_org_id 
and o.broker_org_id = cust.organization_id 
and o.order_id = ro.order_id 
and o.status = 'D' 
and (ro.receive_payment_in_full = 0 or ro.receive_payment_in_full is NULL) 
and (NOW()::DATE - o.delivery_confirmed_date::DATE) < 31 
group by org.organization_id, org.name, 
cust.name 
order by org.name asc limit 20 

SELECT org.organization_id, org.name, cust.name as customer, 
count(*) as num_orders, round (sum(cast(o.total_charge as real))) as receivables 
FROM 
organization as org, orders as o, organization as cust, reconcile_order as ro 
WHERE org.organization_id = o.shipper_org_id 
and o.broker_org_id = cust.organization_id 
and o.order_id = ro.order_id 
and o.status = 'D' 
and (ro.receive_payment_in_full = 0 or ro.receive_payment_in_full is NULL) 
and (NOW()::DATE - o.delivery_confirmed_date::DATE) between 31 and 60 
group by org.organization_id, org.name, 
cust.name 
order by org.name asc limit 20 

しかし、私はこれらの列の隣の第二日付範囲の列の別のペアを出力するが、最初の日付の範囲内の注文や債権のための列を持つ単一のテーブルであるように、この1つのクエリを作成する必要があり、そして。 (すなわちnum_orders < 31、債権< 31、num_orders 31から60、債権31〜60)

+0

http://stackoverflow.com/q/39919206/330315 –

答えて

0

イム私はあなたの正確な質問を理解していることを確認し、どのようにこの程度ではない:

Select earlier_ones.organization_id,earlier_ones.organization_id, name, customer, earlier_ones.receivables, later_ones.receivables 
FROM (
    SELECT org.organization_id, org.name, cust.name as customer, 
    count(*) as num_orders, round (sum(cast(o.total_charge as real))) as receivables 
    FROM 
    organization as org, orders as o, organization as cust, reconcile_order as ro 
    WHERE org.organization_id = o.shipper_org_id 
    and o.broker_org_id = cust.organization_id 
    and o.order_id = ro.order_id 
    and o.status = 'D' 
    and (ro.receive_payment_in_full = 0 or ro.receive_payment_in_full is NULL) 
    and (NOW()::DATE - o.delivery_confirmed_date::DATE) < 31 
    group by org.organization_id, org.name, 
    cust.name 
    order by org.name asc limit 20 
) earlier_ones 
LEFT JOIN (
    SELECT org.organization_id, org.name, cust.name as customer, 
    count(*) as num_orders, round (sum(cast(o.total_charge as real))) as receivables 
    FROM 
    organization as org, orders as o, organization as cust, reconcile_order as ro 
    WHERE org.organization_id = o.shipper_org_id 
    and o.broker_org_id = cust.organization_id 
    and o.order_id = ro.order_id 
    and o.status = 'D' 
    and (ro.receive_payment_in_full = 0 or ro.receive_payment_in_full is NULL) 
    and (NOW()::DATE - o.delivery_confirmed_date::DATE) between 31 and 60 
    group by org.organization_id, org.name, 
    cust.name 
    order by org.name asc limit 20 
) later_ones ON earlier_ones.organization_id = later_ones.organization_id AND earlier_ones.name = later_ones.name; 
+0

I各日付範囲の個別の表ではなく、複数の日付範囲の列を持つ表が1つ必要です。あなたの答えはうまくいくかもしれませんが、最後の行に構文エラーが出ています。 – Roberto

+0

調整しました。フリースタイルをコーディングしていた:D – chickahoona

+0

あなたがしたい:0-60、company1、receivables1、receivables2; 0-60、company2、receivables1、receivables2; 31-91、company1、receivables1、receivables2; 31-91、company2、receivables1、receivables2; (セミコロンは行を分けて、わかりやすくするために会社の名前などを残しました)そうですか? – chickahoona

1

あなたが条件を置くことができますcount()関数とsum()関数の中の文。

したがって、(両方の日付範囲で)すべての注文を戻すようにwhere句を調整した場合、select句に複数の結果列を作成し、必要な日付範囲から集計して合計することができます。

SELECT ... 
     count(CASE WHEN (NOW()::DATE - o.delivery_confirmed_date::DATE) < 31 THEN 1 ELSE NULL END) as num_orders_a, 
     round(sum(CASE WHEN (NOW()::DATE - o.delivery_confirmed_date::DATE) < 31 THEN cast(o.total_charge as real) ELSE NULL END)) as receivables_a, 
     count(CASE WHEN (NOW()::DATE - o.delivery_confirmed_date::DATE) BETWEEN 31 AND 60 THEN 1 ELSE NULL END) as num_orders_b, 
     round(sum(CASE WHEN (NOW()::DATE - o.delivery_confirmed_date::DATE) BETWEEN 31 AND 60 THEN cast(o.total_charge as real) ELSE NULL END)) as receivables_b 
(same FROM, WHERE, GROUP BY, and ORDER BY sections) 
+0

こんにちは、ありがとう、これは私のために働いています。私は実際に60日以上経過したものをすべて捕まえるために別の列のセットを追加する必要があります。したがって、調整済みのwhere節はより広い範囲をカバーする必要があります。少なくともこのレポートでは、気にする必要があるすべてのものを1000日で捕捉する必要があるため、(NOW():: DATE - o.delivery_confirmed_date :: DATE)<1000 'のようなものを考えていました。 – Roberto

+1

このアプローチでは、3番目の列セットを追加するのは簡単です。 '<1000'は良い機能かもしれませんが、本当にすべてのレコードを捕まえたいのであれば、WHERE句のフィルタは単に' o.delivery_confirmed_date IS NOT NULL'になります。を使用して。 – efreed

+0

スタックオーバーフローがあなたの質問に答えるのを助けたならば、これを答えとしてマークすることを忘れないでください。ありがとう。 – efreed

1

この猫を肌には、いくつかの方法がありますが、パフォーマンスとコードの保守性との間に、ここで本当の潜在的なトレードオフが存在します。

ここでのCTEは、コードの可読性/透過性/保守性に役立ちます。これはそれを行うにはハックの道の少しですが、これは1つのアイデアです:私はより一般的なアプローチは、(current_date - o.delivery_confirmed_date::DATEとして)CTEから「days_delta」列を渡すかもしれないと思うと持って

with order_data as (
    SELECT 
    org.organization_id, org.name, cust.name as customer, 
    o.total_charge::real, 
    case 
     when current_date - o.delivery_confirmed_date::DATE < 31 then 1 
     when current_date - o.delivery_confirmed_date::date < 61 then 2 
     else 3 
    end as cat 
    FROM 
    organization as org, 
    orders as o, 
    organization as cust, 
    reconcile_order as ro 
    WHERE 
    org.organization_id = o.shipper_org_id 
    and o.broker_org_id = cust.organization_id 
    and o.order_id = ro.order_id 
    and o.status = 'D' 
    and (ro.receive_payment_in_full = 0 or ro.receive_payment_in_full is NULL) 
) 
select 
    organization_id, name, customer, 
    sum (case when cat = 1 then 1 else 0 end) as "Orders < 31", 
    round (sum (case when cat = 1 then total_charge else 0 end)) as "Rec < 31", 
    sum (case when cat = 2 then 1 else 0 end) as "Orders 31-60", 
    round (sum (case when cat = 2 then total_charge else 0 end)) as "Rec 31-60", 
    sum (case when cat = 3 then 1 else 0 end) as "Orders 61+", 
    round (sum (case when cat = 3 then total_charge else 0 end)) as "Rec 61+" 
from order_data 
group by 
    organization_id, name, name 
order by name asc 

あなたの合計関数は次のようになります。

sum (case when days_delta between 31 and 60 then ... end) as "31-60" 

そして...あなたがCTEを必要としないと言う人は誰もが正しいと言います。あなたはそうしない。私にとっては、コードを処理するほうが楽しいです。

- EDIT - CTE、サブクエリの

あまり魅力(とあまり機能)いとこ:

select 
    organization_id, name, customer, 
    sum (case when cat = 1 then 1 else 0 end) as "Orders < 31", 
    round (sum (case when cat = 1 then total_charge else 0 end)) as "Rec < 31", 
    sum (case when cat = 2 then 1 else 0 end) as "Orders 31-60", 
    round (sum (case when cat = 2 then total_charge else 0 end)) as "Rec 31-60", 
    sum (case when cat = 3 then 1 else 0 end) as "Orders 61+", 
    round (sum (case when cat = 3 then total_charge else 0 end)) as "Rec 61+" 
from (
    SELECT 
    org.organization_id, org.name, cust.name as customer, 
    o.total_charge::real, 
    case 
     when current_date - o.delivery_confirmed_date::DATE < 31 then 1 
     when current_date - o.delivery_confirmed_date::date < 61 then 2 
     else 3 
    end as cat 
    FROM 
    organization as org, 
    orders as o, 
    organization as cust, 
    reconcile_order as ro 
    WHERE 
    org.organization_id = o.shipper_org_id 
    and o.broker_org_id = cust.organization_id 
    and o.order_id = ro.order_id 
    and o.status = 'D' 
    and (ro.receive_payment_in_full = 0 or ro.receive_payment_in_full is NULL) 
) as order_data 
group by 
    organization_id, name, name 
order by name asc 
+0

この答えは私の問題を解決する方法についてはPostgresのドキュメントに記載していますが、誰かのために 'with order_data as'節を使って1行目に構文エラーが出ます。なぜ私は理解できません。 – Roberto

+0

あなたはどのバージョンにいますか? – Hambone

+0

PostgreSQL 8.1.23 – Roberto

関連する問題