9

Magento Sales Order Collection をattribute1 = value1 AND (attribute2 = value2 OR attribute3 = value2)でフィルターするにはどうすればよいですか? WHERE {COND1} AND {COND2} OR {COND3}と書くことはできますが、 AND ({COND2} OR {COND3})をグループ化することはできません。

まず第一に、これは私の知る限り複製ではありません。私はこれを見、バージョン 1.3.2 ではうまく機能しますが、Enterprise Edition 1.11.1 では機能しません。これが私がやろうとしていることです...「処理中」のステータスを持つ、定義された日付範囲で作成または更新されたMagento注文を取得します。以前のバージョンでは機能するが、私のバージョンでは機能しないコードは次のとおりです。

$orderIds = Mage::getModel('sales/order')->getCollection()
    ->addFieldToFilter('status', 'processing')
    ->addFieldToFilter(array(
        array(
            'attribute' => 'created_at',
            'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'),
            'to'   => $toDate->toString('yyyy-MM-dd HH:mm:ss'),
        ),
        array(
            'attribute' => 'updated_at',
            'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'),
            'to'   => $toDate->toString('yyyy-MM-dd HH:mm:ss'),
        ),
    ));

これは、生成している SQL とその結果のエラーです。

SELECT `main_table`.* FROM `sales_flat_order` AS `main_table`
WHERE (status = 'processing') AND (Array = '')

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Array' in 'where clause' 

コードを掘り下げるとaddFieldToFilter、 lib/Varien/Data/Collection/Db.php に関数が見つかりました

/** 
 * Add field filter to collection
 *
 * @see self::_getConditionSql for $condition
 * @param string $field
 * @param null|string|array $condition
 * @return Mage_Eav_Model_Entity_Collection_Abstract
 */
public function addFieldToFilter($field, $condition=null)
{   
    $field = $this->_getMappedField($field);
    $this->_select->where($this->_getConditionSql($field, $condition),
        null, Varien_Db_Select::TYPE_CONDITION);
    return $this;
}   

// **********************************************
// ** Different from addFieldToFilter in 1.3.2 **
// **********************************************

/** 
 * Add field filter to collection
 *
 * If $attribute is an array will add OR condition with following format:
 * array(
 *     array('attribute'=>'firstname', 'like'=>'test%'),
 *     array('attribute'=>'lastname', 'like'=>'test%'),
 * )
 *
 * @see self::_getConditionSql for $condition
 * @param string|array $attribute
 * @param null|string|array $condition
 * @return Mage_Eav_Model_Entity_Collection_Abstract
 */
public function addFieldToFilter($field, $condition=null)
{   
    $field = $this->_getMappedField($field);
    $this->_select->where($this->_getConditionSql($field, $condition));
    return $this;
}       

最初のパラメーターを配列として受け入れるのに使用されていたように見えaddFieldToFilterますが、今では文字列でなければなりません...興味深いので、運がゼロで次のことを試しました...

$orderIds = Mage::getModel('sales/order')->getCollection()
    ->addFieldToFilter('status', 'processing')
    ->addFieldToFilter('attribute', array(
        array(
            'attribute' => 'created_at',
            'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'),
            'to'   => $toDate->toString('yyyy-MM-dd HH:mm:ss'),
        ),
        array(
            'attribute' => 'updated_at',
            'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'),
            'to'   => $toDate->toString('yyyy-MM-dd HH:mm:ss'),
        ),
    ));
SELECT `main_table`.* FROM `sales_flat_order` AS `main_table`
WHERE (status = 'processing')
AND ((
    (attribute >= '2012-06-13 17:52:01' AND attribute <= '2012-06-15 17:52:01')
 OR (attribute >= '2012-06-13 17:52:01' AND attribute <= '2012-06-15 17:52:01')
))

SQLを操作することでできることは知っていますが、「Magentoの方法」があればそれを行う方法を本当に知りたいです...

ちなみに、私も使ってみましaddAttributeToFilterたが、エラーメッセージは「フィールド名を特定できません」です。


アップデート

Mage_Sales_Model_Resource_Order_Collection半有望に見える2 つの関数に出くわしましたが、それでもまだ私が望むものではありません。

/**
 * Add field search filter to collection as OR condition
 *
 * @see self::_getConditionSql for $condition
 *
 * @param string $field
 * @param null|string|array $condition
 * @return Mage_Sales_Model_Resource_Order_Collection
 */
public function addFieldToSearchFilter($field, $condition = null)
{
    $field = $this->_getMappedField($field);
    $this->_select->orWhere($this->_getConditionSql($field, $condition));
    return $this;
}

/**
 * Specify collection select filter by attribute value
 *
 * @param array $attributes
 * @param array|integer|string|null $condition
 * @return Mage_Sales_Model_Resource_Order_Collection
 */
public function addAttributeToSearchFilter($attributes, $condition = null)
{
    if (is_array($attributes) && !empty($attributes)) {
        $this->_addAddressFields();

        $toFilterData = array();
        foreach ($attributes as $attribute) {
            $this->addFieldToSearchFilter($this->_attributeToField($attribute['attribute']), $attribute);
        }
    } else {
        $this->addAttributeToFilter($attributes, $condition);
    }

    return $this;
}

