2010-05-04 24 views
37

considerar esta tabla: c_constfórmula para la columna calculada sobre la base de la columna distinta de la tabla

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

y otra mesa t_anytable

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

El objetivo es tener s_id ser una columna calculada, según la siguiente fórmula :

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

Este p produce un error:

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

¿Cómo puedo calcular el valor de esta columna calculada utilizando la columna de otra tabla como entrada?

+0

@marc_s: eso está bien, gracias por su ayuda. – adnanturken

Respuesta

59

Se puede crear una función definida por el usuario para esto:

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

y luego utilizar eso para definir su columna calculada:

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

gracias, que funcionó – adnanturken

+2

¿Se actualizará el campo calculado cada vez que se actualice la otra tabla? –

+2

@littlestewie: ** ¡sí! ** Cada vez que un fragmento de código accede a la columna 'NewColumnName', se llamará a la función y se calculará el valor –

22

Esto parece ser más de un puesto de trabajo para las vistas (vistas indizadas, si necesita búsquedas rápidas en la columna calculada):

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 

Esto tiene una sutil diferencia entre t La versión de la subconsulta en que devolvería múltiples registros en lugar de producir un error si hay múltiples resultados para la unión. Pero eso se resuelve fácilmente con una restricción UNIQUE en c_const.code (sospecho que ya es un PRIMARY KEY).

También es mucho más fácil de entender para alguien que la versión de la subconsulta.

usted puede hacerlo con una subconsulta y UDF como marc_s ha demostrado, pero es probable que sea altamente ineficiente en comparación con un simple JOIN, ya que una UDF escalar tendrá que ser calculada fila por fila.

+1

Tenga en cuenta que una vista indizada no siempre será una "búsqueda rápida", si la vista indizada almacena tantas filas como la tabla base (por ejemplo, no es una agregación), y no es mucho más delgada que la tabla base, no va a ser más rápido, en casos como que una columna calculada es una mejor opción que una vista indexada en mi humilde opinión. –

+1

... o si * es * más delgado que la tabla base, pero igual debe unirse a la tabla base para satisfacer la consulta de todos modos. La principal ventaja de las vistas indexadas en mi experiencia siempre ha sido el almacenamiento reducido de las agregaciones calculadas, no la eliminación del cálculo en sí. –

+2

Voy a modificar mi comentario, ya que obviamente no leí todo el contexto aquí y no me di cuenta de que el requisito era extraer un valor de una tabla diferente. Una vista indexada probablemente sería una buena solución en este caso, mi objeción fue solo acerca de la idea errónea común (y la perpetuación aquí) de que las vistas indexadas siempre serán más rápidas que las vistas normales o las columnas calculadas. –

0

Compliqué el plan de consulta de una vista frente a una columna calculada llamando a una UDF que utiliza la misma consulta que la vista, y me sorprendí al descubrir que el costo de la columna calculada era mucho menor (8% frente a 92%) . Estoy usando SQL Server 2016. ¿Alguien sabe por qué sería esto?

Me imaginé que la columna calculada esencialmente consultaría la vista para cada fila de la tabla padre y sería mucho más lenta. No estoy trabajando con una tabla que tenga muchos datos, así que estoy comparando los planes de consulta en lugar del tiempo de ejecución real.

Cuestiones relacionadas