0

「PROD_CD」で4つの個別のクエリを結合して、正しい出力を1つのクエリに返し、後で別の言語でクエリをマージする必要がないようにしようとしています。現在のものでは(そして私は多くのバリエーションを試しましたが、すべてさまざまな問題があります)、多くの重複した結果とそれぞれの重複の数が異なります。

これが私が試している現在のクエリです(すべての日付関数は一定期間にわたってデータセットを決定するためのものです-データベースは非常に古く、クラリオン時間を使用しています):

$query_ats = "SELECT 
            plog.prod_cd as prod_id,
            ord_log.ORDER_QTY as total_so,
            ediordlg.ORDER_QTY as total_edi_so,
            inv_data.IN_STOCK as in_stock
        FROM plog 
        INNER JOIN ord_log 
            ON plog.prod_cd = ord_log.prod_cd 
        INNER JOIN ediordlg 
            ON plog.prod_cd = ediordlg.prod_cd AND ord_log.prod_cd = ediordlg.prod_cd
        INNER JOIN inv_data 
            ON plog.prod_cd = inv_data.prod_cd AND ord_log.prod_cd = inv_data.prod_cd AND ediordlg.prod_cd = inv_data.prod_cd
        WHERE 
            inv_data.CLASS_CD = 'ALG7' 
        AND 
            dateadd(day, plog.EST_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        AND 
            dateadd(day, ord_log.SHIP_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        AND 
            dateadd(day, ediordlg.SHIP_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        GROUP BY plog.prod_cd, plog.log_qty, ord_log.ORDER_QTY, ediordlg.ORDER_QTY, inv_data.IN_STOCK
        ORDER BY plog.prod_cd ASC";

そして、これはそれが出力するもののサンプルです:

配列([prod_id] => ALG-809
[total_so] => 4 [total_edi_so] => 46 [in_stock] => 0)配列([prod_id] => ALG-809
[total_so] => 6 [total_edi_so] => 46 [in_stock] => 0)配列([prod_id] => ALG-809
[total_so] => 7 [total_edi_so] => 46 [in_stock] => 0)

正しい結果を返す4つの個別のクエリは次のとおりです。

$query_stock = "SELECT 
                prod_cd, 
                inv_data.DESCRIP,
                inv_data.IN_STOCK
            from 
                inv_data 
            where 
                inv_data.CLASS_CD = 'ALG7'
            ORDER BY
                inv_data.prod_cd ASC";

$query_po = "SELECT 
            plog.prod_cd, 
            SUM(plog.log_qty) as total_po
        FROM 
            plog JOIN inv_data ON plog.prod_cd = inv_data.prod_cd 
        WHERE 
            inv_data.CLASS_CD = 'ALG7'
        AND 
            dateadd(day, EST_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        GROUP BY 
            plog.prod_cd
        ORDER BY
            plog.prod_cd ASC";

$query_so = "SELECT 
            ord_log.prod_cd,
            SUM(ord_log.ORDER_QTY) as total_so
        FROM 
            ord_log JOIN inv_data ON ord_log.prod_cd = inv_data.prod_cd 
        WHERE 
            inv_data.CLASS_CD = 'ALG7' 
        AND 
            dateadd(day, SHIP_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate()) 
        GROUP BY 
            ord_log.PROD_CD
        ORDER BY
            ord_log.prod_cd ASC";

$query_edi = "SELECT 
            ediordlg.prod_cd,
            SUM(ediordlg.ORDER_QTY) as total_so_EDI
        FROM
            ediordlg JOIN inv_data ON ediordlg.prod_cd = inv_data.prod_cd 
        WHERE 
            inv_data.CLASS_CD = 'ALG7' 
        AND 
            dateadd(day, SHIP_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate()) 
        GROUP BY 
            ediordlg.PROD_CD
        ORDER BY
            ediordlg.prod_cd ASC";

私が使っているのはJOINだと思いますが、一生理解できません。助言がありますか?ありがとう!

4

2 に答える 2

0

このような場合の SQL のルール 1: 最初に行を取り出したいものから選択し、詳細情報が必要なものに結合します。あなたの場合、あなたが望むのは製品IDのようで、これはinv_dataテーブルに一意に格納されているようですので、それから始めましょう.

select
        i.prod_cd as product,
        i.descrip as description,
        i.in_stock
    from
        inv_data as i
    where
        i.class_cd = 'ALG7'
    order by
        i.prod_cd asc
;

それぞれ 1 つしか保存されていないため、それぞれ 1 つを取得します。残りは単なる詳細です。いくつかの結合を追加しましょう

select
        i.prod_cd as product,
        i.descrip as description,
        i.in_stock,
        sum(l.order_qty) as l_total_so,
        sum(e.order_qty) as e_total_so
    from
        inv_data as i
        inner join plog as p
            on i.prod_cd = p.prod_cd
        inner join ord_log as l
            on i.prod_cd = l.prod_cd
        inner join ediordlg as e
            on i.prod_cd = e.prod_cd
    where
        i.class_cd = 'ALG7'
    order by
        i.prod_cd asc
    group by
        i.prod_cd,
        i.descrip,
        i.in_stock
;

onいずれにせよ、それらはすべて同じであるため (定義上、以前の内部結合が成功したため)、句にそれほど多くの列をリストする必要はありません。

それがマスターテーブルではplogないことが判明した場合は、クエリでそれらを逆にします。inv_data両方の合計値が必要な場合は、sum(l.order_qty + e.order_qty) as total_so2 つの列を作成する代わりに を使用します。

理解しておくべきことは、結合によって結果が倍増する可能性があるということです。どのテーブルがより多いかを理解し、それぞれの場合に何かをして、余分な結果になるたびに「余分な」結果を制限すると、クリーンな結果セットが得られます。この場合、おそらく合計とグループ化だけで十分ですが、複雑なケースでは、十分に異なるセットを選択して戻すサブクエリに参加する必要があります。

そして、関連するメモdistinctとして、あなたの質問には毒があります! 「結合後に重複する行が多すぎる」ことを修正することではない、非常に具体的な目的があります。そのために使用している場合は、おそらくバグがあり、他の未知の副作用が発生する可能性があります。group by最初によりスマートなonステートメントで修正し、次にネストされたクエリで修正してください。

$x質問とは関係ありませんが、重要です。クエリ内で変数を展開しているようです。これはおそらく安全 (または効率的) ではありません。代わりにパラメータ化されたクエリを使用してみてください。

于 2013-01-25T21:38:25.357 に答える
0

なぜ使用しないのDISTINCTですか?

$query_ats = "SELECT DISTINCT
            plog.prod_cd as prod_id,
            ord_log.ORDER_QTY as total_so,
            ediordlg.ORDER_QTY as total_edi_so,
            inv_data.IN_STOCK as in_stock
        FROM plog 
        INNER JOIN ord_log 
            ON plog.prod_cd = ord_log.prod_cd 
        INNER JOIN ediordlg 
            ON plog.prod_cd = ediordlg.prod_cd AND ord_log.prod_cd = ediordlg.prod_cd
        INNER JOIN inv_data 
            ON plog.prod_cd = inv_data.prod_cd AND ord_log.prod_cd = inv_data.prod_cd AND ediordlg.prod_cd = inv_data.prod_cd
        WHERE 
            inv_data.CLASS_CD = 'ALG7' 
        AND 
            dateadd(day, plog.EST_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        AND 
            dateadd(day, ord_log.SHIP_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        AND 
            dateadd(day, ediordlg.SHIP_DT, '18001228') BETWEEN getdate() and dateadd(day, $x, getdate())
        GROUP BY plog.prod_cd, plog.log_qty, ord_log.ORDER_QTY, ediordlg.ORDER_QTY, inv_data.IN_STOCK
        ORDER BY plog.prod_cd ASC";
于 2013-01-25T19:59:58.100 に答える