По возможности не делайте этого.
Это ответ - это антипаттерн. Если клиент знает таблицу, из которой ему нужны данные, тогдаSELECT FROM ThatTable
. Если база данных спроектирована таким образом, чтобы это требовалось, кажется, что она спроектирована неоптимально. Если слою доступа к данным необходимо знать, существует ли значение в таблице, легко составить SQL в этом коде, и помещать этот код в базу данных нецелесообразно.
Для меня это похоже на установку устройства внутри лифта, где можно ввести номер желаемого этажа. После нажатия кнопки Go он перемещает механическую руку к нужной кнопке для нужного этажа и нажимает ее. Это создает множество потенциальных проблем.
Обратите внимание: здесь нет намерения насмехаться. Мой глупый пример с лифтом был * самым лучшим устройством, которое я мог представить * для лаконичного указания на проблемы с этой техникой. Он добавляет бесполезный уровень косвенного обращения, перемещая выбор имени таблицы из пространства вызывающей стороны (с использованием надежного и хорошо понятного DSL, SQL) в гибрид с использованием непонятного / причудливого серверного кода SQL.
Такое разделение ответственности за счет перемещения логики построения запроса в динамический SQL затрудняет понимание кода. Это нарушает стандартное и надежное соглашение (как SQL-запрос выбирает, что выбрать) в названии настраиваемого кода чревато ошибкой.
Вот подробные сведения о некоторых потенциальных проблемах этого подхода:
Динамический SQL предлагает возможность SQL-инъекции, которую трудно распознать в коде внешнего интерфейса или только в коде серверной части (чтобы увидеть это, нужно изучить их вместе).
Хранимые процедуры и функции могут получать доступ к ресурсам, на которые владелец SP / функции имеет права, а вызывающий - нет. Насколько я понимаю, без особой осторожности, то по умолчанию, когда вы используете код, который производит динамический SQL и запускает его, база данных выполняет динамический SQL под правами вызывающего. Это означает, что вы либо вообще не сможете использовать привилегированные объекты, либо вам придется открыть их для всех клиентов, увеличивая поверхность потенциальной атаки на привилегированные данные. Установка SP / функции во время создания на постоянный запуск от имени конкретного пользователя (в SQL Server EXECUTE AS
) может решить эту проблему, но усложняет задачу. Это усугубляет риск SQL-инъекции, упомянутый в предыдущем пункте, делая динамический SQL очень привлекательным вектором атаки.
Когда разработчик должен понять, что делает код приложения, чтобы изменить его или исправить ошибку, ему будет очень трудно получить точный выполняемый SQL-запрос. Можно использовать профилировщик SQL, но это требует особых привилегий и может отрицательно сказаться на производительности производственных систем. Выполненный запрос может регистрироваться SP, но это увеличивает сложность с сомнительной выгодой (требующей размещения новых таблиц, очистки старых данных и т. Д.) И совершенно неочевидно. Фактически, некоторые приложения спроектированы таким образом, что разработчик не имеет учетных данных базы данных, поэтому для него становится практически невозможным фактически увидеть отправляемый запрос.
При возникновении ошибки, например, при попытке выбрать несуществующую таблицу, вы получите сообщение в строке «недопустимое имя объекта» из базы данных. Это будет происходить точно так же, независимо от того, составляете ли вы SQL в серверной части или в базе данных, но разница в том, что какой-то плохой разработчик, пытающийся устранить неполадки в системе, должен углубиться на один уровень глубже в еще одну пещеру ниже той, где находится Проблема существует, чтобы покопаться в чудо-процедуре, которая делает все, чтобы попытаться выяснить, в чем проблема. В журналах не будет отображаться «Ошибка в GetWidget», будет отображаться «Ошибка в OneProcedureToRuleThemAllRunner». Эта абстракция, как правило, ухудшает систему .
Пример на псевдо-C # переключения имен таблиц на основе параметра:
string sql = $"SELECT * FROM {EscapeSqlIdentifier(tableName)};"
results = connection.Execute(sql);
Хотя это не устраняет все возможные проблемы, которые можно вообразить, недостатки, которые я обозначил с помощью другой техники, отсутствуют в этом примере.