Без динамического SQL (или динамического построения запроса на уровне приложения или API)? Я не думаю, что это будет очень красиво. Команда UPDATE не имеет каких-либо внутренних знаний о том, какие разрешения может иметь пользователь для соответствующих столбцов. Он собирается отправить запрос в движок и надеяться на лучшее. Если у пользователя нет прав доступа ко всем столбцам, он вернет ошибку, а не попытается ее обойти, изменив предполагаемый оператор. Я думаю, что на самом деле было бы очень плохо продолжать обновление, хотя не все запланированные столбцы были обновлены.
Тем не менее, я полагаю, вы могли бы сделать что-то подобное, но это совсем не будет красиво - на самом деле будет намного проще, если вы не полагаетесь на принципалов базы данных:
DECLARE
@dpid INT = DATABASE_PRINCIPAL_ID(),
@obj INT = OBJECT_ID('dbo.foo'),
@col SYSNAME = N'bar';
UPDATE dbo.foo SET bar = CASE
WHEN EXISTS -- check they've been granted UPDATE at column or table level:
(
SELECT 1
FROM sys.database_permissions AS dp
INNER JOIN sys.objects AS o
ON dp.major_id = o.[object_id]
LEFT OUTER JOIN sys.columns AS c
ON dp.minor_id = COALESCE(c.column_id, 0)
WHERE dp.grantee_principal_id = @dpid
AND o.[object_id] = @obj
AND (c.name = @col OR c.column_id IS NULL)
AND dp.[permission_name] = 'UPDATE'
AND dp.[state] = 'G' -- GRANT
)
AND NOT EXISTS -- since DENY trumps GRANT, make sure that doesn't also exist:
(
SELECT 1
FROM sys.database_permissions AS dp
INNER JOIN sys.objects AS o
ON dp.major_id = o.[object_id]
LEFT OUTER JOIN sys.columns AS c
ON dp.minor_id = COALESCE(c.column_id, 0)
WHERE dp.grantee_principal_id = @dpid
AND o.[object_id] = @obj
AND (c.name = @col OR c.column_id IS NULL)
AND dp.[permission_name] = 'UPDATE'
AND dp.[state] = 'D' -- DENY
)
THEN @bar ELSE bar END
-- WHERE...
;
Это не совсем то, что вы просите; технически он обновляет столбец, но устанавливает его себе (таким образом, он все равно будет указан, например, как обновленный столбец в триггере), но предотвращает применение ввода к таблице. Я также не проверял разрешения, предоставленные способами, отличными от явного ОБНОВЛЕНИЯ ГРАНТА или ОБНОВЛЕНИЯ ДЕНЬГИ для указанного пользователя или роли - например, GRANT ALL или разрешения, унаследованные членством в группе AD, могут усложнить это. Конечно, управлять этим будет не очень весело, если у вас есть несколько столбцов для проверки.
Возможно, вы захотите добавить другие условия в предложение WHEN, например, чтобы избежать проверки для dbo (who) или пользователей, которым вы хотите явно обойти проверку, вы можете иметь:
CASE
WHEN DATABASE_PRINCIPAL_ID() = 1 THEN @bar
WHEN SUSER_SNAME = 'some_user' THEN @bar
WHEN (...stuff from above...)
ELSE bar
END
-- WHERE...
;