Ответы пользователя по тегу MySQL
  • Как вывести строку по id php ?id=1?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Вопрос хороший, но здесь мы упираемся в главную беду пхп - ВСЕ учебники в интернете, и особенно видео - показывают как писать адов говнокод из прошлого века.

    1. Получение значения из адресной строки

    Чтобы получить значение переменной, которую передали в строке запроса (это то что после знака вопроса), надо обратиться к переменной $_GET

    То есть в данном случае можно написать $id = $_GET['id']. Имя получаемой переменной ($id) может быть любым и не обязательно совпадать с переданным значением. А вот в индекс массива $_GET разумеется надо писать именно то имя, которое в адресной строке. То есть если site.com/?id=1 то в $_GET['id'] будет значение 1.

    2. Валидация данных

    Далее очень желательно проверить, что мы в переменной получили то что хотели, а так же что мы вообще хоть что-то получили.

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

    Затем, поскольку id может быть только целым числом больше нуля, то лучше проверить и это тоже и тоже выдать ошибку.

    3. Соединение с БД.

    в "config.php" должно быть написано не то что там сейчас а вот это (со своими параметрами подключения разумеется)
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    $link = mysqli_connect($host, $user, $pass, $db_name);
    $link->set_charset("utf8mb4");


    4. SQL

    Запрос, который нам нужен, выглядит так:
    SELECT * FROM `product` WHERE id=1

    5. Выполнение запроса в РНР

    Но разумеется вместо 1 надо подставить значение переменной.
    Это самое сложное. Но надо один раз выучить и потом везде применять

    Важно, чтобы данные в БД всегда попадали отдельно от самого запроса. Это непреложное правило, которое надо соблюдать всегда.
    Для этого надо
    1. Заменить все переменные в запросе на специальные маркеры, которые называются плейсхолдеры или параметры, а по сути - просто знаки вопроса
    2. Подготовить запрос к исполнению с помощью функции prepare(). Эта функция принимает строку запроса и возвращает экземпляр специального класса stmt, с которым в дальнейшем и производятся все манипуляции
    3. Привязать переменные к запросу.
    4. Выполнить подготовленный ранее запрос с помощью с помощью execute()
    5. Получить результат запроса через get_result()
    6. и дальше конкретную строку из БД с помощью уже знакомой fetch_assoc


    В коде это будет так
    $sql = "SELECT * FROM `product` WHERE id=?";
    $stmt = $link->prepare($sql);
    $stmt->bind_param("s", $id);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();


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

    6. Вывод данных.

    Важно понимать, что в момент вывода данных никакой работы с БД уже быть не должно!
    Должны быть только переменные РНР с уже полученными данными.
    Ответ написан
    1 комментарий
  • Как взламывают бд крупных компаний?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Взламывают точно так же как и мелкие.
    В статье описана обычная SQL инъекция, когда данные подставляются прямо в SQL запрос.

    Я просто сомневаюсь, что valve может нанять таких людей в backend

    Не надо сомневаться.
    Нету никаких "особенных способов взлома".
    А есть такое явление как "эффективные менеджеры". У которых размер премии зависит от того, сколько денег они сэкономили акционерам.

    Если бы там были подготовленные выражения, то и взлома бы не было.
    Но вместо подготовленных выражений в больших компаниях есть эффективные менеджеры. Которые экономят на нормальных программистах, и заказывают разработку в Индии, в штате Бангалор. Где живет какой-нибудь Хамишь Кумар, который родился в касте вычерпывателей говна из сортиров. И вот у него только один шанс не черпать говно всю жизнь - всеми правдами и неправдами научиться программировать, путь даже за еду. Сравниваем с силиконовым программером с запросами $250k в месяц. Экономия налицо!

    На всякий случай напомню, для стопроцентной защиты от инъекций необходимо всегда следовать двум простым правилам:

    1. данные подставляем в запрос только через плейсхолдеры
    2. идентификаторы и ключевые слова подставляем только из белого списка, прописанного в нашем коде.


    Ключевое слово здесь - "всегда". Как только начинаются рассуждения вида "ну эти данные и так безопасные, их защищать не надо", то в этот момент мы добавляем инъекцию к себе на сайт. Следует понимать, что защищаем мы не данные, а запрос. Данные нас вообще не интересуют - какие они, откуда пришли, являются "безопасными" или нет. Важно не то откуда они пришли, а то, куда они идут. В SQL запрос? Используем подготовленные выражения, точка.
    Ответ написан
    2 комментария
  • Как правильно хранить несколько значений внутри поля в MySQL?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    "несколько значений внутри поля" в терминах реляционных баз данных - это отдельная таблица, которая ссылается на строку в исходной таблице. по ид публикации можно будет получить из неё все фотографии
    Ответ написан
    6 комментариев
  • Как ускорить mysql?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Любые вопросы про "ускорение mysql" необходимо сопровождать не голословными заявлениями "Слющай, использует индексы, мамом клянус!", а ВЫВОДОМ EXPLAIN
    Без которого вопрос в принципе не имеет смысла, и должен удаляться.

    Плюс неплохо сразу выкатить результат SHOW ENGINE INNODB STATUS
    Ответ написан
    Комментировать
  • Какой интерфейс можно использовать удаленно для управления субд mysql?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    пхпбыдлоадмин страшен не "дырами", а интерфейсом.
    Это самый кривой клиент для работы с БД, какой я когда-либо видел

    Самый удобный - встроенный в пхпшторм.
    остальные по вкусу

    если прямого соединения с бд нет, настраивать через ssh туннель, во всех клиентах есть такая опция
    Ответ написан
    Комментировать
  • Ошибка в запросе?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    1. Надо включать отображение ошибок РНР.
    Тогда ПХП тебе бы прямым текстом сказал, что в нет никакой переменной "priceMan". Хотя если смотреть на полный запрос, то скорее отсутствует parpage
    2. Надо использовать для запросов подготовленные выражения
    Тогда даже при отсутствии переменной не будет ошибки запроса. Не говоря уже про взлом сайта

    Даже такая параша, как тухлая фасоль, и то умеет в замещение переменных в запросе

    $params = [
    'min' => $_GET['priceMin'],
    'max' => $_GET['priceMax'],
    'cnt' => $cnt,
    'start' =>$start, 
    'perpage' =>$perpage,
    ]
    $idparam = '';
    foreach ($ids as $i => $item)
    {
        $key = ":id$i";
        $idparam .= $idstr? "," : "" . $key;
        $params[$key] = $item; 
    }
    $filterparam = '';
    foreach ($ids as $i => $item)
    {
        $key = ":f$i";
        $filterparam .= $filterparam? "," : "" . $key;
        $params[$key] = $item; 
    }
    
    
    
    $sql = "SELECT id, articul, category_id, brand_id, title, alias, content, price, old_price, status, keywords, description, img, hit, novinki  
    FROM product 
    WHERE status = '1' AND category_id IN ($idparam) 
    AND price > :min AND price < :max
    AND id IN (SELECT product_id FROM attribute_product WHERE attr_id IN ($filterparam) 
    GROUP BY product_id 
    HAVING COUNT(product_id) = :cnt)
    LIMIT :start, :perpage"
    
    $rows = \R::getAll($sql, $params);
    Ответ написан
  • Как правильно организовать базу даных?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    вопрос довольно сумбурный
    структура БД не определяется структурой "меню".
    непонятна связь между "контентом" и "каталогом"
    непонятно, зачем таблица с меню

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

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

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Почему больше всего подписчиков всегда слетается на самые дурацкие вопросы?
    Которым место в мусорке, а не на главной Хабра.
    Ну ведь как в прошлый раз же, весь текст - какие-то бессвязные эротические фантазии, не имеющие ничего общего ни с реальностью, ни друг с другом, ни - главное - с собственно вопросом, который был задан.

    Так вот: я смотрю, что получил 1500 строк из базы за 0.0316 секунд. Это нормально?

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

    База растёт и строк к выводу станет больше.

    С КАКОГО, я стесняюсь спросить, перепугу, с ростом базы строк к выводу станет больше?
    На тостере с каждым днем прибавляется сотня дебильных вопросов.
    Ты уверен что количество запрашиваемых из базы строк тоже растёт? А если подумать? А если прям вот хорошенько подумать?

    Этот ход мысли напоминает старый еврейский анекдот, который рассказывал Джоэл Спольский в далёком 2001 году:
    Маляр Шлёма подрядился красить пунктирные осевые линии на дорогах. В первый день он получил банку краски, поставил её на дорогу, и к концу дня покрасил 300 метров осевой линии. «Отлично! — сказал прораб. — Быстро работаешь!» и заплатил ему.
    На следующий день Шлёма покрасил 150 метров. «Мда, это, конечно, не так здорово, как вчера, но приемлемо», — сказал прораб и снова заплатил ему.
    Ещё через день Шлёма покрасил всего 30 метров. «Всего лишь 30! — заорал прораб. — Это никуда не годится! В первый день было в десять раз больше! В чём дело?»

    «Ничего не могу поделать, — говорит Шлемиэль. — Каждый день я ухожу всё дальше и дальше от банки!»


    Тебе не кажется что эта логика напоминает твоё "но с каждым днём в БД появляется всё больше и больше записей!"?

    На что ориентироваться? На показатели загрузки процессора или время выполнения запроса или расход памяти?

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

    И вопрос в догонку: если одним запросом я получаю 1500 строк и если в запросе я установлю select нужных мне столбиков - это усложняет запрос или нет? Ведь в первом случае я получаю информацию как есть, а во втором случае процессору надо время чтобы перебрать нужные столбики?!

    Судя по количеству восклицательных знаков - это самый важный вопрос во всём этом и так целиком гениальном тексте. Процессор опасносте!!! Срочно надо спасать!

    Запрос выполняется три сотых секунды, дом рисуется 10, но вопрос почему-то "как узнать , не тормозит ли база?"
    Ну ей-богу, снова как в анекдоте - "Где логика??! Где разум??".

    Сейчас я кеширую результаты php на 60 минут,

    Вот это я понимаю. Сразу заходим с козырей.
    странно что на 60 минут, а не на 24 часа. или вообще сделать сайт статикой. тогда вообще всё летать будет. Или вообще перенести всю БД на клиента. Чего не сделаешь ради борьбы за миллисекунды.

    Как понять есть ли нагрузка на БД?/

    Посмотреть, есть ли нагрузка.
    Тормозит ли сайт, есть ли загрузка по процу и памяти, есть ли отказы в обслуживании, ошибки в логах.
    Если ничего этого нет, то сидеть на попе ровно и ничего не трогать!

    А вместо всяких "оптимизаций" типа кэширования на 60 минут запроса, который выполняется пару сотых секунды, или не на покупки бессмысленного диска, а на букварь про работе с БД. И прочитать там про нормализацию, индексы, базовые команды SQL, пагинацию, в конце концов.

    И тогда и твоя микроскопическая БД в 10 тыщ записей, и нормальная база с миллионами строк, будут работать одинаково быстро и эффективно.
    Ответ написан
    9 комментариев
  • Какой collation выбрать для Mysql базы данных?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Никакой не выбирать. Выбрать надо charset. utf8mb4.
    А collation подставится сам, по умолчанию.
    Ответ написан
    3 комментария
  • Как сделать json в mysql пустым, чтобы rowCount возвращал 0?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    $query = $db->prepare("SELECT * FROM `followers` WHERE `author_id`=? AND follower_id=?");
    $query->execute([$authorsID,$followersID]);


    и о чудо! rowCount() внезапно работает!!!!

    if ($query->rowCount() > 0) {
          echo 'subscribed';
    } else {
          echo 'unsubscribed';
    }
    Ответ написан
    Комментировать
  • Как вернуть и кол строк выборки и данные из этой же выборки с заданным лимитом?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    В африке есть такая птица - страус.
    В случае опасности она втыкает голову в песок.
    Поскольку при этом она перестает видеть хищника, и думает что хищник тоже её теряет из виду.

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

    Для тех, кому ехать, а не шашечки. единственный реальный и осмысленный вариант
    SELECT COUNT(*) FROM ## задача с блекджеком и JOIN'ами
    SELECT * FROM /* задача с блекджеком и JOIN'ами */ LIMIT 150


    а "ресурсоёмкие" запросы надо оптимизировать. чтобы они перестали быть ресурсоёмкими.
    Ответ написан
  • В mysql для быстрого поиска по дате лучше использовать timestamp как int или как date (datetime)?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Для скорости абсолютно без разницы, а для хранения даты и времени надо использовать предназначенные для этого типы данных
    Ответ написан
    7 комментариев
  • Выгрузка картинки из базы mysql?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Этот вопрос надо отлить в граните и поместить в палате мер и весов, в виде большой квадратной доски.
    И всех любителей хранить картинки в базе "это же так удобно!!!" заставлять биться об нее головой, пока вся эта дурь из головы не вылетит.
    Ответ написан
    9 комментариев
  • Почему php не может подключиться к БД?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Это очень забавная ошибка, в которой смешалась куча старого карго культ кода, который и сам по себе использовать не стоит, и вдобавок он здесь написан неправильно.

    Если разобраться, то код or die("Ошибка1 " . mysqli_error($link)); очень смешной (это не к тебе претензия, никто не ожидает от тебя понимания таких тонкостей, которые не то что новички, а половина здешних "кураторов" не понимают).
    Что тут происходит?
    слово or die (которое на самом деле вообще нельзя никогда писать) пишут тогда, когда ожидают что в переменной $link будет знаение false. Но если в $link будет false, то тогда её бессмысленно подставлять в mysqli_error. именно поэтому для получения ошибки соединения в мускули есть отдельная специальная функция.

    Но как я говорил выше, её применять не следует, как и or die.

    Что тебе нужно - это настроить пхп так чтобы он отображал ошибки, а mydsqli - чтобы оно бросало исключения.
    То есть код должен выглядеть вот так

    <?php
    // видеть все ошибки!
    ini_set('display_errors',1);
    error_reporting(E_ALL);
     // подключаем настройки
    require_once 'connect.php';
    
    // включаем режим информирования об ошибках
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    // подключаемся к серверу
    $link = mysqli_connect($host, $user, $password, $database);
       
    // выполняем операции с базой данных
    $query ="SELECT * FROM foo";
    $result = mysqli_query($link, $query);
    echo "Выполнение запроса прошло успешно";
    // в большинстве случаев закрывать подключение не надо


    ЗЫ. На боевом сервере ошибки на экран выводить конечно не стоит, а их надо писать в лог (собственно, именно поэтому все эти die - это ужас). И на боевом сервере display_errors надо отключать, а log_errors наоборот - подключать.
    Если совсем не можешь найти, где у сервера висит лог ошибок, можешь задать свой собственный, с помощью функции ini_set('error_log','/путь/к/файлу');. Но только размещать его надо разумеется в папке недоступной пользователям сайта
    Ответ написан
    2 комментария
  • Почему не записывает значение в БД?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    ё моё, ну нормальный почти у тебя код был
    оставь все как было только запрос поменяй
    $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
    $opt = [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ];
    $pdo = new PDO($dsn, $user, $pass, $opt);
    
    $query = 'INSERT INTO `configs` (`CName`, `Username`, `Time`) VALUES (?,?,?)';
    $stmt->$pdo->prepare($query);
    $stmt->execute([$CName,$Username, $Time]);
    $id = $pdo->lastInsertId();
    Ответ написан
  • Как правильно создать индексы mysql?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Я так понимаю что главная задача - убрать перемножение таблиц.
    По идее должно быть достаточно добавить индекс на product_id.
    тогда во второй строке в rows должна появиться единичка

    Если это реальные цифры количества строк в таблицах, то больше вообще никакие индексы не нужны.
    Ответ написан
  • Почему не получается записать в базу данных?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Сразу учимся правильно работать с БД.
    Сначала учимся правильно соединяться.
    Весь этот детский лепет "не могу соединиться с БД" выкидываем и пишем нормальный код, который без всяких проверок сам сообщит об ошибках.
    В случае mysqli это
    mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
    $link = mysqli_connect($host, $user, $pass, $db_name);
    $link->set_charset("utf8mb4");
    Здесь первая строчка отвечает как раз за информирование об ошибках

    Для PDO будет так
    $host = '127.0.0.1';
    $db   = 'test';
    $user = 'root';
    $pass = '';
    $port = "3306";
    $charset = 'utf8mb4';
    $options = [
        \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
        \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
        \PDO::ATTR_EMULATE_PREPARES   => false,
    ];
    $dsn = "mysql:host=$host;dbname=$db;charset=$charset;port=$port";
    $pdo = new \PDO($dsn, $user, $pass, $options);

    Здесь за информирование об ошибках отвечает параметр PDO::ERRMODE_EXCEPTION, а остальные просто для удобства/корректности.

    После этого переписываем запрос. Причем так, чтобы данные в БД всегда попадали отдельно от самого запроса. Это непреложное правило, которое надо соблюдать всегда.
    Для этого надо
    • Заменить все переменные в запросе на специальные маркеры, которые называются плейсхолдеры или параметры, а по сути - просто знаки вопроса
    • Подготовить запрос к исполнению с помощью функции prepare(). Эта функция принимает строку запроса и возвращает экземпляр специального класса stmt, с которым в дальнейшем и производятся все манипуляции
    • Привязать переменные к запросу.
    • Выполнить подготовленный ранее запрос с помощью с помощью execute()

    В mysqli это будет так
    $sql = "INSERT INTO `events` (`title`, `discription`, `date`, `img`) VALUES (?,?,?,?)";
    $stmt = $link->prepare($sql);
    $stmt->bind_param("sssss", $title, $discription, $date, $path);
    $stmt->execute();

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

    И тогда никаких ошибок запроса уже никогда не будет. Не говоря уже о том что при любых других вариантах твой сайт поломает любой пятиклассник

    Но по-хорошему для работы с БД в РНР лучше использовать PDO, Тем более что там колупаться с bind_param не нужно, а можно сразу отправить все данные в execute
    $sql = "INSERT INTO `events` (`title`, `discription`, `date`, `img`) VALUES (?,?,?,?)";
    $stmt = $link->prepare($sql);
    $stmt->execute([$title, $discription, $date, $path]);
    Ответ написан
    2 комментария
  • Как добавить только не пустые параметры в бд?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Начнем с того, что "if isset" не проверяет, "пустая ли переменная". Она только проверяет, было ли переменной присвоено какое-то значение.
    Что, в свою очередь, очень забавно смотрится после того как буквально строчкой выше каждой переменной уже было присвоено значение.
    Ну то есть это условие сработает, если в запросе вообще не было такого поля, но во-первых, мне кажется не это имелось в виду, а во-вторых, если поля не было, то уже при присвоении будет ошибка, и после этого делать isset уже как-то глупо.

    И, как правильно заметил Кирилл Николаевич, наверное имеется в виду размер строки с данными. Если он нулевой, то мы можем считать поле пустым. Плюс, как он опять же, правильно заметил, возможно имеет смысл отрезать концевые пробелы, правда непонятно, каким местом для этого регулярки.

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

    В общем случае нам надо список полей, которые мы можем добавить в БД. Чтобы не колупаться с отдельными переменными. А дальше все просто - цикл, который проверяет на пустоту и формирует сам запрос плюс массив с данными для него.
    $fields = ['phrase','secret','custom1', ...];
    $conditions = [];
    $params = [];
    foreach($fields as $key) {
        if (strlen($val = trim(filter_input(INPUT_POST,$key)))) {
            $conditions[] = "`$key` =?";
            $params[] = $val;
        }
    }
    if ($params) {
        $sql = "INSERT INTO table SET ".implode(",",$conditions);
        $pdo->prepare($sql)->execute($params);
    }
    Ответ написан
    Комментировать
  • Как выбрать две последнии записи для каждой группы?

    FanatPHP
    @FanatPHP
    Помогаю и новичкам, и старичкам
    Мне кажется, можно и без оконных функций
    каким-нибудь select max(id) group by group-id получить айдишники последних 20 разговоров, соответственно этим подзапросом выбрать все последние реплики, ну и еще один подзапрос чтобы выбрать реплику второго адресата
    Ответ написан