Ответы пользователя по тегу MySQL
  • Почему данные заказа не отправляются в базу данных?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Потому что вы вообще никак не отреагировали на те ответы, которые вам дали в прошлый раз на этот же самый вопрос.
    Вам написали, как правильно выполнять запросы. Вы это сделали?
    Вам написали, какие действия выполнять, если код не работает. Вы их выполнили?
    Вы так и планируете ходить на Хабр каждый раз, когда код не работает? Вот прямо серьёзно? Это, по-вашему, именно то, чем занимаются программисты?

    Пожалуйста, прочитайте ответы, которые вам давали на этот вопрос в прошлый раз и начните уже им следовать.
    Иначе программирование для вас так и останется игрой в прятки в темноте - "ой, что-то написала, не работает! Ой, что-то другое написала - работает!".

    К тому что написано в предыдущем ответе надо добавить только одно: перед
    new mysqli(...);
    надо всегда писать
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    чтобы база данных сама сообщала, почему не может выполнить запрос. Если дело именно в нём.
    Ответ написан
  • Как правильно объединить два запроса в один?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Правильно будет не объединять запросы в один без необходимости.
    Ответ написан
  • Как сделать так, что бы при пустом запросе в базу выводились ВСЕ значения?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    есть немного замороченный способ, но в целом он требует куда меньше кода
    WHERE (account_id=? OR ? is null)  AND (priority=? OR  ? is null)

    Чтобы его использовать, надо всего лишь передавать каждую переменную в запрос по два раза (и следить, чтобы пустые переменные содержали null).

    Другим вариантом является условная сборка запроса.
    Для этого мы собираем условия и переменные для них в массивы

    $conditions = [];
    $parameters = [];
    if ($account_id)
    {
        $conditions[] = 'account_id=?';
        $parameters[] = $account_id;
    }
    if ($priority )
    {
        $conditions[] = 'priority =?';
        $parameters[] = $priority;
    }

    собираем из условий запрос и выполняем его, привязывая все переменные разом
    тут из сложного будет привязка переменных из массива, но благодаря оператору распаковки аргументов это не так уж и сложно.
    if ($parameters)
    {
        $sql .= " WHERE ".implode(" AND ", $conditions);    
        $stmt = $db->prepare($sql);
        $stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
        $stmt->execute();
        $result = $stmt->get_result();
    } else {
        $restult = $db->query($sql);
    }
    Ответ написан
    3 комментария
  • Как вытащить данные из stmt?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    вместо store_result(); надо писать get_result();
    этот метод даст вам привычный ресурс, из которого уже можно получить данные обычным способом
    $stmt = $link->prepare("SELECT * FROM users WHERE id=?");
    $stmt->bind_param('i', $value);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    Ответ написан
    5 комментариев
  • В чём ошибка подключения к безе по PDO?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ошибку указывает сама PDO.
    Для этого в настройках надо указать PDO::ERRMODE_EXCEPTION - это уже сделано.
    После этого, в случае, если выполнение запроса завершится ошибкой, РНР об этом сообщит.
    Надо только, опять же, не забыть включить отображение (на домашнем компьютере) или логирование (на боевом сервере) ошибок РНР.

    Если же РНР никаких ошибок не выводит, то их и нет.
    Ответ написан
    4 комментария
  • Что нужно отправить на сервер, чтобы php понял это, как null?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Вопрос неверный. В стиле анекдота "у таракана уши в ногах".
    Разумеется, сервер всё прекрасно видит.
    чтобы РНР принял null, надо отправить на сервер null. Удивительно, но факт.
    var_dump(json_decode('{ 
        "name": ["i", "b"], 
        "val": [null]
    }',1));


    А вот что там делает код на этом сервере - никто не знает.
    И обращаться надо к автору кода. А не в Спортлото

    Скорее всего там либо array_filter, либо isset/empty($array['val']);
    Ответ написан
    4 комментария
  • Как получить список таблиц и полей без индекса (mysql), по которым происходит выбор?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Джинны и феи бывают только в сказках, дружок.

    Сидеть разбирать вручную каждый запрос через explain - именно так это и делается.
    Потому что само по себе механические впиливание индекса не решает вообще ничего.
    Оптимизация запроса - это далеко совсем не только "создать индекс на поле, по которому идёт выборка"
    Потому что этот индекс может не сработать
    Потому что может быть нужен совсем другой индекс.
    Потому что избыточные индексы могу наоборот замедлить приложение.
    Ответ написан
    Комментировать
  • Как сделать prepare запрос без bind_params?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Сначала я вообще ничего не понял, но поразмыслив, разобрался, про что этот вопрос.
    И поскольку он повторяет весьма распространённые заблуждения, то будет полезно на него подробно ответить.

    Можно ли как-то безопасно сделать такой запрос, который я соберу в строку?

    Нет, нельзя.

    Это распространённое, но очень смешное заблуждение. Если подумать, то само по себе prepare() ни от чего не защищает. Это не волшебное слово типа "Экспекто патронум!" - написал, и дальше уже можно не париться, оно само как-то магически защитит от инъекций. В реальной жизни таких слов ещё, увы, не придумали. А защищает именно замена актуальных переменных в запросе на знаки подстановки и последующая привязка через bind_param. А prepare просто говорит базе данных ,что запрос еще рано исполнять, это только схема запроса, а данные для него приедут позже.

    Я так понял, что если я выполняю $sql = $mysqli->prepare($request), то выполнится только один запрос, который первый, даже, если в него вложен будет второй, пусть я его строкой и засунул.

    Это тоже очень распространённое, и очень вредное заблуждение. Запрос выполнится только один, да. Тут всё верно. Но проблема в том, что SQL инъекция - это не один запрос
    INSERT INTO students (name) VALUES ('Robert');DROP TABLE students;
    , который рисуют в примерах для первоклассников. Инъекция - это любой посторонний код в запросе, вообще любой.

    Поэтому собирать в строку надо всё равно запрос со знаками подстановки, а потом его выполнить. Благо, в 5.6 версии пхп появился оператор распаковки параметров, который значительно облегчил эту задачу.

    Не хочется использовать лишние переменные и обработку для типов данных

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

    Для запроса, который приведен в примере, код будет относительно простым, поскольку заменяется на вызов IN:

    $names = ["Stepan" , "Stiv"];
    $in    = str_repeat('?,', count($names) - 1) . '?'; // получаем строку вида "?,?"
    $sql   = "SELECT * FROM users WHERE name IN ($in)"; // поставляем её в SQL
    $stmt  = $mysqli->prepare($sql); // prepare
    $types = str_repeat('s', count($names)); // получаем строку "sss" по количеству переменных
    $stmt->bind_param($types, ...$names); // привязываем наш массив
    $stmt->execute(); // выполняем
    $result = $stmt->get_result(); // дальше всё как обычно
    $data = $result->fetch_all(MYSQLI_ASSOC);


    Для более сложных запросов принцип будет тот же: собираем строку с плейсхолдерами, а переменные для неё - в массив. И потом выполняем так же через bind_param($types, ...$parameters);, как-то так:

    $conditions = [];
    $parameters = [];
    if (!empty($_GET['name']))
    {
        $conditions[] = 'name LIKE ?';
        $parameters[] = '%'.$_GET['name']."%";
    }
    // любое количество таких условий
    if ($conditions)
    {
        $sql .= " WHERE ".implode(" AND ", $conditions);
    }

    и дальше выполняем обычным порядком.

    Ну и в завершение, ответим на вопрос из заголовка буквально
    Как сделать prepare запрос без bind_params?

    Как правильно заметил TheAndrey7 в комментариях, начиная с версии 8.1 можно будет отправить переменные сразу в execute():

    $names = ["Stepan" , "Stiv"];
    $in    = str_repeat('?,', count($names) - 1) . '?';
    $sql   = "SELECT * FROM users WHERE name IN ($in)";
    $stmt  = $mysqli->prepare($sql); 
    $stmt->execute($names); 
    $data = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    Ответ написан
    3 комментария
  • Как убить ошибку Error Code: 1114. The table '...\#sqlc60_9_37' is full?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    alter table test add key (sec_code, class_code)
    и смотреть, уйдёт ли temporary из поля Extra в EXPLAIN

    И вообще - в первую очередь смотреть EXPLAIN, а не возиться с этой ерундой.
    и убирать using temporary ДО того как временной таблице перестанет хватать места на диске.
    Потому что у меня даже и без этой ошибки инфаркт будет, если я увижу такой запрос в продакшен коде.
    Ответ написан
    3 комментария
  • Как связать новость на одной странице с ее развернутой формой на другой?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Поднимаем глаза наверх. Только не к Небу, а чуть ниже. К адресной строке своего браузера (пока она ещё там есть, и её не отменили улучшаторы из компании альфабет).
    И - о чудо! - видим там ссылку вида qna.habr.com/q/1077518
    Казалось бы, что могут означать эти загадочные цифры?.. ;-)
    spoiler

    Для "моего первого скрипта на пхп" правда там будет не /q/1077518, а news.php?id=1077518.
    После чего в скрипте news.php вожделенное число будет доступно в переменной $_GET['id']
    Содержимое которой можно будет использовать для запроса строки из БД.
    Только не так как это показано во всех видео на ютубе, а нормально:

    $query = "SELECT * FROM news WHERE id=?";
    $stmt = $conn->prepare($query);
    $stmt->bind_param("s", $_GET['id']);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();


    в переменной $row будет содержимое нужной строки из БД


    А так-то вопрос, конечно, про SQL ;-)
    Ответ написан
    Комментировать
  • Как корректно реализовать автовход пользователя на сайт?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Очень правильный вопрос. Разумеется, с таким подходом зайдет кто угодно.

    поэтому надо в таблицу users добавить поле autoenter, и если пользователь выбирает автологин, то в него записывать значение bin2hex(random_bytes(16)); и его же записывать в куку.
    Ответ написан
  • Как сделать дамп большой базы данных?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Ответ написан
    Комментировать
  • Хранение значений массива в БД?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Это задание, а не вопрос.
    Ответ написан
    5 комментариев
  • Как правильно составить запрос к БД?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Стандартный способ:
    SELECT count(*) FROM shop LEFT JOIN shopData ON shopData.shop_id=shop.id WHERE shopData.shop_id IS NULL

    Но следующий способ должен быть быстрее
    SELECT count(*) FROM shop WHERE NOT EXISTS (SELECT 1 FROM shopData WHERE shop_id=shop.id)
    Ответ написан
    2 комментария
  • Как сделать запрос через тройную связь, при это получая все связанные значения 3 таблицы в массив к 1 записи?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    GROUP_CONCAT()
    Но это редко бывает полезно поскольку обычно нужны не только названия ролей, но и их идентификаторы
    Если хочется "одной строчкой", то надо осваивать продвинутые ORM типа Doctrine
    Ответ написан
    Комментировать
  • Как перебрать все значения строки разделенные запятой в mysql?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    В бд не должно быть строк, которые содержат значения, разделенные запятой. Для этого в бд есть таблицы и строки.

    И тогда вопроса как прочитать значение никогда не возникнет
    Ответ написан
    4 комментария
  • Сколько времени должен занимать такой запрос MySQL?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Я не очень понимаю во всех этих AWS, но расход памяти в три гига - это какая-то чушь.

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

    Вообще цифры странные. Полное ощущение что индекс не влезает в память и идёт постоянная работа с диском. Но тогда должен процессор зашкаливать. А он на 5 процентах. Вот не понимаю я эти ваши авс.
    Ответ написан
  • Почему в базу записываются иероглифы?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Хрестоматийный пример того, как не надо задавать вопросы.

    "Я там что-то сделал, получилось каля-маля. Колеса в разный цвет красил. Не помогает".

    Буквальный ответ на вопрос из заголовка: потому что кодировка данных не совпадает с той, которую ждёт база.
    Ответ написан
    Комментировать
  • Как перейти с mysql на elasticsearch?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Никак. "перейти" с базы данных на поисковый движок нельзя.
    Можно сделать поисковый сервис, который будет индексировать информацию, взятую из бд

    На основе этого сервиса сделать полнотекстовый и фасетный поиск.
    А текущую базу данных оставить как есть. Только запросы оптимизировать, чтобы "скорость работы не понижалась"
    Ответ написан
    3 комментария
  • Безопасность кода php -> mysql?

    ipatiev
    @ipatiev Куратор тега PHP
    Потомок старинного рода Ипатьевых-Колотитьевых
    Вопрос хороший, характерностью имеющихся в коде ошибок.

    На первом месте тут конечно , конечно, незабвенный Бобби Тейблс и его прошаренная мамаша.
    Таблицу здесь удалить не получится, но вот скачать всю базу - запросто.

    Плюс мамаша конечно тупит. Данные надо не "экранировать", поскольку почти никто не понимает, что это значит, а отправлять в БД отдельно от запроса.

    Но меня здесь больше интресует не безопасность, а осмысленность данного кода.
    Если элемент "login" попадает в сессию в результате авторизации, то зачем снова делать все эти 100500 запросов в БД?
    Я бы этот код сократил до
    <?php
    require_once $_SERVER["DOCUMENT_ROOT"] . "/engine/core/session.php";
    if (empty($_SESSION["user_id"])) {
        include "login.php";
        die;
    }

    и поместил в profile.php

    При этом убедившись, что код собственно авторизации выглядит как-то так

    $stmt = $conn->prepare("SELECT * FROM users_all WHERE name=?");
    $stmt->bind_param("s", $_POST['name']);
    $stmt->execute();
    $user = $stmt->get_result()->fetch_assoc();
    
    if ($user && password_verify($_POST['password'], $user['password']))
    {
        $_SESSION['user_id'] = $user['id'];
        header("Location: /profile.php");
        die;
    }
    Ответ написан
    Комментировать