コードを更新すると、目的の結果に非常に近くなりますが、本当に必要なのはCONDITION1 AND (CONDITION2 OR CONDITION3)です。

$orderIds = Mage::getModel('sales/order')->getCollection()
    ->addFieldToFilter('status', 'processing')
    ->addAttributeToSearchFilter(array(
        array(
            'attribute' => 'created_at',
            'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'),
            'to'   => $toDate->toString('yyyy-MM-dd HH:mm:ss'),
        ),
        array(
            'attribute' => 'updated_at',
            'from' => $fromDate->toString('yyyy-MM-dd HH:mm:ss'),
            'to'   => $toDate->toString('yyyy-MM-dd HH:mm:ss'),
        ),
    ));

SELECT `main_table`.*,
       `billing_o_a`.`firstname`,
       `billing_o_a`.`lastname`,
       `billing_o_a`.`telephone`,
       `billing_o_a`.`postcode`,
       `shipping_o_a`.`firstname`,
       `shipping_o_a`.`lastname`,
       `shipping_o_a`.`telephone`,
       `shipping_o_a`.`postcode`
FROM `sales_flat_order` AS `main_table`
LEFT JOIN `sales_flat_order_address` AS `billing_o_a`
    ON (main_table.entity_id = billing_o_a.parent_id AND billing_o_a.address_type = 'billing')
LEFT JOIN `sales_flat_order_address` AS `shipping_o_a`
    ON (main_table.entity_id = shipping_o_a.parent_id AND shipping_o_a.address_type = 'shipping')
WHERE (status = 'processing')
OR (created_at >= '2012-06-16 16:43:38' AND created_at <= '2012-06-18 16:43:38')
OR (updated_at >= '2012-06-16 16:43:38' AND updated_at <= '2012-06-18 16:43:38')
4

3 に答える 3

2

FLAT TABLE と EAV コレクションは異なる構文を使用することに注意してください!

OR 条件を EAV コレクションに追加する

同じ属性に OR 条件を指定する場合、2 つの異なる属性を使用する場合とは構文が異なることに注意してください。

指定されたフィルターをテストして SQL として表示するために使用$collection->load(true)します (その方が理解しやすいと思います)。

EAV コレクションにはaddAttributeToFilter()oraddFieldToFilter()を使用しますが、最初のコレクションはオプションの 3 番目の$joinType引数を取ることができます。

EAV コレクションの 1 つの属性に OR フィルターを追加する方法: 属性コードは最初の引数で、条件は 2 番目の引数です。

例えば:$col->addFieldToFilter('name', array(array('like' => 'M%'), array('like' => '%O'))); // (get items whose name starts with M OR ends with O)

EAV コレクションの DIFFERENT 属性に OR フィルターを追加する方法: 属性を含む条件の配列である 1 つの引数のみを渡します。

OR 条件を FLAT TABLE コレクションに追加する

フラット テーブル コレクションで単一の属性を持つ OR フィルターを指定することは、EAV コレクションの場合と同じです。

例えば:$col->addFieldToFilter('name', array(array('like' => 'M%'), array('like' => '%O'))); // get items whose name start with M OR end with O

複数の属性を OR 条件で結合するには、構文が EAV コレクションとは異なります (注: これは Magento 1.6 では壊れています)。

例えば:$col->addFieldToFilter(array('weight', 'name'), array(array('in' => array(1,3)), array('like' => 'M%')));

最初の属性は最初の条件にマップされ、2 番目の属性は 2 番目の条件にマップされます。

これは 1.6 で壊れているため、複数の属性に対して単純な等価条件を指定する可能性が残されています。addFilter()

例えば:$col->addFilter('weight', 1, 'or')->addFilter('weight', 2, 'or')->addFilter('sku', 'ABC', 'or'); // weight is 1 or 2 or sku is ABC

もいつでも使用でき$collection->getSelect()->orWhere(…)ますが、RDBMS 間の互換性に注意する必要があります。

注: これは、私が何年も前に tumblr に投稿した 2 つの投稿のクロス ポスト
です
。 11102525164/フラットテーブルコレクションまたはフィルター

于 2014-01-17T15:43:29.340 に答える
1

Zend_Db メソッドを介して SELECT ステートメントを変更する、使用したくないソリューションを次に示します。

$orderIds = Mage::getModel('sales/order')->getCollection()
    ->getSelect();
$adapter = $orderIds->getAdapter();
$quotedFrom = $adapter->quote(
    $fromDate->toString('yyyy-MM-dd HH:mm:ss')
);
$quotedTo = $adapter->quote(
    $toDate->toString('yyyy-MM-dd HH:mm:ss')
);
$orderIds
    ->where('status = ?', 'processing')
    ->where(
        vsprintf(
            '(created_at >= %s AND created_at <= %s)'
          . ' OR (updated_at >= %s AND updated_at <= %s)',
            array(
                $quotedFrom, $quotedTo,
                $quotedFrom, $quotedTo,
            )
        )
    );
于 2012-06-18T17:54:07.947 に答える