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

    @Akina
    Сетевой и системный админ, SQL-программист.
    Легко решается триггером. Пример:

    - исходная таблица:
    CREATE TABLE users (
      id INT AUTO_INCREMENT PRIMARY KEY,
      username VARCHAR(100),
      created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    );


    - триггер:

    CREATE TRIGGER tr_users_bi
    BEFORE INSERT ON users
    FOR EACH ROW
    BEGIN
      DECLARE allowed_created_at DATETIME;
      DECLARE error_message_text VARCHAR(64);
      SELECT MAX(created_at) + INTERVAL 12 HOUR INTO allowed_created_at
      FROM users
      WHERE username = NEW.username;
      IF NEW.created_at < allowed_created_at THEN
        SET error_message_text = CONCAT('Регистрация возможна не ранее ', allowed_created_at);
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = error_message_text; 
      END IF;
    END


    DEMO fiddle

    PS. Надеюсь, получение сгенерированного сообщения об ошибке и показ его юзеру не составит проблемы..
    Ответ написан
    Комментировать
  • Почему paragonie/easydb не пропускает слэши?

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

    Рекомендую включить временно General Log, и посмотреть, какой именно текст запроса получает MySQL. После чего отрихтовать текст запроса.

    В крайнем случае
    WHERE `value` LIKE CONCAT('%', CHAR(92), CHAR(92), '%')
    Ответ написан
    Комментировать
  • Как распределить число равномерно?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Обычный подход - тупо:

    Количество(Склад Номер Х) = ВсегоТовара * НомерСклада / ВсегоСкладов - Количество(Склады Номер 1 .. Х-1)


    Т.е. если, как в вопросе, три склада и 5 товаров:

    Склад 1: количество = 5 * 1 / 3 - 0 = 1,666 = 2 штуки
    Склад 2: количество = 5 * 2 / 3 - 2 = 1,333 = 1 штука
    Склад 3: количество = 5 * 3 / 3 - (2 + 1) = 1,666 = 2 штуки


    $amount = 5;
    $num = 3;
    
    for($used = 0, $i = 1; $i <= $num; $i++) {
      $used += ($current = round($amount * $i / $num - $used));
      echo("$i: $current\n");
    }


    https://phpize.online/sql/mysql57/undefined/php/ph...
    Ответ написан
  • Некоторые бинарные строки не определяются по оператору LIKE, проблема не дебажится, в чём может быть причина?

    @Akina
    Сетевой и системный админ, SQL-программист.
    LIKE в принципе не пригоден для указанной операции. Это чисто текстовый оператор. В частности, он безусловно применяет к обоим операндам регистронезависимый collation - в этих условиях сравнение БИНАРНЫХ строк способно давать весьма неожиданные эффекты.

    Если надо работать именно с бинарными строками - всё плохо. В MySQL нет нормальных функций для работы с ними.

    Для решения задачи рекомендую преобразовать бинарную строку в шестнадцатеричное представление, укоротить до 40-символьного (что соответствует 20-байтовому бинарному значению), преобразовать обратно, и сравнить.

    WHERE CONV(LEFT(HEX('$entered_hash'), 40), 16, 10) = correct_hash


    К тому же такое условие SARGable.

    PS. В выражении
    WHERE '{value1}' = '{value2}' OR '{value1}' LIKE '{value2}%'
    первое условие заведомо лишнее (ведь если оно выполняется, то и второе тоже выполняется).
    Ответ написан
    7 комментариев
  • MySQL PDO, Почему все значения при выборке типа string?

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

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

    Предположу, что эмуляция - процесс двусторонний. То есть не только на пути "туда", но и на обратном пути. Что при дополнительной обработке, которую требует настройка PDO::ATTR_EMULATE_PREPARES => true, корёжит тип данных.

    На всякий случай проверьте, не вызывает ли изменение этого флага корректировки других флагов. В частности, PDO::ATTR_STRINGIFY_FETCHES.
    Ответ написан
  • Как объединить запросы?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Два LEFT JOIN, условие связывания - по id и определённому значению типа.
    Ответ написан
    Комментировать
  • Как получать данные из формы на сайте в разные таблицы БД?

    @Akina
    Сетевой и системный админ, SQL-программист.
    При добавлении набора данных в связанные таблицы (а по большому счёту - вообще всегда) следует забыть о существовании INSERT .. VALUES и пользоваться исключительно INSERT .. SELECT. Первый запрос вставляет запись в основную таблицу, второй вставляет в зависимую, получая необходимое для связывания значение из основной по известным критериям отбора (по только что вставленным значениям, либо, в случае MySQL, из LAST_INSERT_ID).
    Ответ написан
    Комментировать
  • Как вывести из sql таблицы все строки с совпадающими значениями?

    @Akina
    Сетевой и системный админ, SQL-программист.
    WITH cte AS (
        SELECT a, b, c, COUNT(*) OVER (PARTITION BY a, c) cnt
        FROM table
    )
    SELECT a, b, c
    FROM cte 
    WHERE cnt > 1
    Ответ написан
    1 комментарий
  • Как получить timestamp,обрезав пустое время?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Не делай так. Единообразие - это очень полезная штука. Если оставить нулевую компоненту времени, то конечному пользователю не придётся думать, действительно ли там нули, или время не отображается из-за какого-то косяка..
    Ответ написан
  • Как оптимально сделать выборку из БД?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Применительно к данной конкретной задаче:
    • СУБД предназначена для хранения и обработки массивов данных.
    • ЯП предназначен для обеспечения пользовательского интерфейса этого процесса и управления им.


    По-моему, выбор стороны для проведения обработки очевиден.
    Ответ написан
    Комментировать
  • Как сделать ежесекундную обработку действий?

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

    @Akina
    Сетевой и системный админ, SQL-программист.
    В синтаксисе MySQL:
    SELECT c.name category_name, p.id post_id, p.name post_name, p.title post_title
    FROM posts p
    JOIN categories c ON p.category_id = c.id
    UNION ALL
    SELECT name, NULL, NULL, NULL
    FROM categories 
    ORDER BY category_name, post_id IS NOT NULL

    Соответственно если в поле post_id обнаруживается NULL, то в этой записи категория, и она рисуется как категория. Если же там не NULL - то это пост, и он рисуется со смещением.

    Дурь, конечно, но для сельской местности сойдёт..
    Ответ написан
    1 комментарий
  • Как узнать CIDR или маску подсети по голому ip адресу?

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

    Максимум - можно получить сведения о диапазоне, в который входит целевой IP, по учётным данным регистратора. Но вот как выделенный диапазон порезал его арендатор, и в какой подсети находится целевой адрес, определить в общем случае невозможно.
    Ответ написан
    3 комментария
  • Как работать с двумя и более базами данных одновременно?

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

    PDO подключается не к базе данных, а к серверу. Просто в процессе подключения некоторая база сервера назначается текущей, и в случаях, когда в имени таблицы отсутствует алиас базы данных, считается, что данная таблица лежит в текущей БД. Кстати, в процессе работы текущая БД может быть и изменена - запросом USE new_default_database_name

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

    А если ещё подключить внешние таблицы (используя FEDERATED ENGINE) - то можно работать и с данными из баз на другом инстансе (сервере) MySQL.
    Ответ написан
    Комментировать
  • Как отсортировать массив?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT name, `text`
    FROM product
    JOIN product_attribute USING (product_id)
    JOIN attribute_description USING (attribute_id)
    -- JOIN attribute USING (attribute_id)   -- таблица в запросе не нужна
    GROUP BY 1, 2
    HAVING COUNT(*) > 1;

    fiddle

    Если нужна именно сортировка как в эталоне - ну добавить ORDER BY MAX(attribute_id)

    Таблица attribute потребуется лишь в случае, если данные из неё нужны (например, в запрос добавится отбор по значению attribute_group_id).

    Если надо сравнивать атрибуты у более чем 2 товаров, то соотв. образом откорректировать условие пост-отбора. Например, для 3 товаров и атрибутов, имеющихся у всех трёх, это будет HAVING COUNT(*) = 3
    Ответ написан
  • Как упорядочить id записей в MySQL?

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

    PRIMARY KEY выполняет в таблице только одну функцию - однозначно идентифицирует запись. В нормальных условиях значение такого поля используется исключительно для связывания данных (установления соответствия), и надобности видеть значение этого поля не существует в принципе.

    То, что хочешь ты - это не что иное как попытка на такое поле взвалить ещё одну функцию - последовательной и неразрывной нумерации. Само поле для этого не предназначено, а попытка всё же реализовать эту хотелку ломает нормальный алгоритм работы, не говоря уж о сопутствующем геморрое с перенумерациями.

    В общем, надо тебе поле-нумератор? создай для этого дела ещё одно поле, просто числовое, не автоинкремент, и заполняй программно. А ещё лучше - организуй односвязный список, и нумеруй прямо в запросе на получение данных.
    Ответ написан
    Комментировать
  • Насчет экспорта таблицы MySQL в Excel средствами PHP?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Выполняем SELECT .. INTO OUTFILE, полученный CSV прекрасно читается в Excel. Т.е. PHP выполняет указанный запрос, а потом, если надо, организует перемещение полученного CSV в нужное место.
    Ответ написан
  • Как держать в таблице только последние 10 записей?

    @Akina
    Сетевой и системный админ, SQL-программист.
    1. Создать сразу 10 записей с достаточно древней датой.
    2. Вместо вставки записи обновлять самую старую:
    UPDATE table
    SET {columns} = {values}
    ORDER BY created_at ASC LIMIT 1;

    Само собой created_at - ON UPDATE CURRENT_TIMESTAMP. Ну или обновлять вручную, если больше заняться нечем.

    Такая технология к тому же позволяет "на лету" изменять лимит записей. Надо больше? вставляем необходимое число записей с датой в далёком прошлом. Надо меньше? удаляем необходимое число самых старых записей.
    Ответ написан
    Комментировать
  • Что быстрее поиск по файлу JSON в PHP или в базе посредством MySQL?

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

    Определитесь. Или в приоритете скорость, или нагрузка. Но не то и другое одновременно.

    Если приоритетна скорость - то данные должны быть предварительно (а не в момент поступления запроса) загружены в PHP и там проиндексированы, причём должен использоваться алгоритм индексирования, обеспечивающий высокую скорость поиска. Поскольку речь идёт о поиске по подстроке, то, вероятно, это суффиксное дерево или аналогичная индексирующая структура.

    Если приоритетна нагрузка - то поиск следует производить средствами СУБД.
    Ответ написан
    Комментировать
  • Как оптимизировать INSERT запросы в PDO(phpmyadmin)?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Пример.

    На стороне PHP имеется массив строк:

    aaa
    bbb
    ccc

    Необходимо записать его в таблицу. Причём уложиться в один запрос. Длина списка, понятно, не фиксирована.

    Первое - объединяем/сериализуем этот массив в одно значение. Допустим, выбрали JSON массив. То есть ["aaa", "bbb", "ccc"]
    И именно этот JSON мы передадим в запрос.

    Далее на стороне MySQL надо разобрать JSON на элементы и вставить в таблицу. Это делается одним запросом.
    INSERT INTO destination_table (single_value)
    SELECT single_value
    FROM JSON_TABLE( ? ,
                     '$[*]' COLUMNS ( single_value VARCHAR(255) PATH '$' )) jsontable;

    И... а, собственно, всё.

    Осталось только убедиться, что размер строкового представления данных не превышает установленный в MySQL размер входящего пакета, и, если превышает, то соответствующим образом подрихтовать сессионную переменную max_allowed_packet. Впрочем, дефолтно там 67108864 байтов, это порядка 1480 байтов на элемент - должно хватить.
    Ответ написан
    Комментировать