2010-05-04 2 views
37

Рассмотрим эту таблицу: c_constформула для вычисляемого столбца на основе столбца другой таблицы в

code | nvalue 
-------------- 
1  | 10000 
2  | 20000 

и другую таблицу t_anytable

rec_id | s_id | n_code 
--------------------- 
2  | x  | 1 

Цель состоит в том, чтобы иметь s_id быть вычисляемый столбец, основанный на этой формуле :

rec_id*(select nvalue from c_const where code=ncode) 

Этот продукт uces ошибка:

Subqueries are not allowed in this context. Only scalar expressions are allowed.

Как вычислить значение для этого вычисленного столбца, используя столбец другой таблицы в качестве ввода?

+0

@marc_s: Это нормально, спасибо вам за помощь. – adnanturken

ответ

59

Вы можете создать пользовательскую функцию для этого:

CREATE FUNCTION dbo.GetValue(INT @ncode, INT @recid) 
RETURNS INT 
AS 
    SELECT @recid * nvalue 
    FROM c_const 
    WHERE code = @ncode 

, а затем использовать, чтобы определить ваш вычисляемый столбец:

ALTER TABLE dbo.YourTable 
    ADD NewColumnName AS dbo.GetValue(ncodeValue, recIdValue) 
+0

спасибо, что сработало – adnanturken

+2

Будет ли обновляемое поле обновляться всякий раз, когда обновляется другая таблица? –

+2

@littlestewie: ** да! ** Каждый раз, когда какой-то фрагмент кода обращается к столбцу «NewColumnName», функция будет вызываться и значение будет вычисляться –

22

Это, кажется, больше работы для представлений (индексированные представления, если вам нужен быстрый поиск по вычисленному колонку):

CREATE VIEW AnyView 
WITH SCHEMABINDING 
AS 

SELECT a.rec_id, a.s_id, a.n_code, a.rec_id * c.nvalue AS foo 
FROM AnyTable a 
INNER JOIN C_Const c 
    ON c.code = a.n_code 

Это имеет тонкое отличие от версии подзапроса в том, что он будет возвращать несколько записей вместо создания ошибки, если для объединения есть несколько результатов. Но это легко решить с помощью ограничения UNIQUE на c_const.code (я подозреваю, что это уже PRIMARY KEY).

Это также намного легче понять, чем версия подзапроса.

Вы можете сделать это с помощью подзапроса и UDF, как marc_s показал, но это, вероятно, будет весьма неэффективна по сравнению с простой JOIN, так как скалярная UDF нужно будет вычисляться строка за строкой.

+1

Обратите внимание, что индексированный просмотр не всегда будет «быстрым поиском» - если индексированное представление хранит столько строк, сколько базовая таблица (например, это не агрегирование), и это не намного проще, чем базовая таблица тоже, это будет не так быстро - в таких случаях вычисленный столбец лучше, чем индексированный вид IMHO. –

+1

... или если он * является более узким, чем базовая таблица, но вам все равно нужно присоединиться к базовой таблице, чтобы удовлетворить запрос в любом случае. Основным преимуществом индексированных представлений в моем опыте всегда было уменьшенное хранение рассчитанных агрегатов, а не удаление самого расчета. –

+2

Я поправлю свой комментарий, так как я, очевидно, не читал весь контекст здесь и не понимал, что требовалось вытащить значение из другой таблицы. Индексированное представление, вероятно, было бы прекрасным решением в этом случае, мое возражение было связано с распространенным заблуждением (и продолжением здесь), что индексированные представления всегда будут быстрее, чем обычные представления или вычисленные столбцы. –

0

Я сравнил план запроса вида с вычисленным столбцом, вызывающим UDF, который использует тот же запрос, что и представление, и был действительно удивлен, обнаружив, что стоимость вычисляемого столбца была намного меньше (8% против 92%). , Я использую SQL Server 2016. Кто-нибудь знает, почему это было бы?

Я понял, что вычисляемый столбец по существу будет запрашивать представление для каждой строки родительской таблицы и будет намного медленнее. Я не работаю с таблицей с большим количеством данных, поэтому просто сравниваю планы запросов, а не фактическое время выполнения.