Использование метода whereIn для возврата нескольких результатов для одного и того же значения массива, но с другим индексом

$pidArray содержит идентификаторы продуктов, некоторые из этих идентификаторов продуктов могут совпадать. IE: 34 34 56 77 99 34. Похоже, что метод whereIn не возвращает результатов для productId, который уже найден в $pidArray, даже если он имеет другой индекс.

 $productDataForOrder = Product::whereIn('id', $pidArray)->get(['id','price']);


 $totalAmount = $productDataForOrder->sum('price');

$productDataForOrder теперь содержит данные о продукте, но только для уникальных ProductID в $pidarray. Таким образом, при запуске функции суммирования сумма неверна, поскольку она не учитывает цену для нескольких экземпляров одного и того же идентификатора продукта.

Следующий код также не возвращает одинаковые объекты для каждого идентификатора продукта в массиве. Таким образом, если $pidArray содержит три одинаковых идентификатора продукта, запрос вернет коллекцию только с одним объектом вместо трех.

   $query = Product::select();
        foreach ($pidArray as $id)
        {
            $query->orWhere('id', '=', $id);
        }

        $productDataForOrder = $query->get(['id','price']);

        $totalAmount = $productDataForOrder->sum('price');

person LaserBeak    schedule 10.04.2016    source источник
comment
Поместите свой полный код туда. Код выше правильный.   -  person trinvh    schedule 10.04.2016
comment
@trinvh это почти мой полный код. Контроллер получает список идентификаторов продуктов из объекта запроса, эти идентификаторы хранятся в $pidArray. Затем идентификаторы в $pidArray используются для извлечения данных [id,price] для каждого идентификатора продукта в массиве. В $pidArray может быть несколько идентичных идентификаторов продукта, и мне нужно добавить цену для каждого из них.   -  person LaserBeak    schedule 10.04.2016
comment
Если я понимаю, что вы имеете в виду. Вместо этого попробуйте get(['id, 'price', DB::raw(sum(price))]).   -  person trinvh    schedule 10.04.2016
comment
@trinvh Нет, это не делает ничего другого. Я не знаю, как я могу сделать мое объяснение еще проще. У меня есть массив идентификаторов продуктов, некоторые из этих идентификаторов продуктов могут совпадать. Я хочу вернуть коллекцию объектов [id, price] для каждого идентификатора продукта в массиве, а затем добавить цену. В нынешнем виде запрос не возвращает вышеупомянутые объекты для нескольких идентичных идентификаторов продукта, а только для одного. Я хочу сделать это в одном запросе.   -  person LaserBeak    schedule 11.04.2016


Ответы (3)


Вы не сможете получить повторяющиеся данные так, как пытаетесь. SQL возвращает строки, соответствующие вашему предложению where. Он не будет возвращать повторяющиеся строки только потому, что ваше предложение where имеет повторяющиеся идентификаторы.

Это может помочь думать об этом следующим образом:

select * from products where id in (1, 1)

такой же как

select * from products where (id = 1) or (id = 1)

В таблице есть только одна запись, удовлетворяющая условию, так что это все, что вы получите.

Вам придется выполнить дополнительную обработку в PHP, чтобы получить свою цену. Вы можете сделать что-то вроде:

// First, get the prices. Then, loop over the ids and total up the
// prices for each id.

// lists returns a Collection of key => value pairs.
// First parameter (price) is the value.
// Second parameter (id) is the key.
$prices = Product::whereIn('id', $pidArray)->lists('price', 'id');

// I used array_walk, but you could use a plain foreach instead.
// Or, if $pidArray is actually a Collection, you could use
// $pidArray->each(function ...)
$total = 0;
array_walk($pidArray, function($value) use (&$total, $prices) {
    $total += $prices->get($value, 0);
});

echo $total;
person patricus    schedule 11.04.2016

Метод whereIn ограничивает результаты только значениями в данном массиве. Из документов:

Метод whereIn проверяет, содержится ли значение данного столбца в данном массиве.

Id создаст переменную запроса и прокрутит массив, добавляя к переменной запроса в каждом проходе. Что-то вроде этого:

$query = Product::select();

foreach ($pidArray as $id)
{
    $query->where('id', '=', $id);
}

$query->get(['id','price']);
person revolt_101    schedule 10.04.2016
comment
Приведет ли это к количеству запросов, равному количеству идентификаторов, или $query->get() будет единственным запросом? - person LaserBeak; 10.04.2016
comment
Только один запрос. $query — это экземпляр Illuminate\Database\Eloquent\Builder. Когда вы перебираете идентификаторы, оператор select создается в экземпляре Builder. Метод get() в Builder фактически выполняет запрос. Ознакомьтесь с документацией по API: laravel.com/api/5.2/Illuminate/ База данных/Eloquent/Builder.html - person revolt_101; 10.04.2016
comment
Только что попробовал код, и он также возвращает результаты только для уникальных значений идентификатора продукта. Протестировано с двумя одинаковыми идентификаторами продукта в $pidArray. $query-›get() создал коллекцию только с одним объектом. - person LaserBeak; 10.04.2016
comment
Попробуйте использовать orWhere вместо where. - person revolt_101; 10.04.2016

Вот код, который будет работать для вашего варианта использования, расширяющегося на @patricus. Сначала вы извлекаете массив ключа как идентификатор и значение как цену из таблицы продуктов.

$prices = Product::whereIn('id', $pidArray)->lists('price', 'id');

$totalPrice = collect([$pidArray])->reduce(function($result, $id) use ($prices) {

      return $result += $prices[$id];

}, 0);
person valmayaki    schedule 03.08.2016