如何在一列上正确连接MSsql中的四个表?

时间:2013-01-25 19:57:14

标签: sql sql-server

我正在尝试在“PROD_CD”上加入四个单独的查询,以将正确的输出返回到一个查询中,以防止必须在另一种语言之后将查询合并在一起。对于当前的(并且我尝试了许多变化,都有各种问题),我收到了很多重复的结果和每个重复的不同数量。

这是我一直在尝试的当前查询(所有日期函数都用于确定一段时间内的数据集 - 数据库非常陈旧且使用Clarion时间):

$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   )

以下是返回正确结果的四个单独查询:

$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,但我无法理解我的生活。有什么建议?谢谢!

2 个答案:

答案 0 :(得分: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";

答案 1 :(得分: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
;

你会得到其中一个,因为每个只存储一个。其余的只是细节。让我们添加一些联接

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_so而不是创建两列。

要理解的是,连接可以使结果倍增。了解哪些表具有更多表并在每种情况下执行某些操作以限制每次额外的“额外”结果将导致清晰的结果集。在这种情况下,可能只是求和和分组就足够了,但在复杂的情况下,你需要加入一个子查询,选择一个足够不同的集合。

而且,在相关的说明中,distinct对您的查询是有害的!它有一个非常特殊的目的,来修复“加入后重复的行太多”。如果您正在使用它,可能有一个可能具有未知其他副作用的错误。首先尝试使用group by和更智能的on语句修复它,然后再嵌套查询。

与您的问题无关,但很重要:您似乎正在查询中扩展变量$x。这可能不安全(或有效);尝试使用参数化查询。