Как записать в Yii2 INSERT INTO SELECT массив данных

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Artur_Hopf
Сообщения: 19
Зарегистрирован: 2019.02.28, 11:18

Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение Artur_Hopf »

Добрый день. Есть такой массив данных:

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

$date = date('Y-d-m H:i:s');
$array = [
['oid' => 1, 'sum' = >0, 'date' => $date],
['oid' => 2, 'sum' = >0, 'date' => $date],
['oid' => 3, 'sum' = >0, 'date' => $date]
];
Длинная массива заранее не известна, это просто для примера.

Раньше без проверки добавлялось в базу так:

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

Yii::$app->db->createCommand()->batchInsert(
  'database',
  ['oid', 'sum','date'],
   $array
 )->execute()
Теперь же появилась проверка перед INSERT, на наличие записи с проверкой даты. SQL запрос выглядит так:

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

INSERT INTO database
SELECT *
FROM (VALUES(newid(), '1', 0 , GETDATE()),
(newid(), '2', 0 , GETDATE()),
(newid(), '3', 0 , GETDATE())) as a (id, oid, sum, date)
WHERE
NOT EXISTS (SELECT 1 FROM database  b WHERE b.date > DATEADD(minute, -1, GETDATE()) AND a.oid = b.oid)
Подскажите пожалуйста как мне теперь использовать эту проверку в Yii2?
frid-karatel
Сообщения: 50
Зарегистрирован: 2017.03.06, 15:37
Откуда: Владивосток

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение frid-karatel »

В принципе, тут может помочь yii\db\Expression.

Вообще, batchInsert заточен больше под ставку заранее известных данных, а тут вставка через select из другой таблицы.
Если честно, такие запросы лучше выполнять на чистом SQL, ибо читаются они легче, чем задействовать ActiveRecord.
Через MyActiveRecord::getDb()->createCommand($sql)->execute();
Artur_Hopf
Сообщения: 19
Зарегистрирован: 2019.02.28, 11:18

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение Artur_Hopf »

Вставка не из другой таблицы :
вот это

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

VALUES(newid(), '1', 0 , GETDATE()),
(newid(), '2', 0 , GETDATE()),
(newid(), '3', 0 , GETDATE())
это вот этот массив:

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

$date = date('Y-d-m H:i:s');
$array = [
['oid' => 1, 'sum' = >0, 'date' => $date],
['oid' => 2, 'sum' = >0, 'date' => $date],
['oid' => 3, 'sum' = >0, 'date' => $date]
];
Просто для примера я расписал.
Artur_Hopf
Сообщения: 19
Зарегистрирован: 2019.02.28, 11:18

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение Artur_Hopf »

Я не представляю как на такой запрос массив данных вставить:

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

$sql = " INSERT INTO database
        SELECT *
        FROM (VALUES(newid(), '1', 0 , GETDATE()), 
        (newid(), '2', 0 , GETDATE()),
        (newid(), '3', 0 , GETDATE())) as a ([id], [oid], [sum], [date])
        WHERE
        NOT EXISTS (SELECT 1 FROM database  b WHERE b.date > DATEADD(minute, -1, GETDATE()) AND a.oid = b.oid)";
        
Yii::$app->db->createCommand($sql)->execute();
Через foreach попробовать?
frid-karatel
Сообщения: 50
Зарегистрирован: 2017.03.06, 15:37
Откуда: Владивосток

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение frid-karatel »

Можно попробовать через temp table для MySQL и через WITH для PgSQL.
Условно говоря, вставить во временный буфер, а потом уже вставить в реальную базу.

SQL запрос на вставку можно получить так:

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

$sql = $this->db->getQueryBuilder()->batchInsert($table, $columns, $rows, $params);
А далее расширить SQL условием и выполнить.
Без буфера можно извратиться и подменить часть сгенерированного batchInsert-запроса, дописав свой прям туда, а потом его уже выполнить.

Все эти решения, факт, выходя за рамки самого Yii, и штатной реализации такого запроса нет.
Artur_Hopf
Сообщения: 19
Зарегистрирован: 2019.02.28, 11:18

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение Artur_Hopf »

Хорошо, спасибо. Буду пробовать.
Artur_Hopf
Сообщения: 19
Зарегистрирован: 2019.02.28, 11:18

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение Artur_Hopf »

Сделал через foreach все таки, вроде самый простой вариант:

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

$date = date('Y-d-m H:i:s');
$value= '';

foreach ($array as $key =>$item){
    if($item == end($allRfid)) {
        $virgule = "";
    }else{
         $virgule = ",";
     } 
     $value.="(newid(), '".$item['oid']."', ".(int)$item['status'].", '".$date."')".$virgule; 
 }
 
$sql = "INSERT INTO [Terminal].[dbo].[TrendArchive] 
           SELECT *
           FROM (VALUES $value) as a ([id], [oid], [sum], [date])
           WHERE
           NOT EXISTS (SELECT 1 FROM database  b WHERE b.date > DATEADD(minute, -1, GETDATE()) AND a.oid = b.oid)";

Yii::$app->db->createCommand($sql)->execute();
frid-karatel
Сообщения: 50
Зарегистрирован: 2017.03.06, 15:37
Откуда: Владивосток

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение frid-karatel »

А экранирование данных?
Я же как раз почему и написал про использование queryBuilder'а - он экранирует данные, тем самым защищая от SQL-инъекций.
Можно, конечно, и самому через \PDO экранировать, но есть же функционал движка.
Artur_Hopf
Сообщения: 19
Зарегистрирован: 2019.02.28, 11:18

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение Artur_Hopf »

не совсем понимаю как это применить в моем случае:

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

$sql = $this->db->getQueryBuilder()->batchInsert($table, $columns, $rows, $params);
В этих параметрах что должно быть $table, $columns, $rows, $params ?
frid-karatel
Сообщения: 50
Зарегистрирован: 2017.03.06, 15:37
Откуда: Владивосток

Re: Как записать в Yii2 INSERT INTO SELECT массив данных

Сообщение frid-karatel »

$table - таблица
$columns - названия колонок
$rows - строки для вставки

И не забыть, что newid() указать не текстом, а через new \yii\db\Expression('newid()')

В документации же есть информация о том, что передавать в этот метод.
PS: $this->db, по сути, равно Yii::$app->db
Ответить