Ответ
На проектах с SQL Server активно использовал следующий функционал T-SQL:
- Хранимые процедуры и функции: Для инкапсуляции бизнес-логики, повышения безопасности и производительности.
- Триггеры (DML): В основном для аудита изменений и поддержания сложной целостности данных, с осторожностью из-за влияния на производительность.
- CTE (Common Table Expressions) и рекурсивные запросы: Для работы с иерархическими данными и построения сложных, читаемых запросов.
- Оконные функции:
ROW_NUMBER(),RANK(),SUM() OVER()для аналитики без группировки исходных строк. - Динамический SQL: Для построения гибких запросов, где структура запроса зависит от параметров. Всегда с параметризацией для защиты от SQL-инъекций.
DECLARE @TableName sysname = 'Users', @Id INT = 5; DECLARE @Sql NVARCHAR(MAX); SET @Sql = N'SELECT * FROM ' + QUOTENAME(@TableName) + ' WHERE Id = @ParamId'; EXEC sp_executesql @Sql, N'@ParamId INT', @ParamId = @Id; - Явное управление транзакциями:
BEGIN TRAN,COMMIT,ROLLBACKдля атомарности операций. - Временные таблицы (#temp) и табличные переменные (@table): Для хранения промежуточных результатов.
- Оператор
MERGE: Для выполнения операций "upsert" (обновить или вставить) одной командой. - PIVOT/UNPIVOT: Для преобразования данных из строк в столбцы и обратно.
Ответ 18+ 🔞
А, ну ты спрашиваешь, на чём я собаку съел в SQL Server? Давай по полочкам разложу, как я с этой штукой работал, чтобы не просто работало, а ещё и не ебало мозги потом всем, кто это читать будет.
Хранимки и функции — это вообще святое. Всю бизнес-логику, которую можно, туда засовывал. И безопасность повышается, и производительность часто подрастает, потому что план запроса кэшируется. Просто не надо туда всякую хуйню пихать на десять тысяч строк, а то потом разбираться — пиздец.
Триггеры... О, это отдельная песня. Использовал, но с оглядкой, как на мину. В основном для аудита — кто, когда и что поменял в таблице. Или для поддержания какой-нибудь ебучей целостности, которую на уровне ограничений не опишешь. Но блядь, если навесить их дохуя на активную таблицу, они так могут производительность просадить, что мало не покажется. Поэтому осторожно, как с огнём.
CTE и рекурсивные запросы — вещь просто охуенная для иерархий. Всякие деревья категорий, оргструктуры — красота. И обычные CTE просто для читаемости больших запросов: разбил сложную хуйню на логические куски, и всё сразу понятнее становится.
Оконные функции — это просто магия. ROW_NUMBER() для пагинации или выборки уникальных строк, RANK(), SUM() OVER() для всяких скользящих итогов и аналитики прямо в выборке, без дурацких группировок, которые всю выборку ломают. Прям чувствуешь себя крутым, когда применяешь.
Динамический SQL... Вот тут надо с умом, а то такую дыру в безопасности проделаешь, что все данные утекут. Я его использовал, когда нужно было гибко собирать запрос: например, фильтры по разным полям, которые могут быть, а могут и не быть. Но главное правило — всё параметризовать, как в примере. Никаких прямых подстановок строк от пользователя, иначе SQL-инъекция обеспечена. Смотри, как правильно:
DECLARE @TableName sysname = 'Users', @Id INT = 5;
DECLARE @Sql NVARCHAR(MAX);
SET @Sql = N'SELECT * FROM ' + QUOTENAME(@TableName) + ' WHERE Id = @ParamId';
EXEC sp_executesql @Sql, N'@ParamId INT', @ParamId = @Id;
Видишь? Имя таблицы экранирую через QUOTENAME, а значение параметра передаю отдельно. Так никакая инъекция не пролезет.
Явные транзакции — это когда нужно, чтобы несколько операций прошли как одна, атомарно. Либо всё хорошо, либо откатываемся к чёртовой матери, если где-то ошибка. BEGIN TRAN, потом если всё ок — COMMIT, если пиздец — ROLLBACK. Главное, не забывать их закрывать, а то повесишь блокировку на всю систему.
Временные таблицы (#temp) и табличные переменные (@table) — для промежуточных результатов. #temp — пообъёмнее, поиндексовать можно, живёт до конца сессии. @table — помельче, для быстрых штук, обычно в памяти. Выбирал по ситуации.
MERGE — оператор-комбайн. Нужно обновить запись, если есть, а если нет — вставить? Вместо кучи IF EXISTS просто пишешь один красивый MERGE, и он сам всё делает. Удобно, ёпта.
Ну и PIVOT/UNPIVOT. Когда нужно было отчёты строить и превращать строки в столбцы (или наоборот). Выглядит немного магически, но когда разберёшься — мощный инструмент. Хотя иногда проще на стороне приложения это сделать, если логика слишком замудрённая.
Вот так, вкратце. Всё это использовал не абы как, а с пониманием, где и зачем. Чтобы работало быстро, безопасно и не приходилось потом ночами разгребать последствия кривых решений.