Основным отличием (преимуществом) является то, что вы можете вызывать функции inline в отличие от хранимых процедур.
например,
SELECT dbo.fxnFormatName(FirstName, LastName) AS FormattedName
FROM MyTable
SELECT *
FROM dbo.fxnTableReturningFunction() x
Пользовательские функции могут возвращать данные типа TABLE, а затем функцию можно вызывать в запросе, как показано выше. В случае sproc вам нужно будет выполнить его и сохранить результаты во временной таблице, чтобы затем манипулировать / запрашивать набор результатов далее.
С другой стороны, да, вы ограничены в том, что вы можете сделать в функции. например вы не можете использовать динамический SQL и до SQL 2005 вы не можете использовать недетерминированные функции, такие как GETDATE () внутри функции.
Примером, когда вы можете захотеть использовать функции, является завершение общей функциональности «форматирования», как показано в первом примере выше - вместо того, чтобы повторять логику для форматирования имени и фамилии в одно в каждом запросе, вы оберните это в функцию и вызывайте это везде. Обычно я рекомендую оставить форматирование до пользовательского интерфейса, но это простой пример того, где / почему вы можете использовать.
Кроме того, часто может быть приятнее не создавать временные таблицы для хранения результатов из sproc для дальнейшего его запроса. Если sproc изменяется и возвращает больше столбцов, вам также необходимо изменить везде, где результаты загружаются во временную таблицу, чтобы синхронизировать схему таблицы, которую он использует для хранения результатов с новой возвращенной схемой. У вас нет этой проблемы с функциональным подходом, так как нет временной таблицы для обслуживания.