Ответы пользователя по тегу MySQL
  • Как лучше хранить заявки из форм в БД?

    @alexalexes
    А что вы так боитесь сделать в таблице кучу колонок?
    У записи заявки будет type_id - тип заявки, и в зависимости от этого будет использоваться разный набор колонок. Все колонки, которые опционально будут использоваться только в определенных типах будут с допущением null значениями.
    В основную записываем допустим имя, а в сводную то что придёт в формате ключ - значение.

    Имеет право на жизнь, но для разработчика будет сложнее сопровождать запросы. При написании запроса, если нужно вытащить или сравнить свойства заявок, будете писать на каждый такой момент подзапрос. Если захочется получать выборки с результатами в одну строку, то придется тоже использовать кучу подзапросов, возможно, сам текст запроса нужно будет формировать динамически.
    С точки зрения производительности. План запроса усложнится, нужно будет использовать индексы.
    2. Сохранять данные в json

    Если не будете использовать свойства, которые запишите в json для связывания таблиц, и формирования условий выборки, то можно использовать.
    Ответ написан
  • Логирование mysql запросов с ошибками?

    @alexalexes
    Пройдите регуляркой по запросам:
    Вариант 1. Прописать всем insert явные названия полей.
    Найдите случаи, когда перед values (через пробелы или переносы строк) нет закрывающийся скобки - пропишите явно названия полей для вставки.

    Вариант 2. Подсчитать у всех insert для каждой table правильное кол-во значений для вставки.
    По названию таблицы перед values и по запятым после values в скобках определить случаи, когда кол-во полей не то.

    PS: Переведите проект на mysqli или PDO.
    PSS: вангую, что в проекте полный треш с bind-ами параметров - тоже отдельная задача.
    Ответ написан
    Комментировать
  • Как получить строки с большими значениями?

    @alexalexes
    Как мне получить 12 строчек,

    применить в запросе клаузу limit

    по убывающей значения numberofVisits


    применить в запросе клаузу order by с опцией desc по данному полу выборки.
    Ответ написан
    Комментировать
  • Как сделать массив 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
    Второй пароль уязвим, если вы на всех системах, которые администрируете, устанавливаете пароль по похожей маске. Злоумышленнику достаточно узнать, как строится пароль к одной системе, чтобы иметь представление, как подбирать пароль к остальным. Злоумышленник будет использовать ровно ту логику, по которой вам удобнее запоминать пароль.
    Лучше не понижать энтропию ни у какой части пароля, использовать только генераторы случайных символов.
    Ответ написан