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

    @alexalexes
    Для извлечения, изменения, удаления конкретной записи таблицы достаточно знать значение первичного ключа. Первичный ключ обладает свойством уникальности значения. Знать позицию записи таблицы, которая записалась физически в базу не имеет смысла. При выборке может быть полезна нумерация строк, но эта нумерация всегда относительна и зависит от сортировки.
    В вашем случае запрос будет выглядеть так.
    SELECT c.id, c.region,
    (select count(*)
       from `class_item` c2
       where c.data <= c2.data-- знак будет влиять на направление нумерации
           ) as row_num
    FROM `class_item` c
    order by с.data desc

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

    @alexalexes
    в гугле решения найти не смог

    sql join

    redbeanphp

    Научитесь сначала использовать базовый набор функций работы с СУБД:
    либо mysqli, либо PDO. Не нужно использовать ORM-ки на начальном этапе обучения.
    Ответ написан
    1 комментарий
  • Как оптимизировать запрос один ко многим в MySQL?

    @alexalexes
    В вашем случае для подзапроса цен нужно использовать оконную функцию ранжирования списка, чтобы получить последнюю актуальную цену:
    SELECT * FROM `products`
    LEFT JOIN (SELECT `product`, `price`,
                      row_number() over (partition by `product` order by `id` desc) as price_rank
                          from `prices`) as prc on `products`.`id` = prc.`product`
                                                  and prc.price_rank = 1
     limit 10

    Но у вас, наверняка, версия mySQL не 8.x, а 5.x. В ней есть пользовательские переменные, которые позволяют создать патерн запроса, эмулирующий оконные функции.
    SELECT * FROM `products`
    LEFT JOIN (SELECT `product`, `price`,
                      IF(@prev_id <> `product`, @p_rank := 0, @p_rank),
                      @prev_id := `product`,
                      @p_rank := @p_rank + 1 as price_rank -- определяем partition
                from `prices`,
                      (SELECT @p_rank := 0) p_rank, -- начальное значение ранга
                      (SELECT @prev_id := -1) prev_id -- начальное значение товара (не должен быть в диапазоне сущ. id)
                    order by `product` asc,
                             `id` desc -- устанавливаем сортировку partition
                           ) as prc on `products`.`id` = prc.`product`
                                                  and prc.price_rank = 1
     limit 10

    PS: За точность воспроизведения аналога не ручаюсь, возможно, придется шаманить с order by в подзапросе.
    Ответ написан
    Комментировать
  • Как добавить ещё одну выборку SQL JOIN?

    @alexalexes
    Нужно подзапросом пройтись опять по той же структуре таблиц, и сгруппировать теги относительно категории.
    Атрибут category_tagname покажет все теги, используемые в изображениях той же категории.
    SELECT images.name,
     GROUP_CONCAT(tags.tagname SEPARATOR ", ") AS tagname,
     category.title,
     a.category_tagname
    FROM images
    INNER JOIN images_tags ON images.id = images_tags.images_id
    INNER JOIN tags ON images_tags.tags_id = tags.id
    INNER JOIN category ON images.category_id = category.category_id
    ---------------------
    join (SELECT category.category_id,
                        GROUP_CONCAT(tags.tagname SEPARATOR ", ") AS category_tagname
              FROM images
                  INNER JOIN images_tags ON images.id = images_tags.images_id
                  INNER JOIN tags ON images_tags.tags_id = tags.id
                  INNER JOIN category ON images.category_id = category.category_id
                   GROUP BY category.category_id
    ) a on a.category_id = images.category_id
    ----------------------
    WHERE images.category_id = 1
    GROUP BY images.name, category.title, a.category_tagname

    Или взять полученный массив $arrTable вытащить оттуда $arrTable[tagname], пересобрать, почистить от дубликатов и выводить уже его?

    Можно и на стороне php дообработать выборку. На практике, обычно, смотрят что либо быстрее выполняется, либо меньше по памяти.
    Ответ написан
  • Можно ли удалить последний параграф из строки mysql?

    @alexalexes
    Лучше для такой операции написать отдельный скрипт на php или python. В СУБД очень бедный функционал на функциях регулярных выражений. А в скрипте вы сможете как извлечь данные, так обрезать все лишнее, а потом обновить данные в базе. Если данные записаны в виде HTML или JSON, то удобнее их декодить или строить DOM дерево и обрезать лишнее в преобразованной структуре с последующим преобразованием в вид для сохранения в базе.
    Ответ написан
    Комментировать
  • Как сформировать запрос?

    @alexalexes
    select u.*
      from users u
    where not exists(
                select 999
                  from user_statuses us
                where us.user_id = u.id 
                    and us.status_id = 1
                 )
    Ответ написан
    2 комментария
  • Как написать запрос?

    @alexalexes
    Предположу, что в ORM нет возможностей для написания второго уровня вложенности подзапросов.
    Вероятно, ответ будет таков:
    $this->db->select('инструктор, дата, SUM(длительность)');
    $this->db->from('( SELECT DISTINCT инструктор, дата, начало, длительность
                                    FROM таблица ) AS алиас');
    $this->db->group_by(['инструктор', 'дата']);
    $query = $this->db->get();
    Ответ написан
  • Как вставить все значения у всех таблиц через JOIN?

    @alexalexes
    Так:
    SELECT *
    FROM table1 t1
    RIGHT JOIN table2 t2
    ON t1.ID = t2.ID;

    или так:
    SELECT t1.*, t2.*
    FROM table1 t1
    RIGHT JOIN table2 t2
    ON t1.ID = t2.ID;

    А зачем вам insert, когда задача на "вывести"?
    Ответ написан
  • Как наисать условие where с множесвом параметров?

    @alexalexes
    SELECT a.*, ai.name_img_file, ai.src, ai.title as img_title 
    FROM adverts as a
    join  advert_imgs as ai on a.id = ai.id_adv 
    WHERE 1 = 1
        AND exists( select 1 from adverts_fields af where a.id = af.id_advert and  af.field_name = 'storey_apartament' AND af.field_value = '58')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and af.field_name = 'condition_house' AND af.field_value = '13')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and af.field_name = 'Sleeping'AND af.field_value = '38')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and af.field_name = 'Availability' AND af.field_value = '48')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and  af.field_name = 'Bathroom' AND af.field_value = '77')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and af.field_name = 'Heating'AND af.field_value = '26')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and af.field_name = 'Furnished' AND af.field_value = '14')
        AND  exists( select 1 from adverts_fields af where a.id = af.id_advert and af.field_name = 'kitchen_area' AND af.field_value = '34')
    ORDER BY `title` DESC

    У вас свойства одного объекта "a" хранятся не в одной записи "af", а в нескольких, которые связаны внешним ключом через af.id_advert. Поэтому, чтобы посмотреть каждое свойство фильтра, нужно подзапросом exists пройтись по таблице свойств столько раз, сколько критериев в фильтре.
    А то, что вы написали - то проверит одну запись свойства и отсечет выборку на следующем AND проверки критериев, поскольку field_name и field_value в одной цепочке and проверит на разные значения, но обратить такую цепочку and в true невозможно.
    Ответ написан
    1 комментарий
  • Как удалить ¶ из sql?

    @alexalexes
    update table_name
    set value = replace(value, char(код символа ¶), concat(char(код символа \r), char(код символа\n)))

    Только не копипасьте вслепую, а разберитесь с вложенными функциями, в какой кодировке база и какие коды символов можно использовать для замены.
    Перед применением update проверьте результат select-ом:
    select value,
              replace(value, char(код символа ¶), concat(char(код символа \r), char(код символа\n))) as new_value
    from table_name
    Ответ написан
    31 комментарий
  • Как поправить mysql запрос?

    @alexalexes
    Классика жанра - подставить что-то в секцию запроса where из данных фильтра.
    Вы можете изменить запрос в зависимости от входных параметров, но есть один подводный камень.
    Вот так делать не надо:
    $sql = "select ...
    from ...
    where 1 = 1
    ".(isset($_POST['status']) ? ' and medialib.status LIKE '.$_POST['status'] // тут сшили текст запроса и значение параметра (эти два слова нужно подчеркнуть) 
     : "")

    Прямая подстановка дает возможность проводить sql инъекции.
    Правильно нужно примерно так:
    $bind_params = [];
    if(isset($_POST['status']))
      $bind_params['status'] = $_POST['status'];
    $sql = "select ...
    from ...
    where 1 = 1
    ".(isset($bind_params['status']) ? " and medialib.status LIKE :status " // тут сшили текст запроса со специальным маркером (может использоваться знак ? )
     : "")
    foreach($bind_params as $bind_param)
    {
      // тут привязываем каждое значение параметра с маркером в запросе через функцию bind_param (интерфейс и название функции зависит от библиотеки для соединения с базой данных)
    }
    Ответ написан
    Комментировать
  • Как извлечь данные записи бд по кнопке?

    @alexalexes
    В href записываете get параметр id строки.
    <a href="?id=1">см. запись</a>
    Если текущий список php используется для вывода всего списка, то скрипт нужно модифицировать так, что принимая параметр id, он начал работать по логике вывода сведений одной строки. Нет параметра - выводим все.
    if(isset($_GET['id']))
    {
      // тут код или вызов функции для работы с одной записью
    }
    else
    {
      // тут код или вызов функции для вывода всего списка
    }

    В ветке кода, где работаем с одной записью, подставляем get параметр в запрос:
    msqli_prepare("текст запроса ... where id = ?"); // ставим в нужное место запроса параметрические метки
    msqli_bind_param("i", $_GET["id"]); // передаем параметр на место меток-вопросов, в каком порядке они идут
    msqi_execute();
    // msqli_fetch функция и форматированный вывод сведений

    PS: msqli_* примерно накидал, смотрите документацию, как их вызывать. Идея и порядок кода примерно такой будет.
    Ответ написан
  • Насколько сложный пароль стоит иметь от БД?

    @alexalexes
    Второй пароль уязвим, если вы на всех системах, которые администрируете, устанавливаете пароль по похожей маске. Злоумышленнику достаточно узнать, как строится пароль к одной системе, чтобы иметь представление, как подбирать пароль к остальным. Злоумышленник будет использовать ровно ту логику, по которой вам удобнее запоминать пароль.
    Лучше не понижать энтропию ни у какой части пароля, использовать только генераторы случайных символов.
    Ответ написан
  • Как создать ссылку в базе данных?

    @alexalexes
    Общий ответ с точки зрения любой СУБД по отношению к любому способу вывода (выкатить что-то на веб-страницу) - никак. База данных ничего не знает, что такое ссылка в веб-документе. Она оперирует такими понятиями, которые позволяет хранить данные, как таблица, столбец, строка, значение атрибута. Из таблиц и связующих атрибутов таблиц - внешних и внутренних ключей строится структура данных для вашей предметной области.
    С другой стороны, у вас имеется ссылка в веб документе, которая имеет некоторые атрибуты, пригодные для хранения в базе данных: href - адрес ссылки, title - подсказка на ссылки, и возможно, какой-то текст, который обрамляет эта ссылка.
    Попробуйте значения этих атрибутов поместить в таблицу базы данных links, со столбцами:
    link_id, -- идентификатор записи в таблице ссылок
    link_href, -- ссылка
    link_title, --подсказка ссылки
    link_text -- текст ссылки
    И с помощью запроса к СУБД, а также с помощью PHP сделайте форматированный построчный вывод данных:
    // тут опущены действия связанные с формированием запроса,
    // на этом этапе вы каким-то способом получили выборку данных из таблицы links
    foreach($rows as $row)
    {
      echo '<a href="'.$row['link_href'].'" title="'.$row['link_title'].'">'.$row['link_text'].'</a><br/>';
    }

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

    @alexalexes
    Обновлять строки по условию с подзапросом. Но проблема в том, что в утверждении не говорится, чем связаны table_1 и table_2.
    update  table_1 t1
    set  t1.column_1 = A
    where exists (select 1 from table_2 t2 where t2.какой-то-связный-ключ-с-t1 = t1.какой-то-связный-ключ-с-t2 and t2.column_1 = B)
    Ответ написан
    6 комментариев
  • Как сделать вывод последнего сообщения между двумя юзерами?

    @alexalexes
    Каждый уважающий себя разработчик должен пройти путь создания своего велосипеда - мессенджера.
    От простой почтовой модели данных, где в записи сообщений есть отправитель и получатель, до модели данных, содержащий беседки (они же чаты, они же диалоги - называйте как хотите).
    Но вопрос не в этом. Давайте попробуем что-то сделать с существующей моделью.
    Время сообщения у нас нет - не проблема. Время летит вперед, и id увеличиваются в ту же сторону - по возрастанию. Значит id достаточно, чтобы различать, какое сообщение пришло раньше, а какое позже.
    Отсутствует сущность беседки - тоже не проблема. Будем считать совокупность сообщений, где отправитель, в которых может быть как сам автор, так и собеседник, или получатель также может быть как сам автор, так и собеседник одной беседкой. Такую совокупность сообщений можно выделить условием: (m2.to_id = m.to_id and m2.from_id = m.from_id or m2.to_id = m.from_id and m2.from_id = m.to_id) - что и будет выделять сущность беседки в упрощенном виде. Для выделения всех сообщений, где участвует пользователь from_id будет выражение: :from_id in (m.from_id, m.to_id). Осталось сообразить, как составить подзапрос с count, чтобы выделить самые поздние сообщения.
    Где-то такой запрос получится:
    select * from messages m
     where  :from_id in (m.from_id, m.to_id)
        and (select count(*)
                  from messages m2
                 where  (m2.to_id = m.to_id and m2.from_id = m.from_id
                       or   m2.to_id = m.from_id and m2.from_id = m.to_id) 
                   and m2.id > m.id
    ) < 1
    order by id desc

    Если понадобится выделить сообщения одной беседки, то скорее всего будет такой запрос:
    select * from messages m
     where (m.to_id = :to_id and m.from_id = :from_id
     or        m.to_id = :from_id and m.from_id = :to_id)
    order by id asc
    Ответ написан
    Комментировать
  • Как переделать запрос для получения нужного ответа?

    @alexalexes
    Как-то, так.
    SELECT
    city.id,
    city.name,
    country.name,
    salary,
    country.is_here
    FROM city
    LEFT JOIN country ON city.cid = country.id
    union all
    SELECT
    city.id,
    city.name,
    country.name,
    salary + 2000,
    1
    FROM city
    LEFT JOIN country ON city.cid = country.id
    where (country.id is null or country.is_here = 0)
    Ответ написан
    Комментировать
  • Как получить только первые строки из групп строк отсортированной таблицы?

    @alexalexes

    model_id = '269'
    AND partner_id = '0'
    AND size <= '32'

    Ай-ай-ай. Все Id-шники строками заданы, не тот тип данных выбрали для столбцов.
    Выбрать первые записи от какой-то категории можно c помощью коррелирующего группирующего подзапроса (где count считается).
    SELECT id, size, price, date
      FROM prices p
      WHERE model_id = 269
           AND partner_id = 0
           AND date_time <= '2021-10-19' 
           AND (select count(*)
               from prices p2
              where  -- сюда нужно прописать параметры строк, по которым будет определяться окно счетчика
                         -- то есть, отсчет счетчика будет в пределах одного размера, одной и той же модели, одного и того де партнера.
                          p2.size = p.size
                   and p2.partner_id = p.partner_id
                  and  p2.model_id = p.model_id
                  -- а тут параметр, чем отличается одна строка счетчика от другой
                  and p2.date > p.date 
            ) < 1 -- сколько строк отсечь от категории (n + 1) ?
    order by p.date desc
    Ответ написан
  • MySQL - выборка диалогов с тремя последними сообщениями?

    @alexalexes
    Вариант для MySQL ниже 8 версии:
    select A.*
    from 
    (
    SELECT d.id AS dialog_id, 
           d.date_latest_message,
           (select max(DM.added_date)
               from dialog_messages dm3
              where dm3.dialog_id = dm.dialog_id
           ) as datetime_latest_message,
           Dm.Id as Dm_Id,
           DM.message,
           DM.added_date
      FROM dialogs d
      join dialog_messages dm on DM.dialog_id = D.dialog_id
      WHERE (select count(*)
               from dialog_messages dm2
              where dm2.dialog_id = dm.dialog_id
              and dm2.id > dm.id -- по идент. будет эффективнее работать, чем по дате-время, к тому же первичный ключ, как правило, проиндексирован, не требуется доп. индексов
            ) < 3 -- берем только те сообщения, которые позднее опубликованы чем текущее (3 вышестоящих)
        and DATE(d.date_latest_message BETWEEN) '2020-10-01' AND '2021-10-08'
    ) A
    order by A.datetime_latest_message desc, A.Dm_Id desc

    Если MySQL версии 8 и выше, как вариант, можно взять оконную функцию row_number.
    select A.*
    from
    (
      SELECT 
             d.id AS dialog_id, 
             d.date_latest_message,
             (select max(DM.added_date)
               from dialog_messages dm3
              where dm3.dialog_id = dm.dialog_id
             ) as datetime_latest_message,
             Dm.Id as Dm_Id,
             DM.message,
             DM.added_date AS message_added_date,
             row_number() over (partition by d.id              -- окно счетчика в пределах идент. диалога
                                order by DM.Id desc    -- направление сортировки счетчика
                               ) dm_rownum -- счетчик для отсечения порций
      FROM dialogs d
      join dialog_messages dm on DM.dialog_id = D.dialog_id
      WHERE DATE(d.date_latest_message) BETWEEN '2020-10-01' AND '2021-10-08'
    ) A
    where A.dm_rownum <= 3 -- отсекаем нужное число "локальных" отсчетов
    ORDER BY A.datetime_latest_message DESC, A.Dm_Id DESC
    Ответ написан
  • Как массово изменить расширение изображений на свой фомат в MYSQL базе?

    @alexalexes
    Этим запросом крайне внимательно изучаете - удовлетворяет ли вас результат преобразования строк в result_mod_f1 из mod_f1, и result_mod_f2 из mod_f2.
    select mod_f1,  replace(mod_f1, '.png', '.webp') as result_mod_f1,
              mod_f2,  replace(mod_f2, '.png', '.webp') as result_mod_f2
    from table

    Если что-то не устраивает, переписываете replace-ы.
    Если что-то переписали, то заменяете выражения в правых частях после знака =, чтобы преобразование mod_f1 соответствовало mod_f1, а преобразование mod_f2 для mod_f2.
    /*update table
    set mod_f1 = replace(mod_f1, '.png', '.webp'),
          mod_f2 = replace(mod_f2, '.png', '.webp')*/

    Снимаете комментарий, словно собираетесь открыть защитную крышку на красной кнопке атомной бомбы и выполняете запрос.
    ПС: Желательно делать это в программном средстве, которое поддерживает режим незакрытой транзакции, чтобы можно было откатить.
    ППС: Если таблица очень большая, то лучше обновлять порциями.
    /*update table
    set mod_f1 = replace(mod_f1, '.png', '.webp'),
          mod_f2 = replace(mod_f2, '.png', '.webp')
    where mod_f1 like '%.png%'
          or mod_f2 like '%.png%'
    LIMIT 1000 */
    Ответ написан
    5 комментариев