Ответы пользователя по тегу MySQL
  • Как правильно создать триггер?

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

    Задача не решается вычисляемым полем - в его выражении не допускается недетерминированных конструкций.

    Для решения задачи потребуется:
    1) trigger, который обработает начальные условия
    2) event procedure, которая обработает изменение значения по наступлении заданного момента времени

    Однако условия на формирование значения поля:

    1) написаны так, что хрен поймёшь (даже непонятно, с какого языка это переводили)
    2) не описывают ВСЕ возможные вариации факторов (например, непонятно, какое должно быть значение, если ни одно из трёх условий не выполняется)

    Ну и, как правильно предлагает Константин Цветков, разумнее не изменять данные в таблице, а рассчитывать актуальный статус в момент, когда он требуется.
    Ответ написан
  • Зависит ли скорость записи в БД от количества в ней записей?

    @Akina
    Сетевой и системный админ, SQL-программист.
    1. Меняется/Зависит ли как-то скорость записи в таблицу БД от количества записей в таблице?

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

    2. Меняется/Зависит ли как-то скорость записи в таблицу БД от количества таблиц в БД?

    В MySQL - нет.

    3. Меняется/Зависит ли как-то скорость записи в таблицу БД от количества записей в соседних таблицах БД?

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

    Да и разница в значении параметра "количество записей" должна быть на несколько порядков, чтобы разница по скорости записи была хотя бы не меньше точности измерения.
    Ответ написан
    Комментировать
  • Как составить сложную выборку из двух таблиц?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT address, 
           office, 
           t1.fio, 
           t2.counter, 
           CASE t2.counter
               WHEN 'counter1' THEN t1.counter1
               WHEN 'counter2' THEN t1.counter2
               WHEN 'counter3' THEN t1.counter3
               END value,
           t2.num,
           t1.date       
    FROM table1 t1
    JOIN table2 t2 USING (address, office)
    Ответ написан
    2 комментария
  • Почему не работает функция CURRENT_DATE() в триггере?

    @Akina
    Сетевой и системный админ, SQL-программист.
    Почему не работает функция CURRENT_DATE() в триггере?

    Где-то что-то криво делаешь. У меня - работает.

    Хотя с моей точки зрения - у тебя кривая таблица. Нафига нужен триггер, если существует такая штука как "значение по умолчанию"?

    CREATE TABLE Sotrudnik (
      .....
      Date_Prinyatiya DATE DEFAULT (CURRENT_TIMESTAMP),
      .....
    );

    FIDDLE

    PS. Обращаю внимание - скобки в выражении значения по умолчанию обязательны!
    Ответ написан
    Комментировать
  • Почему при выборке первых трех строк, MySQL просматривает все записи таблицы?

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


    Таков принцип работы у этой СУБД. MySQL сначала выбирает все соответствующие условиям отбора записи, и только потом применяет к ним ограничение количества. Правда, обычно в запросе ещё присутствует и сортировка.

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

    Мне возвращается первые 3 строки.

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

    Вот, полюбопытствуйте: FIDDLE. Кстати, забавно, что без хинта оптимизатор выбирает вовсе даже не первичный индекс... Более того, в данном конкретном случае этому есть совершенно точное и строгое объяснение - попробуйте его найти.
    Ответ написан
    Комментировать
  • Можно ли такое реализовать с помощью MySQL?

    @Akina
    Сетевой и системный админ, SQL-программист.
    В рамках реляционной СУБД для описанной схемы есть несколько принципиально разных подходов.

    Первый - одна таблица и NULL в полях, отсутствующих у конкретного типа, её описывает Сергей Соловьев, вариант 2.
    Второй - использование EAV. Удобно, динамично, но проблемы с производительностью. Хотя из всех паттернов для реляционных СУБД он походу наиболее применим для фасетного поиска.
    Третий - использование сериализованного формата хранения. Например, хранение свойств объекта в формате JSON. Но, поскольку требуется поиск по атрибутам, в этом случае необходимо будет использовать внешний поисковый движок, возможно, даже ориентированный на фасетный поиск, или будет ужас как медленно.

    Использование MongoDB на описанном материале (буквально пара типов объектов) мне кажется не очень соответствующим решением. Хотя зависит от планируемого объёма данных.
    Ответ написан
    Комментировать
  • Как сделать запись в 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. Надеюсь, получение сгенерированного сообщения об ошибке и показ его юзеру не составит проблемы..
    Ответ написан
    Комментировать
  • Как защитить данные от повреждения при INSERT?

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

    НЕТ.

    Возможно рассогласование данных, нарушение внутренней логики системы - но никак не повреждение.

    Повреждение БД - это физическое либо логическое разрушение базы данных. Физически - например, битый сектор в теле файла таблицы. Логический (с точки зрения БД, потому как с точки зрения аппаратуры это очень даже физическое) - например, неправильное считывание номера блока данных в файле индекса вследствие наличия на диске слабого бита.

    При отсутствии аппаратных ошибок, на чистой логике повреждение БД возможно либо из-за ошибочного/злонамеренного действия, либо из-за бага/сбоя программного обеспечения. В обоих случаях - как внутри SQL-сервера, так и снаружи (ОС, третий софт, ...).
    Ответ написан
    Комментировать
  • Можно ли составить mysql запрос с выборкой не определенного множества полей?

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

    1; Ручка; Цвет; Синий; Цена; 10
    2; Нож; Материал; Цена; 200; Рукоятка; Дерево; Фото; Есть;

    Приведённый хреново форматированный текст не позволяет понять, где какое поле, и какой в нём тип данных.

    Полное ощущение, что автору требуется куча колонок (в смысле полей в структуре выходного набора). ТО есть если свойство одно, полей 4, если свойств 2, полей 6, и так далее...

    Если так, то требуемый результат называется "сводная таблица" (pivot table). Это совсем даже не реляционная структура, у которой нет и тени шанса попасть в стандарт, а потому практически ни одной СУБД штатно не поддерживается. Из популярных оно есть исключительно в SQL Server, да и там скорее исторически сложилось, чем нужно было.

    В MySQL / MariaDB ничего подходящего нет. И если кому оно реально необходимо, приходится возиться руками - хранимая процедура, динамический код... хотя на порядок разумнее оставить данные в EAV, а сводную таблицу строить на клиенте на его сервисе отчётов.

    Если же устроит выдача всех свойств, собранных в одно сериализованное поле (например, объект JSON) - то это обычная группировка и агрегация.
    Ответ написан
    Комментировать
  • Почему paragonie/easydb не пропускает слэши?

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

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

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

    @Akina
    Сетевой и системный админ, SQL-программист.
    если `prop_id` in (1,2,3,...) штук 20, может быть и больше, запрос выполняется 18 секунд, что прям совсем много.

    Критичное количество значений в таком списке - порядка 7..10, дальше действительно запрос резко замедляется.

    Workaround: создаём индексированную временную таблицу в памяти, записываем в неё набор значений, используем в запросе:

    CREATE TEMPORARY TABLE criteria (prop_id INT PRIMARY KEY) ENGINE = Memory
    SELECT prop_id FROM (VALUES ROW(1), ROW(2), ROW(3), ...) criteria (prop_id);

    и потом

    select `product_id`, count(*) as `cnt`
    from `product_prop`
    NATURAL JOIN criteria 
    group by `product_id`
    order by `cnt` desc


    Ну а ускорить ORDER BY по вычисляемому полю - вообще без шансов.
    Ответ написан
    4 комментария
  • Как отслеживать и выводить обновления базы данных?

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

    Да цельный воз и маленькая тележка.

    Обычно у каждой записи в БД имеется поле, в котором регистрируется штамп времени создания и/или последнего обновления записи. Так что всего и делов - запомнить, когда последний раз обращались к БД, и в следующий раз запросить те записи, что изменены позже. MySQL позволяет получать штамп времени с точностью до микросекунды.

    Или уж совсем по-простому. В каждой таблице держим синтетический первичный ключ-автоинкремент, и по аналогичной схеме запоминаем, каким было максимальное значение при предыдущем обращении.
    Ответ написан
    Комментировать
  • Как написать относительный путь в конфиге MySQL my.ini?

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

    Никак. Относительный путь требует наличия и, главное, детерминированности базового пути, от которого будет выполнен относительный отсчёт. А вот этой детерминированности гарантировать, увы, невозможно.

    Хотелось бы примерно такое (добавить переменную %BASEDIR%)

    Ну сделайте отдельный маленький конфигурационный файл с развёрнутыми путями, подключаемый инструкцией !include, и скриптик, который переформирует этот файл по введённой базовой директории.
    Ответ написан
  • Как составить запрос выборки баллов?

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

    Мне нужно найти запись на который у пользователя где у пользователя 1 накопится допустим 30 баллов, это запись id=5.


    WITH cte AS (
        SELECT *, SUM(point) OVER (ORDER BY point_lifetime) cum_sum
        FROM tablename
        WHERE user_id = 1 --   у пользователя 1 
        )
    SELECT *
    FROM cte
    WHERE cum_sum >= 30   --   накопится 30 баллов
    ORDER BY point_lifetime LIMIT 1;


    PS. Поскольку значения в point_lifetime неуникальны, то однозначного решения может и не быть. Во всяком случае до тех пор, пока не будет точно определён порядок записей при равенстве значений этого поля.
    Ответ написан
    Комментировать
  • Как сделать верную группировку в Union?

    @Akina
    Сетевой и системный админ, SQL-программист.
    SELECT id, MIN(type) type
    FROM t1
    WHERE type IN (1, 2)
    GROUP BY id
    Ответ написан
    4 комментария
  • Стоит ли переноносить таблицу из базы mysql?

    @Akina
    Сетевой и системный админ, SQL-программист.
    MySQL глубоко параллельно, в какой БД лежит таблица (надеюсь, innodb_file_per_table включен?). Посему вынос таблицы в отдельную БД не окажет вообще никакого влияния на работу системы. Разве что незначительно изменится процент кэширования - но скорее всего это даже детектировать не выйдет.

    Если это высоконагруженная таблица с большим потоком запросов на изменение, то имеет смысл для неё создать отдельный tablespace и вынести его на быстрый (SSD) раздел. Плюс согласен с Everything_is_bad - партиционирование (в зависимости от вида основного шаблона запросов в потоке - по юзеру или по дате) может способствовать оптимизации работы с таблицей.
    Ответ написан
    Комментировать
  • Как исправить ошибку связанную с FULL JOIN?

    @Akina
    Сетевой и системный админ, SQL-программист.
    MySQL в принципе не знает о существовании FULL JOIN. И это как раз тот редчайший случай, когда сообщение об ошибке не соответствует проблеме.

    Проблема решается эмуляцией. Есть как минимум два варианта:

    SELECT * FROM table1 LEFT JOIN table2 USING (column)
    UNOIN ALL
    SELECT * FROM table1 RIGHT JOIN table2 USING (column) WHERE table1.column IS NULL

    SELECT *
    FROM (
        SELECT DISTINCT column FROM table1
        UNION ALL
        SELECT DISTINCT column FROM table2
        ) AS table0
    LEFT JOIN table1 USING (column)
    LEFT JOIN table2 USING (column)

    Во втором варианте кажется, что DICTINCT не нужны - но с ними работать будет заметно быстрее, особенно если поле индексировано.
    Ответ написан
    2 комментария
  • MySQL автоматически увеличивает размер ячейки?

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

    В MySQL нет "ячеек" - это не Excel. Есть записи, есть поля, есть поле отдельной записи.

    Если в ячейку типа TEXT не влазят данные, MySQL автоматически увеличит её до необходимого размера или выдаст исключение?

    Если размер данных превышает размер для типа данных поля - будет выдана ошибка или предупреждение "data too long". Что именно будет выдано - зависит от того, какой запрос, и от текущих настроек сессии.

    Как сделать "резиновую" ячейку в таблице?

    Никак. Но если нужно помещать в таблицу данные, которые не лезут в LONGTEXT (а это ни много ни мало 4 гигабайта!) - то Вы явно выбрали инструмент не по задаче. Храните такое в файловой системе.
    Ответ написан
  • MySQL PDO, Почему все значения при выборке типа string?

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

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

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

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

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

    В MySQL связи "один к одному" не существует в принципе. Точнее, такая связь нереализуема на изменяемом наборе данных. Неважно, напрямую или через какой-либо ORM, включая и Sequelize.

    Возможна только реализация связи "один к (ноль либо один)".
    Ответ написан
    Комментировать