Вставить используя PDO внутри цикла - PullRequest
0 голосов
/ 02 ноября 2018

Извините за довольно простые вопросы, но я очень расстроен этой ошибкой. Пожалуйста, проверьте, нужно ли что-то исправить. Иллюстрация, я пытаюсь сохранить данные в таблицу A, где я беру данные из таблицы B. Перед сохранением он проверяет, вставлены ли данные из таблицы B в таблицу A.

Это мой код:

$sql1="select * from B where status=2";
$q1=$this->pdo->query($sql1);
$q1->execute();
$result1=$q1->fetchAll(PDO::FETCH_ASSOC);

foreach ($result1 as $row) {
  $sql2="select * from A where idB='".$row['idB']."'";
  $q2=$this->pdo->query($sql2);
  $q2->execute();
  $result2=$q2->fetchAll();

  if(empty($result2)){
    $data = ['idB' => $row['idB'],'name' => $row['name'];
    $s_inreg="insert into A(idB,name) values(:idB,:name)";
    $stmt=$this->pdo->prepare($s_inreg);
    $ret=$stmt->execute($data);
  }
}

думаю, что есть 100 данных, только 10 данных успешно сохранены, остальные не удалось сохранить.

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Здесь я уменьшил ваш код, или, по крайней мере, код, который на самом деле делает вещи

$result1 = $this->pdo->query('
SELECT
    B.idB,
    B.name
FROM
    B
LEFT JOIN
    A ON A.idB=B.idB
WHERE
    B.status=2 AND IS NULL A.ibB
')->fetchAll(PDO::FETCH_ASSOC);

$stmt = $this->pdo->prepare('
INSERT INTO
    A(idB,name) VALUES (:idB,:name)'
);  

foreach ($result1 as $row) $stmt->execute($row);

Предполагая, что у вас было правильно, давайте посмотрим на JOIN

select * from B where status=2
select * from A where idB='".$row['idB']."'
 //and the results of A are $row
 $row['name'] //<-- dont forget this field

Если A.idB = B.idB, мы можем присоединиться к этому. Тогда вы используете только idB и name, поэтому вместо * мы можем использовать эти 2 как из B (потому что $row был из B).

Мы можем отобразить это как половину путевой точки:

select B.idB,B.name from B where status=2
select * from A where A.idB=B.idB

Который, когда мы присоединяемся к ним:

select 
    B.idB,B.name
from 
    B
LEFT JOIN  #left JOIN
    A ON A.idB=B.idB
WHERE
       B.status=2
   AND
       IS NULL A.ibB #records from B where no A.idB exists.

AS Указано в комментариях:

В основном вам нужны все записи из B, у которых нет записи, совпадающей с A.

Для этого мы можем использовать левое соединение. Который будет возвращать все записи со стороны LEFT в JOIN (таблица B) независимо от того, есть ли у них запись JOINED в A с правой стороны.

Тогда нам просто нужно сохранить записи с левой стороны B, которые имеют null для значения A.ibB, что мы можем сделать с IS NULL A.ibB.

Эти пропущенные записи - те, которые мы хотим вставить в конце:


Тогда давайте посмотрим на код PDO:

$q1=$this->pdo->query($sql1);
/// $q1->execute(); <--------------------- no need for this
$result1=$q1->fetchAll(PDO::FETCH_ASSOC);

Теперь $this->pdo->query() возвращает false или объект PDOStatement, а [PDOSTatement]->fetchAll() может быть присоединен с помощью return.

Так что мы можем покончить со всеми этими локальными переменными и записать это так.

 $result1 = $this->pdo->query($sql1)->fetchAll(PDO::FETCH_ASSOC);

Это лучше всего работает, если у вас есть PDO, настроенный на выдачу исключений, тогда вам не нужно беспокоиться о том, что он возвращает FALSE в случае сбоя, поскольку вместо этого он просто генерирует исключение.

Так же, как мы используем строку SQL только один раз, мы можем просто исправить это и избавиться от $sql1. То же самое верно для запроса вставки:

$stmt = $this->pdo->prepare('INSERT INTO A(idB,name) VALUES (:idB,:name)');  

foreach ($result1 as $row) $stmt->execute($row);

Но с одним или двумя примечаниями. ЗДЕСЬ, потому что мы вернули то, что мы извлекли из первого запроса, только к тому, что нам нужно, и все названо одинаково, мы можем просто поместить $row прямо в execute. Другая вещь, на которую стоит обратить внимание, это подготовить запрос вне цикла. Мы можем повторно использовать PDOStatement столько раз, сколько захотим, и БД нужно только интерпретировать SQL в первый раз, что экономит нам немного производительности.

Summery

Если вам легче читать, сохраняйте локальные переменные. Мне нравится от них избавляться, потому что я не очень люблю печатать, потому что я пишу тонну кода, поэтому я стараюсь писать столько, сколько мне нужно, для выполнения работы. Но я давно этим занимаюсь, поэтому довольно легко могу читать более сложный код.

Я просто хотел показать это таким образом, потому что, я не думаю, что это хорошо отражено во многих примерах того, насколько вы можете уменьшить свой код и при этом сделать то же самое. И чем меньше кода, тем меньше кода для отладки (до предела).

Приветствие.

0 голосов
/ 02 ноября 2018

Если вы используете базу данных MySQL, вы можете сделать это с помощью одного запроса, используя синтаксис INSERT ... SELECT ...

INSERT INTO A (`idB`, `name`)
SELECT `idB`, `name` FROM B
WHERE B.status = 2
AND NOT EXISTS (
  SELECT 1 FROM A
  WHERE A.idB = B.idB
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...