Проблема при добавлении данных в бд

Есть массив логов, у которых есть данные об ip, времени, url, статусе и агенте. Структура таблицы с логами:

CREATE TABLE `logs` (
  `ip` varchar(32) NOT NULL,
  `date` varchar(64) NOT NULL,
  `url_id` int NOT NULL,
  `status_id` int NOT NULL,
  `agent_id` int NOT NULL
) 

CREATE TABLE `agents` (
  `id` int NOT NULL,
  `agent` varchar(256) NOT NULL
) 

CREATE TABLE `statuses` (
  `id` int NOT NULL,
  `status` int NOT NULL
)

CREATE TABLE `urls` (
  `id` int NOT NULL,
  `url` varchar(256) NOT NULL
)

Собственно url_id, status_id и agent_id это вторичные ключи для других таблиц.

Вот так пытаюсь заносить данные:

function edit_log(&$log_data)
{
    $db = new PDO('mysql:host=localhost;dbname=logsdb', 'root', '');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $log_data["date"] = $log_data["date"]->format('Y-m-d H:i:s');

    // Проверяем, существует ли указанный url в таблице urls
    $url_check = $db->query("SELECT `id` FROM `urls` WHERE `url` = '${log_data["url"]}'");
    if ($url_row = $url_check->fetch() == false) {
        $db->query("INSERT INTO `urls` (`url`) VALUES ('${log_data["url"]}')");
        $url_check = $db->query("SELECT `id` FROM `urls` WHERE `url` = '${log_data["url"]}'");
        $url_row = $url_check->fetch();
        $log_data["url"] = $url_row['id'];
    } else {
        $log_data["url"] = $url_row['id'];
    }

    // Проверяем, существует ли указанный статус в таблице statuses
    $status_check = $db->query("SELECT `id` FROM `statuses` WHERE `status` = '${log_data["status"]}'");
    if ($status_row = $status_check->fetch() == false) {
        $db->query("INSERT INTO `statuses` (`status`) VALUES (${log_data["status"]})");
        $status_check = $db->query("SELECT `id` FROM `statuses` WHERE `status` = '${log_data["status"]}'");
        $status_row = $status_check->fetch();
        $log_data["status"] = $status_row['id'];
    } else {
        $log_data["status"] = $status_row['id'];
    }

    // Проверяем, существует ли указанный агент в таблице agents
    $agent_check = $db->query("SELECT `id` FROM `agents` WHERE `agent` = '${log_data["agent"]}'");
    if ($agent_row = $agent_check->fetch() == false) {
        $db->query("INSERT INTO `agents` (`agent`) VALUES ('${log_data["agent"]}')");
        $agent_check = $db->query("SELECT `id` FROM `agents` WHERE `agent` = '${log_data["agent"]}'");
        $agent_row = $agent_check->fetch();
        $log_data["agent"] = $agent_row['id'];
    } else {
        $log_data["agent"] = $agent_row['id'];
    }
}

$count = count($logs); // Количество прочитанных логов
    if ($count) {
        $log_data = $logs[0];
        edit_log($log_data);
        $log_string = "('${log_data["ip"]}', '${log_data["date"]}', ${log_data["url"]}, ${log_data["status"]}, ${log_data["agent"]})";
        for ($i = 1; $i < $count; $i++) {
            $log_data = $logs[$i];
            edit_log($log_data);
            $log_string .= ", ('${log_data["ip"]}', '${log_data["date"]}', ${log_data["url"]}, ${log_data["status"]}, ${log_data["agent"]})";
        }
        $sql_query = "INSERT INTO `logs`(`ip`, `date`, `url_id`, `status_id`, `agent_id`) VALUES " . $log_string;
        $db->query($sql_query);
    }

то есть в функции я проверяю, есть ли в таблице запись об url/статусе/агенте, и если нет, то добавляю их и беру id вставленной записи(авто-инкрементируемый), который потом вставляю в главную таблицу.

Но почему-то при выполнении появляется ошибка:

<b>Fatal error</b>:  Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ', 2), ('213.87.153.60', '2020-09-01 03:16:09', 3, , ), ('46.229.168.163', '2020-' at line 1

то есть почему-то в главную таблицу не вставляются данные о вторичных ключах

Подскажите, в чём может быть проблема?


Ответы (1 шт):

Автор решения: Akina

Структура.

CREATE TABLE `agents` (
  `agent_id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `agent` varchar(256) NOT NULL UNIQUE
);

CREATE TABLE `statuses` (
  `status_id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `status` int NOT NULL UNIQUE
);

CREATE TABLE `urls` (
  `url_id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `url` varchar(256) NOT NULL UNIQUE
);

CREATE TABLE `logs` (
  `ip` varchar(32) NOT NULL,
  `date` varchar(64) NOT NULL,
  `url_id` int NOT NULL, FOREIGN KEY (url_id) REFERENCES urls (url_id),
  `status_id` int NOT NULL, FOREIGN KEY (status_id) REFERENCES statuses (status_id),
  `agent_id` int NOT NULL, FOREIGN KEY (agent_id) REFERENCES agents (agent_id)
);

Вставка:

INSERT IGNORE INTO agents (agent) VALUES ($agent);
INSERT IGNORE INTO statuses (status) VALUES ($status);
INSERT IGNORE INTO urls (url) VALUES ($url);
INSERT INTO logs (ip, `date`, url_id, status_id, agent_id)
    SELECT urls.url_id, statuses.status_id, agents.agent_id
    FROM       urls 
    CROSS JOIN statuses 
    CROSS JOIN agents
    WHERE urls.url = $url 
      AND statuses.status = $status 
      AND agents.agent = $agent;

А всю вон ту ерунду с проверками "существует или нет" - в мусор.

И если используешь PDO, то надо не в тело запроса вставлять значения (здравствуй, инъекция!), а передавать значения в подготовленный запрос как параметры.

→ Ссылка