Ответы пользователя по тегу MySQL
  • Есть ли разница в производительности при запуске функции ил SQL запроса или в цикле php?

    @alexalexes
    1. На 3-10 позициях не имеет значения реализация.
    2. На 100...1 млн лучше экономить трафик между PHP сервером и СУБД.
    3. Если нельзя избежать транссистемой обработки задачи на 100...1 млн, то разбивайте задачу на пакеты в 100...1000 ед. Пакеты ставьте в очередь на обработку. Делайте диспетчер очереди.

    В общем, какой бы замер не сделали бы. Вы придете к одному из этих решений.
    Ответ написан
    Комментировать
  • Как найти минимальное свободное значение в диапазоне?

    @alexalexes
    WITH RECURSIVE
    -- Тестовая выборка. Если есть "живая" таблица, то эту выборку можно убрать  
     t as (select 10.000 value union
               select 10.001 union
               select 10.002 union
               select 10.003 union
               select 10.005 union
               select 10.009 -- специально добавил контр. пример
              ),
    -- Таблица-генератор последовательности чисел от min(t.value) до max(t.value) с шагом 0.001 с помощью CTE (есть ограничение по глубине рекурсии!)
    num_series AS (
      SELECT (select min(value) from t)  AS num
      UNION ALL
      SELECT num + 0.001 FROM num_series
       WHERE num < (select max(value) from t)
    )
    -- Запрос, в котором сопоставляем таблицу генератор и исходную таблицу, чтобы найти недостающие кванты
    SELECT * 
      FROM num_series
     where not exists(select t.value from t where t.value = num_series.num)
         and num_series.num >= 10.000

    PS: Нужен MySQL 8 версии и выше, postgres, или СУБД из интерпрайзного сегмента.
    Ответ написан
  • Из-за чего возникает ошибка mysql при создании таблицы?

    @alexalexes
    ... `key` INT ...
    В обратные кавычки берите названия колонок, потому что без них key будет восприниматься интерпретатором как ключевое слово.
    Ответ написан
    Комментировать
  • Как вывести подсчёт статистики из базы данных?

    @alexalexes
    Несколько Count + умение обращаться с временнЫми функциями, и у вас получится универсальный запрос со статистикой:
    Если scv.date типа date или datetime:
    select count(case when scv.date >= CURDATE() then 1 end) today_count,
           count(case when scv.date >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) and scv.date < CURDATE() then 1 end) yesterday_count,
           count(case when scv.date >= DATE_SUB(CURDATE(), INTERVAL 1 WEEK) then 1 end) week_count,
           count(case when scv.date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH) then 1 end) month_count
    from statistics_couter_visit as scv
    where scv.date >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH) -- тут ограничение по макс. окну просмотра статистики, то есть по month_count

    Если scv.date типа timestamp (или любое другое целочисленное представление):
    select count(case when scv.date >= UNIX_TIMESTAMP(CURDATE()) then 1 end) today_count,
           count(case when scv.date >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 1 DAY)) and scv.date < UNIX_TIMESTAMP(CURDATE()) then 1 end) yesterday_count,
           count(case when scv.date >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 1 WEEK)) then 1 end) week_count,
           count(case when scv.date >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) then 1 end) month_count
    from statistics_couter_visit as scv
    where scv.date >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) -- тут ограничение по макс. окну просмотра статистики, то есть по month_count

    PS: Естественно, по полю scv.date должен быть создан индекс.
    Ответ написан
    24 комментария
  • Какую кодировку выбрать для бд чтобы хранить фото?

    @alexalexes
    В базе данных, обычно, не хранят бинарные данные файлов.
    Кладете на файловый сервер файл, берете путь к этому файлу и записываете в поле таблицы.
    Если очень приспичило какой-то бинарник положить в поле таблицы, то для этого есть binary/varbinary type.
    Но злоупотреблять возможностью записывать безразмерные данные в одно поле не стоит - намучаетесь с бекапами.
    Ответ написан
    Комментировать
  • Как настроить кнопку удаления из бд?

    @alexalexes
    при желании ее удалять

    Скорее очищать данные работы программы. Вряд ли вы держите исходный код программы в таблицах БД, чтобы потом ее удалять.
    Не вполне понятно, как называются таблицы, которые вы хотите очищать (сами таблицы как объекты БД останутся, удалится только их содержимое). Но по вашему фрагменту можно что-то работающее при посте action=delete написать так:
    if(isset($_POST['action']) && $_POST['action'] == 'delete') // есть action и он равен delete
    {
        $link = mysqli_connect($host, $user, $password, $database);
        $sql = "DELETE FROM `program_day_1`"; // по одной инструкции удаления на каждую таблицу
        $res = mysqli_query($link, $sql);
        $sql = "DELETE FROM `program_day_2`";
        $res = mysqli_query($link, $sql);
        mysqli_close($link);
        header('location: program-admin.php');
    }
    Ответ написан
  • Как лучше оптимизировать запрос в базу?

    @alexalexes
    Есть два дилетантских момента построения БД:
    1. Используется строковый тип данных вместо целочисленного на всех полях, где оно используется как идентификатор, (все, что ...id).
    Вероятно, второе следствие наивного проектирования БД:
    2. На поля, которые участвуют в соединении таблиц или в условии фильтрации через where не предусмотрены индексы. По данному запросу сразу просится проверить наличие или создать индексы на:
    `products`.`category_id`, `product_filter_value`.`value_id`, `product_filter_value`.`product_id`.
    Ответ написан
  • Почему разные результаты при проверки вложения (case sensitive)?

    @alexalexes
    Еще явное приведение к типу char работает:
    select instr(convert(json_unquote(json_extract('{"name": "Gamma Electronics"}','$.name')), char), 'ga')
    Ответ написан
    Комментировать
  • В чем может быть причина автоматического созадния столбца в таблице?

    @alexalexes
    Либо в приложении ищите зачатки alter table (не факт, что chat_id добавляют как параметр из какого-нибудь конфига), либо в хранимых процедурах СУБД.
    Ответ написан
  • Как взять каждое значение массива mysqli_fetch_array и занести каждое значение в строку таблицы mySQL?

    @alexalexes
    У вас:
    while($row=mysqli_fetch_array($res))
    {  
        // #########################
        // ####  начало тела цикла  #####
        // ##########################
        $iduser=$id;
        $idkat=$row['idkat'];
         // #########################
        // ####  конец тела цикла  #####
        // ########################## 
    }  
        $res=mysqli_prepare($bd, "INSERT INTO zakaz (iduser,idkat) 
     VALUES(?,?)");
     mysqli_stmt_bind_param($res, 'ii', $iduser,$idkat); // подставляем переменные, которые присвоились на ПОСЛЕДНЕМ прогоне цикла
     $result2=mysqli_stmt_execute($res);

    Как вы ожидаете:
    while($row=mysqli_fetch_array($res))
    {  
        // #########################
        // ####  начало тела цикла  #####
        // ##########################
        $iduser=$id;
        $idkat=$row['idkat'];
        $res2=mysqli_prepare($bd, "INSERT INTO zakaz (iduser,idkat) 
     VALUES(?,?)");
     mysqli_stmt_bind_param($res2, 'ii', $iduser,$idkat); // подставляем переменные, которые присвоились на ТЕКУЩЕМ прогоне цикла
     $result2=mysqli_stmt_execute($res2);
         // #########################
        // ####  конец тела цикла  #####
        // ########################## 
    }

    PS: Есть нюанс. Обработку второго запроса нужно вести по отдельному дескриптору $res2, чтобы не поломать дескриптор $res, по которому работает while.
    Ответ написан
    Комментировать
  • Как составить SQL запрос для отчета с разным количеством строк по категории?

    @alexalexes
    При помощи SQL вы получаете исходные данные, в виде первой таблицы.
    Далее работаете только кодом PHP.
    Вторая таблица - это у вас несколько матриц, по количеству подразделений.
    Одна матрица n*m это:
    n - макс. индекс предмета 000n в пределах одного подразделения.
    m - макс. индекс видов предметов во всей исходной выборке.
    Позиция в матрице i,j:
    i - это 000i
    j - индекс вида предмета.

    Для вывода результата вам нужно получить структуру:
    $result =
    [
      1 =>  // department_id
      [
         1 /* 000i индекс */ => [1 /*индекс вида предмета*/ => '1_1_0001', 2 => '1_2_0001', 3 => '1_3_0001' /* непосредственно данные */],
         2 /* 000i индекс */ => [1 /*индекс вида предмета*/ => '1_1_0002', 2 => '1_2_0002', 3 => '1_3_0002' /* непосредственно данные */],
         3 /* 000i индекс */ => [1 /*индекс вида предмета*/ => '1_1_0003', 3 => '1_3_0003' /* непосредственно данные */],
         ...
      ],
      2 =>
      ...
    ];

    Вариант 2, динамически в PHP создать запрос:
    select t.department_id,
              t1.item as type_1,
              t2.item as type_2,
              ...
    from t
    left join (select t.department_id, t.item from t where t.type_id = 1) t1 on  t1.department_id = t.department_id
    left join (select t.department_id, t.item from t where t.type_id = 2) t2 on  t2.department_id = t.department_id
    ...
    where 1 = 1
        and (SUBSTRING_INDEX(t.item, '_', -1) + 0 = SUBSTRING_INDEX(t1.item, '_', -1) + 0 or t1.item is null)
        and (SUBSTRING_INDEX(t.item, '_', -1) + 0 = SUBSTRING_INDEX(t2.item, '_', -1) + 0 or t2.item is null)
       ...
      -- тут нужно получить равенство всех субиндексов 0000i от t.item сравнить со всеми tn.item
    order by  t.department_id, SUBSTRING_INDEX(t.item, '_', -1) + 0
    Ответ написан
    2 комментария
  • Есть ли готовые решения, для отмены действий на сайте, как бы SQL-undo?

    @alexalexes
    Проектируйте структуру базы данных так, чтобы сохранялась полная история действий над каждым классом данных, словно сохраняете лог для спец. служб.
    Api пользователя не должно использовать DELETE, только INSERT, и UPDATE только для выставления даты удаления записи, выставления метки последней актуальной записи истории. Операцию DELETE имеет право использовать только служебный метод для зачистки истории, когда устаревшие записи становятся неактуальными ни для одного актора системы.
    Ответ написан
    Комментировать
  • Как выбрать данные без дублей с сортировкой?

    @alexalexes
    select A.*
    from (SELECT id, order_id, updated,
                 row_number() over (partition by order_id order by updated DESC) rn
    FROM orders
    WHERE state = 1
    ) A
    where A.Rn = 1
    ORDER BY A.updated DESC
    LIMIT 5, 5
    Ответ написан
    Комментировать
  • Как решить проблему с php?

    @alexalexes
    Во-первых, нужно узнать, где находиться файл error_log, куда сервер пишет ошибки.
    Во-вторых, в любой непонятной ситуации добавляем в начале скрипта принудительное рапортование ошибок в лог и вывод их пользователю в начале скрипта:
    <?php
    error_reporting(E_ALL); // репорт ошибок в файл error_log
    ini_set('display_errors', 'On'); // вывод сообщения об ошибке

    В-третьих, не стесняемся пользоваться функцией var_dump/print_r для любых переменных, где есть сомнения, что они содержат нужные значения.
    var_dump($_POST);
    В-четвертых, при изучении любой библиотеки взаимодействия с СУБД первым делом лезем в справку и ищем, как вывести человекочитаемые ошибки. В PDO это метод errorInfo. Применяем его после любой операции с СУБД - коннектом, подготовкой запроса, выполнением запроса, выборкой результата:
    var_dump($pdo->errorInfo());
    В-пятых, в браузере F12, вкладка "Сеть". Смотрим, а на тот ли адрес идет запрос отправки формы. Изучаем HTTP заголовки, полезную нагрузку, ответ от сервера.

    Вот пример базовых навыков PHP разработчика. Без них можно даже не открывать видосики.
    Ответ написан
    2 комментария
  • Как в Drupal 10 массово проставить noindex для >1000 страниц?

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

    Именно так. Но лучше найти вариант вытаскивать список статей с помощью объектной модели движка самой CMS, и каммитить сохранение статьи тоже методом из объекта CMS (и не забыть еще дернуть метод очистки кэша страницы, или всего сайта, или части его контекста).
    Если у вас сайт высоконагруженный, то лучше разобраться с объектами CMS. Если нет, или не охота углубляться под капот CMS, то можно самописным скриптом поправить записи в базе, и не забыть сбросить кэш уже в панели управления CMS.
    PS: С drupal не знаком, но в любой CMS проблема будет решаться именно так.
    Ответ написан
    Комментировать
  • Как связать таблицы по одному столбцу и посчитать сумму?

    @alexalexes
    /* создание подготавливаемого запроса */
    $stmt = $mysql->prepare("select sum(c.`Price`) as price_sum
                                 from `dogovor` d
                                 join `catalog` c on c.`Id_Product` = d.`Id_Product`
                              where d.`id_client` = ?");
    /* связывание параметров с метками */
    $stmt->bind_param("i", $id_client);
    /* выполнение запроса */
    $result = $stmt->execute();
    /* выборка результатов */
    $row = $result->fetch_accos();
    if($row)
    {
      echo 'Общая стоимость всех заказов клиента: '.$row['price_sum'];
    }
    else
    {
      echo 'Запрос не дал результата!';
    }

    Ошибки в вашем решении:
    1) Небезопасная подстановка параметров в запросах. Неумение использовать в этой ситуации подготовленные запросы.
    2) Использование id_client как строкового параметра, если он состоит из цифр, то целесообразно использовать целочисленный тип в колонке таблицы.
    3) Неиспользование агрегированных функций среды sql. Зачем на php плодить лишние циклы, когда сумму можно посчитать "из коробки" средствами самой СУБД? Она под это заточена.
    4) Связывание таблиц по наименованию сущности, а не по его идентификатору. Рационально связывать по id_product вместо name_product.
    Ответ написан
    Комментировать
  • Как кучу файлов с дампами таблиц соединить в один?

    @alexalexes
    Каждая табличка - это отдельный файл SQL.

    Это не таблица, это "чертеж" таблицы.
    Соберете все файлики в несколько больших с помощью какого-нибудь файлового менеджера, то можете phpMyAdmin скармливать чертеж на постройку сразу нескольких объектов СУБД, а не только одной таблички.
    Ответ написан
    4 комментария
  • Как осуществить проверку по дате в MYSQL?

    @alexalexes
    не больше двух раз в неделю

    Формулировка требует некоторых уточнений.
    Если лимит определен на календарную неделю, и счет обращений сбрасывается в понедельник, то нужен такой запрос проверки:
    select count(*) as cnt -- кол-во записей на этой неделе
    from record as r
    where r.user_id = ? -- пользователь
      -- дата текущего понедельника (от curdate()) <= r.add_date < дата следующего понедельника (от curdate())   
      and r.add_date >= subdate(curdate(), interval weekday(curdate()) day) -- текущ. понедельник с точки зрения curdate()
      and r.add_date < subdate(curdate(), interval weekday(curdate()) - 7 day) -- следующий понедельник с точки зрения curdate()

    Если лимит определен просто на интервал 7 дней, то такой запрос:
    select count(*) as cnt -- кол-во записей за последние 7 дней
    from record as r
    where r.user_id = ? -- пользователь
      and r.add_date > subdate(curdate(), interval 7 day)
    Ответ написан
    5 комментариев
  • Как подсчитать и вывести количество совпадений значения в строке при запросе в MySQL?

    @alexalexes
    Если у вас MySQL 8, то дубликаты телефонов можно найти тривиально:
    select A.*
      from (SELECT `date`, `name`, phone, count() over (partition by phone) phone_count
            FROM `myusers`
    ) A
    where A.phone_count > 1
    ORDER BY date ASC

    Если MySQL 5, то придется немного по сложнее:
    select `date`, `name`, phone, p.phone_count
    from `myusers` as mu
    join (SELECT phone, count(*) phone_count
             FROM `myusers`
             group by phone) p on p.phone = mu.phone
    where p.phone_count > 1
    ORDER BY mu.date ASC
    Ответ написан
    4 комментария
  • Как сгруппировать по убыванию?

    @alexalexes
    Если у вас MySQL 8+ версия, то список чатов получается тривиально - используя оконную функцию:
    SELECT A.*
    from (
    SELECT class_messages.id as class_messages_id,
          `class_messages_chat`.`to_user_id`,
           `class_messages_chat`.`from_user_id`,
           `class_users`.`id`,
           `class_users`.`user_status`,
           `class_users`.`online`,
           `class_messages_chat`.`chat_id`,
           `class_messages_chat`.`ad_id`,
           `class_ads`.user_id,
           `class_ads`.title,
           row_number() over (partition by `class_messages_chat`.`chat_id` order by class_messages.id desc) rn -- этой функцией нумеруем в пределах чата сообщения
        FROM `class_messages_chat`
        inner join `class_ads` on `class_messages_chat`.ad_id = `class_ads`.id
        INNER JOIN `class_users` ON `class_users`.`id`=`class_ads`.`user_id`
        inner join `class_messages` on `class_messages_chat`.`chat_id` = `class_messages`.`chat_id`
    WHERE (   `class_messages_chat`.`to_user_id` = 133337
           or `class_messages_chat`.`from_user_id` = 133337)
    and class_messages_chat.chat_id is not null
    ) A
    where A.Rn = 1 -- оставляем, все что с первым номером счетчика
    order by A.class_messages_id desc

    В mySQL 5.7
    SELECT A.*
    from (
    SELECT
          `class_messages_chat`.`to_user_id`,
           `class_messages_chat`.`from_user_id`,
           `class_users`.`id`,
           `class_users`.`user_status`,
           `class_users`.`online`,
           `class_messages_chat`.`chat_id`,
           `class_messages_chat`.`ad_id`,
           `class_ads`.user_id,
           `class_ads`.title,
      IF(@prev <>  `class_messages_chat`.`chat_id`, @rn:=1,@rn), @prev:= `class_messages_chat`.`chat_id`, @rn:=@rn+1 AS rn -- этой функцией нумеруем в пределах чата сообщения
        FROM `class_messages_chat`
        inner join `class_ads` on `class_messages_chat`.ad_id = `class_ads`.id
        INNER JOIN `class_users` ON `class_users`.`id`=`class_ads`.`user_id`
        inner join `class_messages` on `class_messages_chat`.`chat_id` = `class_messages`.`chat_id`,
         (SELECT @rn:=1)rn,
         (SELECT @prev:=-1)prev
    WHERE (   `class_messages_chat`.`to_user_id` = 133337
           or `class_messages_chat`.`from_user_id` = 133337)
    and class_messages_chat.chat_id is not null
    order by class_messages.id desc
    ) A
    where A.Rn = 1 -- оставляем, все что с первым номером счетчика

    Второй вариант для 5.7, если некорректно будет работать сортировка.
    select B.*
    from (SELECT A.*,
               IF(@prev <> A.chat_id, @rn:=1,@rn), @prev:= A.chat_id, @rn:=@rn+1 AS rn -- этой функцией нумеруем в пределах чата сообщения
    from (
    SELECT
          `class_messages_chat`.`to_user_id`,
           `class_messages_chat`.`from_user_id`,
           `class_users`.`id`,
           `class_users`.`user_status`,
           `class_users`.`online`,
           `class_messages_chat`.`chat_id`,
           `class_messages_chat`.`ad_id`,
           `class_ads`.user_id,
           `class_ads`.title
        FROM `class_messages_chat`
        inner join `class_ads` on `class_messages_chat`.ad_id = `class_ads`.id
        INNER JOIN `class_users` ON `class_users`.`id`=`class_ads`.`user_id`
        inner join `class_messages` on `class_messages_chat`.`chat_id` = `class_messages`.`chat_id`
    WHERE (   `class_messages_chat`.`to_user_id` = 133337
           or `class_messages_chat`.`from_user_id` = 133337)
    and class_messages_chat.chat_id is not null
    order by class_messages.id desc
    ) A,
    (SELECT @rn:=1)rn,
         (SELECT @prev:=-1)prev
    ) B
    where B.Rn = 1 -- оставляем, все что с первым номером счетчика
    Ответ написан