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

    @alexalexes
    товары, корзины и пользователи

    Если вы задумываетесь, а не сделать ли из какого-либо поля массив в пределах сущности в реляционной базе данных, то вы скорее всего не видите еще одну сущность, которая раскрывает содержание той сущности, в которую вы пытаетесь вставить массив.
    По-хорошему, вам нужна таблица "Позиция товара в корзине":
    ID - код позиции в корзине,
    ADD_DATE - дата и время добавления позиции (чтобы сортировать позиции, или потом очищать старые добавления в корзину),
    CART_ID - код корзины (через таблицу корзины можно выйти на USER_ID),
    GOOD_ID - код товара,
    QUANTITY - Количество единиц выбранного товара (если у вас разнородные размерности шт., кг, литры - то можно сделать веществ. тип).
    Если сама корзина не содержит собственных свойств, то таблица корзины напрямую будет содержать ее позиции, тогда вместо CART_ID используйте USER_ID.
    Ответ написан
    Комментировать
  • Что лучше: больше полей или больше Join?

    @alexalexes
    Куча count - возможно, но не join-ов.
    SELECT 
        posts.id, 
        posts.name, 
        count(case when s_vk.social_name = 'vk' then 1 end) as count_vk, 
        count(case when s_vk.social_name = 'tg' then 1 end) as count_tg,
        count(case when s_vk.social_name = 'ok' then 1 end) as count_ok,
        count(case when s_vk.social_name = 'tw' then 1 end) as count_tw
    FROM posts
       LEFT JOIN socials as s_vk on s_vk.post_id = posts.id 
    GROUP BY posts.id, posts.name

    В вашем случае для ускорения не подходит ни то, ни другое.
    Нужно вести отдельную таблицу в качестве кеша с аналогичными полями:
    posts_id,
    count_vk,
    count_tg,
    count_ok,
    count_tw
    При возникновении события клика на соц. сеть - добавлять запись в socials, а также триггером плюсовать значение по полю кеш-таблицы (и предварительно создавать запись в этой таблице по post_id, если не было ранее событий).
    Для необходимости сброса кеша нужно сделать хранимую процедуру для его перегенерации на основе данного запроса.
    PS:
    Еще бы разбить таблицу socials - на справочник соц. сетей:
    id - идент. соц сети.
    full_name - полное название соц. сети,
    abbrev - аббревиатура, например, ОК, ВК и т.д.
    tag_name - тех. название, например, ok, vk и т.д.
    ... - другие параметры соц. сети

    И таблицу для фиксации кликов:
    soc_click_events
    id - идент. события,
    post_id - идент. поста,
    social_id - идент. соц. сети,
    event_date - дата и время клика,
    ... - другие параметры клика

    PPS:
    В итоге, для фиксации событий клика и поддержания структуры базы в нормальной форме вы используйте три таблицы - posts, socials и soc_click_events.
    Для решения статистических задач вы делаете отдельные кеш-таблицы и обслуживаете их либо триггерами, либо хранимыми функциями и процедурами, получая статистические данные из первичной структуры.
    Ответ написан
    1 комментарий
  • Как запросом проверить входит ли дата из списка в диапазон дат?

    @alexalexes
    Выносите даты в отдельную таблицу:
    Название таблицы: location_event_dates
    id - идентификатор даты;
    location_event_id - идентификатор из таблицы location_event (то, что у вас в вопросе)
    event_date - одна из дат события (в формате даты, а не строки!)
    Тогда будет нормальный поиск:
    select le.id, le.locationid, le.eventid,
              led.event_date
    from location_event le
    join location_event_dates led on led.location_event_id = le.id
    where led.event_date between :begin_date and :end_date
    Ответ написан
    Комментировать
  • Как в текущую строку mysql вставить значения из последующих строк? Зациклить новости по id?

    @alexalexes
    Если вы делали механизм связывания похожих новостей (в ручном режиме указания связей), то с точки зрения реляционной теории баз данных хранение связей реализовано не корректно.
    Сложно использовать атрибут rel_id, когда в него записывают несколько значений через запятую.
    Вместо данного атрибута нужно создать отдельную таблицу для хранения связей:
    news_relation - таблица связей похожих новостей:
    атрибуты:
    id - идент. связи (первичный ключ)
    news_id_1 - идент. новости (первый конец ребра связи, внешний ключ, создайте индекс)
    news_id_2 - идент. новости (второй конец ребра связи, внешний ключ, создайте индекс)
    Для новости, с id = 1 таблица будет заполнена так:
    id, news_id_1, news_id_2
    1, 1, 3
    2, 1, 4
    3, 1, 5
    4, 1, 6
    5, 1, 7
    Если ребра связей равнозначны (неориентированный граф), то достаточно иметь запись, подтверждающую связь от news_id_1 к news_id_2. Например, у вас есть запись связи 3, 1, 5 - связь от новости 1 к новости 5, то не нужно создавать еще одну запись вида 6, 5, 1 - связь от новости 5 к новости 1. При создании и редактировании новости отслеживайте этот момент - не допускайте создание повторных связей в другом направлении (иначе придется использовать distinct в запросе ниже, он будет работать медленнее). Эту неориентированность можно реализовать текстом запроса, не записывая дополнительных данных в таблицу (обратите внимание на условие с or в запросе).
    Запрос для получения связанных новостей будет такой:
    select n.*
    from news as n
    join news_relation as nr on (:id = nr.news_id_1 and n.id = nr.news_id_2) -- выявляем связь в одну сторону
                             or (:id = nr.news_id_2 and n.id = nr.news_id_1) -- выявляем связь в другую сторону
    order by n.id desc

    :id - входной параметр текущей новости
    Ответ написан
    Комментировать
  • Как определить позицию строки в бд 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
    Ответ написан
    Комментировать