Un modello abbastanza comune nell'applicazione di database con cui lavoro è la necessità di creare una procedura memorizzata per un report o un'utilità con una "modalità di anteprima". Quando una tale procedura esegue gli aggiornamenti, questo parametro indica che i risultati dell'azione devono essere restituiti, ma la procedura non deve effettivamente eseguire gli aggiornamenti al database.
Un modo per ottenere ciò è semplicemente scrivere if
un'istruzione per il parametro e avere due blocchi di codice completi; uno dei quali aggiorna e restituisce i dati e l'altro restituisce semplicemente i dati. Ma questo non è auspicabile a causa della duplicazione del codice e di un livello relativamente basso di fiducia nel fatto che i dati di anteprima siano in realtà un riflesso accurato di ciò che accadrebbe con un aggiornamento.
L'esempio seguente tenta di sfruttare i punti di salvataggio e le variabili delle transazioni (che non sono interessati dalle transazioni, a differenza delle tabelle temporanee che sono) per utilizzare solo un singolo blocco di codice per la modalità di anteprima come modalità di aggiornamento live.
Nota: i rollback delle transazioni non sono un'opzione poiché questa chiamata di procedura può essere nidificata in una transazione. Questo è testato su SQL Server 2012.
CREATE TABLE dbo.user_table (a int);
GO
CREATE PROCEDURE [dbo].[PREVIEW_EXAMPLE] (
@preview char(1) = 'Y'
) AS
CREATE TABLE #dataset_to_return (a int);
BEGIN TRANSACTION; -- preview mode required infrastructure
DECLARE @output_to_return TABLE (a int);
SAVE TRANSACTION savepoint;
-- do stuff here
INSERT INTO dbo.user_table (a)
OUTPUT inserted.a INTO @output_to_return (a)
VALUES (42);
-- catch preview mode
IF @preview = 'Y'
ROLLBACK TRANSACTION savepoint;
-- save output to temp table if used for return data
INSERT INTO #dataset_to_return (a)
SELECT a FROM @output_to_return;
COMMIT TRANSACTION;
SELECT a AS proc_return_data FROM #dataset_to_return;
RETURN 0;
GO
-- Examples
EXEC dbo.PREVIEW_EXAMPLE @preview = 'Y';
SELECT a AS user_table_after_preview_mode FROM user_table;
EXEC dbo.PREVIEW_EXAMPLE @preview = 'N';
SELECT a AS user_table_after_live_mode FROM user_table;
-- Cleanup
DROP TABLE dbo.user_table;
DROP PROCEDURE dbo.PREVIEW_EXAMPLE;
GO
Sto cercando feedback su questo codice e modello di progettazione e / o se esistono altre soluzioni allo stesso problema in diversi formati.