Как сделать сложный запрос и вывод через GridView?

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Странник
Сообщения: 296
Зарегистрирован: 2013.04.08, 10:35
Откуда: Нижний Новгород

Как сделать сложный запрос и вывод через GridView?

Сообщение Странник »

Есть таблица заказов "orders".
Поля:
id, id_client, id_goods, amount.
Клиентов можен быть ло 50. Наименований товаров не более 7.
Количество любое разумное. Обычно до 100.
Нужно вывезти таблицу примерно такую:

Код: Выделить всё

	<table>
	<tbody>
	<tr>
		<td>&nbsp;</td>
		<td>Покупатель</td>
		<td>Товар_1</td>
		<td>Товар_2</td>
		<td>Товар_3</td>
		<td>Товар_4</td>
		<td>Товар_5</td>
	</tr>
	<tr>
		<td>1</td>
		<td>Клиент_1</td>
		<td>7</td>
		<td>1</td>
		<td>5</td>
		<td>2</td>
		<td>100</td>
	</tr>
	<tr>
		<td>2</td>
		<td>Клиент_1</td>
		<td>2</td>
		<td>2</td>
		<td>7</td>
		<td>3</td>
		<td>80</td>
	</tr>
	<tr>
		<td>3</td>
		<td>Клиент_1</td>
		<td>3</td>
		<td>1</td>
		<td>4</td>
		<td>1</td>
		<td>45</td>
	</tr>
	</tbody>
	</table>
Не понимаю как сделать запрос и вывезти через gridView.
Отдельно сделать запросы запросы, сформировать массив и вывезти через свою вьюху можно, но хочется красиво.
Странник
Сообщения: 296
Зарегистрирован: 2013.04.08, 10:35
Откуда: Нижний Новгород

Re: Как сделать сложный запрос и вывод через GridView?

Сообщение Странник »

Продолжу тему. Сам запрос к базе в случае с 4 товарами получается такой:

Код: Выделить всё

SELECT `view`.`id_client`, COALESCE(`t1`.`amount`,0) `q1`, COALESCE(`t2`.`amount`,0) `q2`, COALESCE(`t3`.`amount`,0) `q3`, COALESCE(`t4`.`amount`,0) `q4` 
FROM (
	SELECT DISTINCT `t1`.`id_client`
	FROM `orders` `t1`
	WHERE (`id_goods` IN (3261,3259,3265,3267))
) `view`
LEFT JOIN `orders` `t4` ON `t4`.`id_goods` = 3265 AND `t4`.`id_client` = `view`.`id_client` 
LEFT JOIN `orders` `t3` ON `t3`.`id_goods` = 3267 AND `t3`.`id_client` = `view`.`id_client`
LEFT JOIN `orders` `t2` ON `t2`.`id_goods` = 3261 AND `t2`.`id_client` = `view`.`id_client` 
LEFT JOIN `orders` `t1` ON `t1`.`id_goods` = 3259 AND `t1`.`id_client` = `view`.`id_client`
ORDER BY `view`.id_client
Вопрос можно ли его сформировать через activeRecords, как сделать $dataProvider и как вывести в GridView с полями q1,q2,q3,q4
Пока делаю так:
В контроллере:

Код: Выделить всё

$orders= Yii::$app->db->createCommand($sql)->queryAll();
В представлении:

Код: Выделить всё

	foreach($clients as $key_client=>$client) {
		printf ('<tr><td align="center">%s</td><td align="left">%s</td>', $i, $client);	
		foreach($allgoods as $key_goods=>$goods) {
			print'<td align="center">';
			print_r($orders[$key_client][$key_goods]['amount']);
			print'</td>';
		}
		print '</tr>';
		$i++;
	}
Странник
Сообщения: 296
Зарегистрирован: 2013.04.08, 10:35
Откуда: Нижний Новгород

Re: Как сделать сложный запрос и вывод через GridView?

Сообщение Странник »

И снова продолжаю.
С частью задачи в контроллере разобрался:

Код: Выделить всё

$id_all_goods = (ArrayHelper::getColumn(Goods::find()->select('id')->where(...])->all(), 'id', $keepKeys = true));

$subQuery = (new Query())->select('`id_client`')->from('`orders` `view`')
->where(['`id_goods`'=>$id_all_goods])->distinct(); // получаем список клиентов для всех товаров

$select = '`view`.`id_client`';

foreach ($id_all_goods AS $key=>$id_goods)  
	$select .= ', COALESCE(`t'.$key.'`.amount,0) `q'.$key.'`'; // создаём select по всем товарам.
	
$query = new Query;

$query->select($select)
->from(['view' => $subQuery]); // создаём начальный запрос

foreach ($id_all_goods AS $key=>$id_goods)  
$query = $query->leftJoin('`orders` `t'.$key.'`','`t'.$key.'`.id_goods = '.$id_goods.' AND `t'.$key.'`.id_client = `view`.`id_client`'); // дополняем его  leftJoin

$dataProvider = new ActiveDataProvider([
	'query' =>$query]);
Осталось в представлении решить как динамически добавлять column.
Странник
Сообщения: 296
Зарегистрирован: 2013.04.08, 10:35
Откуда: Нижний Новгород

Re: Как сделать сложный запрос и вывод через GridView?

Сообщение Странник »

РЕШЕНО:
Не знаю на сколько красиво и кошерно, но работает.
Окончательный вариант:
Контроллер:

Код: Выделить всё

        $id_all_goods = (ArrayHelper::getColumn(Goods::find()->select('id')->where(...)->all(), 'id', $keepKeys = true)); // Получить все товары по доп условиям
        $select = '`view`.`id_client`, `client`.`title` AS `title`'; // начало селекта
        $column[]= ['class' => 'yii\grid\SerialColumn'];
        $column[]= [
            'attribute' => 'Клиенты',
            'value' => 'title',
            'footer' => '<b>ИТОГО:</b>',
        ];
        foreach ($id_all_goods AS $key=>$id_goods)  {
            $select .= ', COALESCE(`t'.$key.'`.amount,0) `q'.$key.'`'; // дополнить селект для всех столбцов
            $column[] = [
                'attribute' => Goods::findOne($id_goods)->title,		// формирорвание самих столбцов
                'headerOptions' => ['style' => '____'],
                'class' => NumberColumn::className(),
                'contentOptions' => ['style' => 'text-align: center'],
                'footerOptions' => ['style' => 'font-weight: bold;text-align: center;'],
                'value' => 'q'.$key,
            ]; 
        }
        $query = new Query;
        $subQuery = (new Query())->select('`id_client`')->from('`orders` `view`')
            ->where(['.....,`id_goods`'=>$id_all_goods])->distinct(); // получение всех клиентов по всем заказам
        $query->select($select)
            ->leftJoin('client', 'view.id_client = client.id') // join для вывода названия клиента
            ->from(['view' => $subQuery]);
        foreach ($id_all_goods AS $key=>$id_goods) 
			$query = $query->leftJoin('`orders` `t'.$key.'`','`t'.$key.'`.id_goods = '.$id_goods.' AND `t'.$key.'`.id_client = `view`.`id_client`'); // формирования колонок
        $dataProvider = new ActiveDataProvider([
            'query' =>$query]);
        return $this->render('print', [
            'model' => $model,
            'column' => $column,
            'dataProvider' => $dataProvider,
        ]);
Представление:

Код: Выделить всё

GridView::widget([
	'dataProvider' => $dataProvider,
	'columns' =>$column,
	'layout' => "{items}",
	'showFooter' => true,
	'showHeader' => true,
	'tableOptions' => ['class' => 'table-striped table-bordered table-print'],
]);
Ответить