2010-05-04 18 views
37

Considerate questa tabella: c_constformula per la colonna calcolata sulla base di colonna della tabella diversa

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

e un altro tavolo t_anytable

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

L'obiettivo è quello di avere s_id essere una colonna calcolata, in base a questa formula :

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

Questo p genera un errore:

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

Come posso calcolare il valore per questa colonna calcolata utilizzando la colonna di un'altra tabella come input?

+0

@marc_s: ok, grazie per il vostro aiuto. – adnanturken

risposta

59

Si potrebbe creare una funzione definita dall'utente per questo:

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

e quindi utilizzare tale per definire la colonna calcolata:

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

grazie, che ha funzionato – adnanturken

+2

Il campo calcolato verrà aggiornato ogni volta che l'altra tabella viene aggiornata? –

+2

@littlestewie: ** yes! ** Ogni volta che una parte di codice accede alla colonna 'NewColumnName', la funzione verrà chiamata e il valore sarà calcolato –

22

Questo sembra essere più di un lavoro per le viste (viste indicizzate, se avete bisogno di ricerche veloci sulla colonna calcolata):

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 

Questo ha una sottile differenza da t ha una versione subquery in quanto restituisce più record invece di produrre un errore se ci sono più risultati per il join. Ma questo è facilmente risolvibile con un vincolo UNIQUE su c_const.code (sospetto che sia già un PRIMARY KEY).

È anche molto più semplice da comprendere per qualcuno della versione subquery.

si può fare con una subquery e UDF come marc_s ha dimostrato, ma è probabile che sia altamente inefficiente rispetto ad un semplice JOIN, dal momento che un UDF scalare dovrà essere calcolato riga per riga.

+1

Si noti che una vista indicizzata non sarà sempre una "ricerca rapida" - se la vista indicizzata memorizza tutte le righe della tabella di base (ad esempio non è un'aggregazione), e non è molto più magro di anche la tabella di base non sarà più veloce - in casi come quello una colonna calcolata è un'opzione migliore di una vista indicizzata IMHO. –

+1

... o se * è * più magro della tabella di base, ma devi comunque unirti alla tabella di base per soddisfare comunque la query. Il vantaggio principale delle visualizzazioni indicizzate nella mia esperienza è sempre stato la riduzione dell'archiviazione delle aggregazioni calcolate, non la rimozione del calcolo stesso. –

+2

Modificheremo il mio commento, poiché ovviamente non ho letto l'intero contesto qui e non ho capito che il requisito era quello di estrarre un valore da una tabella diversa. Una vista indicizzata sarebbe probabilmente una buona soluzione in questo caso, la mia obiezione era solo circa l'idea sbagliata comune (e la perpetuazione qui) che le viste indicizzate saranno sempre più veloci delle normali viste o colonne calcolate. –

0

Ho confrontato il piano di query di una vista con una colonna calcolata che chiama una UDF che utilizza la stessa query della vista, ed è stato davvero sorpreso di scoprire che il costo per la colonna calcolata era molto inferiore (8% vs 92%) . Sto usando SQL Server 2016. Qualcuno sa perché questo sarebbe?

Ho calcolato che la colonna calcolata interrogava essenzialmente la vista per ogni riga della tabella padre e sarebbe molto più lenta. Non sto lavorando con una tabella che ha molti dati, quindi sto solo confrontando i piani di query piuttosto che il tempo di esecuzione effettivo.

Problemi correlati