Какой опыт работы с базами данных, включая JOIN, подзапросы и оконные функции
Что проверяют
Для C++-разработчика это вопрос о двух вещах: владеете ли вы SQL дальше SELECT * и умеете ли безопасно ходить в базу из кода. Следом часто просят написать запрос на доске, например три крупнейших заказа каждого клиента.
Как отвечать
По SQL покажите понимание, а не список ключевых слов:
- JOIN:
INNERоставляет только совпадения,LEFTсохраняет все строки левой таблицы сNULLсправа. Условие на правую таблицу вWHEREпослеLEFT JOINпревращает его во внутреннее соединение, такой фильтр переносят вON; - подзапросы: коррелированный вычисляется для каждой строки внешнего запроса,
EXISTSудобен для проверки наличия.NOT INпо подзапросу, где встречаетсяNULL, не вернёт ни одной строки, поэтому надёжнееNOT EXISTS; - оконные функции:
ROW_NUMBER(),RANK(),LAG(),SUM() OVER (PARTITION BY ... ORDER BY ...). В отличие отGROUP BYони не схлопывают строки. СORDER BYв окне рамка по умолчанию идёт от начала раздела до текущей строки, отсюда накопительный итог. Фильтровать по результату окна вWHEREнельзя, нужен подзапрос или CTE.
Задачу «топ-N в группе» решайте через ROW_NUMBER() OVER (PARTITION BY client_id ORDER BY amount DESC) в CTE и фильтр rn <= 3 снаружи.
Со стороны C++ назовите, чем пользовались: libpq или libpqxx для PostgreSQL, sqlite3 для встроенной базы. Ключевое: параметризованные запросы (PQexecParams, подготовленные выражения) вместо склейки строк, явные транзакции и пакетная вставка вместо запроса на каждую строку в цикле.
Где спотыкаются
Собирают SQL конкатенацией через std::string или std::format. Это прямой путь к SQL-инъекции и к ошибкам экранирования.
Делают N+1: в цикле по результатам первого запроса шлют отдельный запрос на каждую строку. На тысяче записей это тысяча сетевых обращений вместо одного JOIN.
Путают RANK() и ROW_NUMBER(). При равных значениях RANK() даёт одинаковые ранги, и запрос «топ-3» внезапно возвращает пять строк.