Ответы пользователя по тегу PHP
  • Как найти строку по значению и изменить соседнее значение?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WebDiez
    Затупил.. Нашел вариант..

    Пока надо обновлять для строго одной записи - сойдёт. А вообще
    UPDATE request 
    JOIN ( SELECT MAX(id) id 
           FROM request 
           WHERE user_id IN ( '97'  /* список */ )
         ) subquery USING ( id )
    SET request.message = 'text';
    Ответ написан
    Комментировать
  • Как выбрать нужные записи из бд?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT *
    FROM table
    ORDER BY user_id = @user_id DESC, id DESC LIMIT 1

    Если заданный @user_id есть - вернётся соотв. запись. Если таких записей несколько - вернётся запись из них с максимальным id. Иначе вернётся просто запись с макс. id.

    Если же под "Если есть user_id вернуть запись с user_id" разумеется "ну хоть какой-то, лишь бы не NULL", то
    SELECT *
    FROM table
    ORDER BY user_id IS NULL, id DESC LIMIT 1
    Ответ написан
    Комментировать
  • Как правильно будет сделать JOIN?

    @Akina
    Сетевой и системный админ, SQL-программист.
    andry33822, огорчу. Описанная мной в комментарии к вопросу процедура требует ВСТАВКИ записи в таблицу users и ОБНОВЛЕНИЯ существующей записи в таблице users_apikey. То есть INSERT в одну таблицу + UPDATE другой таблицы.

    В один запрос это никаким образом не укладывается. Но задачу можно решить. Триггером.

    CREATE TRIGGER tr_assign_apikey_to_user
    AFTER INSERT 
    ON users
    FOR EACH ROW
    UPDATE users_apikey SET username = NEW.username WHERE username = '' LIMIT 1;


    DEMO fiddle

    Правда, триггер простейший, и ничего не проверяет. По-хорошему надо как минимум проверить, что свободный apikey - есть, и если нет - то сгенерировать ошибку добавления юзера. Ну и не исключаю дополнительных условий - например, мне лично запись в apikey, не имеющая вменяемого значения в поле namekey, как-то не нравится.
    Ответ написан
    Комментировать
  • Как прибавить к текущей дате дни?

    @Akina
    Сетевой и системный админ, SQL-программист.
    В случае MySQL просто прибавить соотв. INTERVAL:
    INSERT INTO `order`
    SET ...
        date_end = CURRENT_DATE + INTERVAL :days_to_add DAY

    В других СУБД - использовать функцию DATEADD().
    Ответ написан
    Комментировать
  • Как изменять значение в бд по времени?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Информация о том, что пользователь оплатил подписку заносится в бд (есть отдельная строка, в которой изначальное значение равно нулю, а при оплате меняется на 1).

    В комплекте с информацией о факте оплаты должна существовать и информация о дате-времени открытия доступа по подписке. Кстати, в этом случае сама информация о факте оплаты не нужна, достаточно просто самого факта наличия момента оплаты либо срока действия оплаченного доступа.

    значение сменилось на 1, а потом через месяц само сменилось на 0.

    Для этого у MySQL есть свой встроенный планировщик. Запускаем, создаём процедуру, которая выполняется, например, ежеминутно, и обнуляет поле доступа для всех записей, у которых разница между текущим штампом времени и штампом времени открытия доступа превышает срок доступа (хардкод, либо взятый из служебной таблицы или даже из обрабатываемой записи).

    MySQL 8.0 Reference Manual / Stored Objects / Usin...
    Ответ написан
    Комментировать
  • База данных MySql, как сделать переменную, с индивидуальным значением для всех аккаунтов?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Ну вообще-то под такие цели обычно создаётся специальная служебная таблица.
    Ответ написан
    2 комментария
  • Есть вариант сохранить в поле json (mysql) массив с нужным порядком?

    @Akina
    Сетевой и системный админ, SQL-программист.
    фишка в том, что в бд порядок меняется, условно скажем, после того, как вытащишь из бд и превратишь обратно в массив, он уже принимает вот такой вид

    Согласно описанию формата, порядок элементов внутри объекта не существует (вернее, не определён), и его поддержание не гарантируется. В отличие от массива.
    Так что если порядок важен, то каждая запись должна быть преобразована в отдельный объект, а все они - сложены в массив в нужном порядке, т.е. JSON должен выглядеть, например, так:
    '[{"a":1}, {"b":2}, {"c":3}]'

    Я его превращаю в json (json_encode), и кладу в бд.

    Покажите точно, как выглядит этот JSON.
    Покажите точный CREATE TABLE таблицы, в которую кладёте.
    Покажите, как точно выглядит в таблице положенное туда JSON значение.
    Покажите точно это же JSON значение после обратного извлечения.

    Да, всё это - для одного и того же JSON.
    Ответ написан
    Комментировать
  • Как заменить строку на цифры у оператора IN?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Если передаваемый параметр - это CSV идентификаторов, то следует использовать
    SELECT *
    FROM `users`
    WHERE FIND_IN_SET(id, ?);


    Примечание 1. CSV не должен содержать никаких паразитных пробелов (а то любят всякие "украшатели" понатыкать пробелов после запятой).
    Примечание 2. Такой запрос - гарантированный фуллскан. Зато не будет инъекции.

    PS. В принципе этот CSV несложно довести до состояния JSON array (всего-то две скобки добавить) - тогда можно применить JSON_CONTAINS(), что может быть немного быстрее. А уж если переданный JSON распарсить на отдельные значения с помощью JSON_TABLE(), так ещё и от фуллскана избавимся (правда, версия сервера нужна достаточно свежая).
    Ответ написан
    2 комментария
  • Как правильно конвертировать SQL дату, чтобы корректно принять и отправить?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Хранить следует в формате для хранения даты (с учётом необходимости дополнительного хранения информации о зоне времени). Если СУБД имеет встроенный тип DATE - следует использовать его. Если такого нет - DATETIME. Если и такого нет - TIMESTAMP.

    Вводить следует в том формате, в каком согласно документации следует представлять литералы даты.
    Ответ написан
    Комментировать
  • Как добавить данные для каждого массива в трехмерным массиве PHP?

    @Akina
    Сетевой и системный админ, SQL-программист.
    $db->prepare("SELECT comments.id, ... , users.login
                       , :me AS me 
                  FROM `comments` ... ");
        $comments->execute([
        "id_post" => $dataAttr,
        "me" => $_SESSION["user"]["id_user"],
        ]);

    или типа того...
    Ответ написан
    1 комментарий
  • При sql запросе писать с кавычками или без?

    @Akina
    Сетевой и системный админ, SQL-программист.
    1) Как безопаснее и правильней писать имя таблицы и базы с кавычками или без кавычек . Если с кавычками то с двойными или одинарными.


    В MySQL используется три разных типа кавычек.

    1. Прямая кавычка '

    Используется для обрамления литералов, требующих такого обрамления, а именно: строковые, даты-времени, JSON, компоненты имени учётной записи и пр. Подробнее см. Literal Values и Specifying Account Names

    2. Обратная кавычка `

    Используется для обрамления имён объектов (БД, таблиц, полей, имён функций/процедур и пр.).

    Если имя объекта не содержит нелегитимных символов (подробнее см. Schema Object Names), не является служебным или зарезервированным словом (см. Keywords and Reserved Words), использование обратной кавычки опционально, иначе обязательно.

    3. Двойная кавычка "

    Используется для обрамления строковых компонентов (имя, значение) для типа данных JSON (внутри строкового литерала с JSON-значением, ограниченного одинарными кавычками). Допускается использование вместо одинарной кавычки для обрамления литералов.

    При включённом ANSI_QUOTES в SQL Mode указанные использования отменяются, и двойная кавычка используется для обрамления имён объектов (т.е. дублирует использование обратной кавычки).

    ИТОГО с точки зрения безопасности:

    - имена объектов ВСЕГДА обрамлять ТОЛЬКО обратной кавычкой
    - литералы, требующие обрамления - обрамлять ТОЛЬКО одинарной кавычкой
    - двойную кавычку использовать ТОЛЬКО как символ в составе литерала (строкового, JSON)
    Ответ написан
    1 комментарий
  • Doctrine как получить расхождение двух запросов?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Делаю так:
    SELECT * FROM tbl1 EXCEPT SELECT * FROM tbl2

    Структуры таблиц совпадают?

    Тогда
    SELECT t1.*
    FROM tbl1
    LEFT JOIN tbl2 ON tbl1.primary_key = tbl2.primary_key
    WHERE t2.primary_key IS NULL

    Это должно без проблем отображаться на синтаксис фреймворка.
    Ответ написан
  • Как правильно составить sql запрос с условием?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Схематично:
    SELECT orders.column,
           COALESCE(books.column, deposits.column) AS column
    FROM orders 
    LEFT JOIN books ON orders.type = 'book' AND orders.id = books.order_id
    LEFT JOIN deposits ON orders.type = 'deposit' AND orders.id = deposits.order_id
    Ответ написан
    1 комментарий
  • Как планировать даты по указанному расписанию (из списка времен)?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Упрощённый пример того, как ежедневно в 09:20, 09:40, 11:20 и 11:40 вставлять в таблицу запись с заданными значениями.

    Таблицы:

    1. Значения для вставки
    CREATE TABLE data ( 
        data_id INT AUTO_INCREMENT PRIMARY KEY,
        data_for_insertion VARCHAR(255) );
    INSERT INTO data VALUES (1, 'Новое сообщение по расписанию', DEFAULT);

    2.Расписание.
    CREATE TABLE schedule ( 
        schedule_id INT AUTO_INCREMENT PRIMARY KEY,
        data_id INT,
        FOREIGN KEY (data_id) REFERENCES data (data_id) ON DELETE CASCADE ON UPDATE CASCADE,
        shedule_time TIME );
    INSERT INTO schedule VALUES 
    (NULL, 1, '09:20'), 
    (NULL, 1, '09:40'), 
    (NULL, 1, '11:20'), 
    (NULL, 1, '11:40');

    3. Таблица, куда надо вставлять записи
    CREATE TABLE main ( 
        main_id INT AUTO_INCREMENT PRIMARY KEY,
        inserted_data VARCHAR(255),
        created_as DATETIME DEFAULT CURRENT_TIMESTAMP );

    Процедура, которая будет вставлять данные
    CREATE EVENT schedule
    ON SCHEDULE EVERY 1 MINUTE
    DO
        INSERT INTO main (inserted_data)
        SELECT data.data_for_insertion
        FROM data
        JOIN schedule USING (data_id)
        WHERE schedule_time > CURRENT_TIME - INTERVAL 1 MINUTE
          AND schedule_time <= CURRENT_TIME;

    Всё. Осталось только разрешить использование Event Scheduler и запустить его.

    Теперь только знай себе в своей программе на PHP правь данные в таблицах 1 и 2. Причём в любое время... В части выполнения нужного действия в нужное время MySQL всё будет делать сам, и никакого PHP ему не требуется.
    Ответ написан
    Комментировать
  • Как выбрать конкретную строку из Mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT SUBSTRING_INDEX(SUBSTRING(full FROM 30 + LOCATE('https://www.youtube.com/embed/', full)), '"', 1)
    FROM params
    WHERE LOCATE('https://www.youtube.com/embed/', full)
    -- AND id=247397
    Ответ написан
  • Как вывести всех родителей у подкатегории до главной категории?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WITH RECURSIVE
    cte AS ( SELECT *, 1 level
             FROM category 
             WHERE id = $category_id
             UNION ALL
             SELECT cat.*, cte.level + 1
             FROM category cat
             JOIN cte ON cat.id = cte.parent_id )
    SELECT *
    FROM cte
    ORDER BY level;

    Для древних версий:
    SELECT CONCAT_WS('=>', c1.id, c2.id, c3.id, c4.id, c5.id) path
    FROM category c1
    LEFT JOIN category c2 ON c1.parent_id = c2.id
    LEFT JOIN category c3 ON c2.parent_id = c3.id
    LEFT JOIN category c4 ON c3.parent_id = c4.id
    LEFT JOIN category c5 ON c4.parent_id = c5.id
    WHERE c1.id = $category_id

    Ну соответственно подрихтовать до нужного вида выходного набора.
    Ответ написан
    4 комментария
  • Проблема с regexp на mysql 8.0.26?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Согласно MySQL 5.7 Reference Manual / ... / Regular Exp...

    [[:<:]], [[:>:]]

    These markers stand for word boundaries.


    Согласно MySQL 8.0 Reference Manual / ... / Regular Exp...

    The Spencer library supports word-beginning and word-end boundary markers ([[:<:]] and [[:>:]] notation). ICU does not. For ICU, you can use \b to match word boundaries; double the backslash because MySQL interprets it as the escape character within strings.


    Так что подход правильный.

    Но Вы не учитываете, что слэш надо квотить как для PHP, так и для MySQL. Т.е. их должно быть не два, а четыре.
    Ответ написан
    Комментировать
  • Как отсортировать разные группы по разным методам?

    @Akina
    Сетевой и системный админ, SQL-программист.
    ORDER BY CASE WHEN parent_id IN (0,51,52)
                  THEN 1
                  ELSE 2 
                  END ASC,
             CASE WHEN parent_id IN (0,51,52)
                  THEN name
                  ELSE ''
                  END ASC,
             CASE WHEN parent_id IN (0,51,52)
                  THEN ''
                  ELSE name
                  END DESC
    Ответ написан
    Комментировать
  • Как определить изменения для товаров в заказе?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Как бы вы поступили в подобной ситуации.

    Да как обычно при хранении timeline. Первым делом настраиваем права и запрещаем обновление и удаление. Записи можно только добавлять. Вторым - вводим автоматически присваиваемое поле штампа времени создания версии заказа. И, собственно, всё.

    Для получения состояния заказа на любой момент времени (актуальное состояние или в прошлом) используем один несложный запрос. То же - если нужно получить разницу между текущим и предыдущим состояниями. Оконные функции делают это на счёт "раз".

    И никакие логи не нужны.
    Ответ написан
    5 комментариев
  • Как вычесть у одного пользователя число и добавить его другому?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Лучше делать всё в одном запросе:
    UPDATE users u1
    CROSS JOIN users u2
    SET u1.amount = u1.amount - $summa,
        u2.amount = u2.amount + $summa
    WHERE u1.id = $client
      AND u2.id = $shop;


    Во-первых, один запрос - проще. Пусть даже сам запрос и сложнее.

    Во-вторых, если, например, в структуре таблицы имеется ограничение CHECK (amount >= 0), а сумма такова, что у клиента баланс уйдёт в минус - в таком случае ни одна из записей не будет изменена.
    Ответ написан
    Комментировать