加入多个表导致扩展具有重复属性的单行

Joining multiple tables lead to extend the single row with duplicated attributes

我有 5 个表需要连接在一起:

products:
  - product_id

orders
  - order_id

order_items
  - item_id
  - order_id
  - product_id

directsells
  - directsell_id

directsell_items
  - item_id
  - directsell_id
  - product_id

我正在使用 Zend-Framework,这是我的代码:

    $ProductsTable = new Products();
    $select = $ProductsTable->select();
    $select->from(array('P' => 'products'), array('product_id', 'product_name'));
    $select->setIntegrityCheck(false);

    $select->joinLeft(array('DI' => 'directsells_items'), 'DI.product_id = P.product_id', array('item_price', 'item_discount', 'qty'));
    $select->joinLeft(array('D' => 'directsells'), 'DI.directsell_id = D.directsell_id', array('directsell_number AS invoice_number', 'directsell_date AS invoice_date', 'invoice_status'));
    $select->where('DATE(D.directsell_date) BETWEEN "'. date('Y-m-d', strtotime($from_date)) .'" AND "'. date('Y-m-d', strtotime($to_date)) .'"');
    $select->where('D.invoice_status <> "Canceled"');

    $select->joinLeft(array('OI' => 'order_items'), 'OI.product_id = P.product_id', array('item_price', 'item_discount', 'qty'));
    $select->joinLeft(array('O' => 'orders'), 'OI.order_id = O.order_id', array('order_number AS invoice_number', 'order_date AS invoice_date'
                    ,'IF(`order_status` = "10", "Returned", "Active") AS invoice_status'
                ));
    $select->where('DATE(O.order_date) BETWEEN "'. date('Y-m-d', strtotime($from_date)) .'" AND "'. date('Y-m-d', strtotime($to_date)) .'"');
    $select->where('O.order_status <> "0"');

    $select->where('P.product_id = '. $product_id);

现在我在 directsell_items 中有 2 个条目:

我在 order_items 中有 1 个条目:

我的查询结果是 directsell_items 中的两个条目与 order_item 中的条目合并,如下所示:

我希望一切都清楚。我知道这可能是我加入的问题,但我想不通。

看起来你的直销商品是一种销售商品,你的订单商品是二次销售商品。你只得到两条记录的原因是当你加入时你有效地扩展了一行。不寻找额外的行。

正如@Barmar 所指出的,您需要一个 UNION 来处理这种情况。联合有效地从两个单独的查询中获取记录集,并将它们 returns 作为一个记录集。

因此,您将需要类似(代码未测试)的内容:

$ProductsTable = new Products();
$selectDirect = $ProductsTable->select();
$selectDirect->from(array('P' => 'products'), array('product_id', 'product_name'));

$selectDirect->joinLeft(array('DI' => 'directsells_items'), 'DI.product_id = P.product_id', array('item_price', 'item_discount', 'qty'));
$selectDirect->joinLeft(array('D' => 'directsells'), 'DI.directsell_id = D.directsell_id', array('directsell_number AS invoice_number', 'directsell_date AS invoice_date', 'invoice_status'));
$selectDirect->where('DATE(D.directsell_date) BETWEEN "'. date('Y-m-d', strtotime($from_date)) .'" AND "'. date('Y-m-d', strtotime($to_date)) .'"');
$selectDirect->where('D.invoice_status <> "Canceled"');
$selectDirect->where('P.product_id = '. $product_id);

$selectOrders = $ProductsTable->select();
$selectOrders->from(array('P' => 'products'), array('product_id', 'product_name'));
$selectOrders->joinLeft(array('OI' => 'order_items'), 'OI.product_id = P.product_id', array('item_price', 'item_discount', 'qty'));
$selectOrders->joinLeft(array('O' => 'orders'), 'OI.order_id = O.order_id', array('order_number AS invoice_number', 'order_date AS invoice_date','IF(`order_status` = "10", "Returned", "Active") AS invoice_status'));
$selectOrders->where('DATE(O.order_date) BETWEEN "'. date('Y-m-d', strtotime($from_date)) .'" AND "'. date('Y-m-d', strtotime($to_date)) .'"');
$selectOrders->where('O.order_status <> "0"');
$selectOrders->where('P.product_id = '. $product_id);

$select = $db->select()->union(array($selectDirect, $selectOrders));