Salve,
come dice @migliorabile, di base non esiste una funzionalita' simile... o forse non nel senso da me interpretato...
a prescindere da cio', e' possibile definire un DEFAULT constraint a livello di singola colonna, quindi
ALTER TABLE [dbo].[nomeTabella]
ADD CONSTRAINT [DF_nomeTabella_nomeColonna] DEFAULT ( 98582.29 ) FOR [nomeColonna];
e quindi provvedere al comando di inserimento tramite
INSERT [dbo].[nomeTabella]
VALUES ( xx, yy, zz, DEFAULT );
dove DEFAULT indica all'engine di utilizzare il DEFAULT constraint value definito come valore da inserire nella nuova riga...
ma, se tu, come mi pare di aver capito, potresti VOLER cambiare nel tempo questo valore, e quindi, da quel momento sino alla prossima variazione, vuoi utilizzare quell' "ultimo valore" come nuovo default, allora la definizione di un constraint non ha molto senso... in questo caso direi abbia piu' senso utilizzare una tabella di appoggio che tu interrogherai al momento dell'insert...
la cosa diventa un pochettino "disgustosa" ma, sempre come diceva @migliorabile, e' fattibile...
basandoci su questa tabella di appoggio, puoi "giocare" con tali valori, ad esempio verificare che la tabella di appoggio abbia un valore predefinito per quella colonna di quella tabella, e nel caso di "assenza di valorizzazione" utilizzare tale default predefinito, ed aggiornare la tabella di appoggio in caso di valore reale definito dall'utente...
con un esempio "triviale", bisogna innanzitutto definire "COSA" indica l'assenza di un valore utente e quindi la richiesta di del "default". definito tale "default" per la colonna, aggiungiamo tale valore alla tabella di appoggio che sara' definita, ad esempio, dal "schema + nomeTabella + nomeColonna" e il relativo valore, ospitato in un tipo sql_variant (che permette di ospitare ogni tipo di dato)...
al momento del nuovo inserimento, verifichiamo che per la colonna il valore utente sia diverso dal "vecchio default", e nel caso aggiorniamo/aggiungiamo, e quindi utilizziamo tali valori ottenuti per il nuovo inserimento...
per l'operazione di gestione dei default utilizziamo in questo esempio un comando di MERGE che verifica la tabella di appoggio in riferimento ai parametri che forniamo alla stored procedure di INSERT, dopo di che possiamo tranquillamente interrogare la tabella di appoggio per tutti i valori necessari, unitamente ai parametri collegati a colonne che non si appoggino su default da noi definiti...
{spezzetto tutto il codice in blocchi perche' ho problemi a far accettare al motore delle regole del forum i comandi DDL}
di nuovo, brutalmente, possiamo scrivere qualche cosa simile a
SET NOCOUNT ON;
USE tempdb;
GO
DEFINIZIONE TABELLA dbo].[tabellaX] (
[Id] int NOT NULL PRIMARY KEY IDENTITY,
[colA] int NOT NULL,
[ColB] decimal (18,4) NOT NULL,
[ColC] date NOT NULL,
[ColD] varchar(10) NOT NULL,
[ColNoDefault] int
);
DEFINIZIONE TABELLA [dbo].[DefaultValues] (
[TabNameColName] varchar(381) NOT NULL, -- [ + 126_char + ] + . + [ + 126_char + ] . [ + 126_char + ] + . + [ + 126_char + ]
[DefaultVal] SQL_VARIANT
);
GO
-- popolamento iniziale Valori Default
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colA]', 5 );
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colB]', 98582.29 );
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colC]', GETDATE() );
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colD]', 'pippo' );
SELECT *
FROM [dbo].[DefaultValues];
--/ popolamento iniziale Valori Default
-- popolamento iniziale Valori Default
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colA]', 5 );
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colB]', 98582.29 );
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colC]', GETDATE() );
INSERT INTO [dbo].[DefaultValues]
VALUES ( '[dbo].[tabellaX].[colD]', 'pippo' );
SELECT *
FROM [dbo].[DefaultValues];
--/ popolamento iniziale Valori Default
GO
segue poi un esempio di generazione di stored procedure...
DDL di generazione procedura [dbo].[usp_INSERT_from_ValuesAndDefaults] (
@ColA int = -2147483648 -- integer.minValue come NON Value per usare il DEFAULT di appoggio
, @ColB decimal(18, 4) = -2147483648 -- integer.minValue come NON Value per usare il DEFAULT di appoggio
, @ColC date = '0001-01-01' -- date.minValue come NON Value per usare il DEFAULT di appoggio
, @ColD varchar(10) = '<EMPTY>' -- <EMPTY> come NON Value per usare il DEFAULT di appoggio
, @ColNoDefault int
)
AS BEGIN
--dichiarazione di dei default values delle singole colonne interessate,
-- CONST
DECLARE @defColA int = -2147483648; -- integer.minValue come NON Value per usare il DEFAULT di appoggio
DECLARE @defColB decimal(18, 4) = -2147483648; -- integer.minValue come NON Value per usare il DEFAULT di appoggio
DECLARE @defColC date = '0001-01-01'; -- date.minValue come NON Value per usare il DEFAULT di appoggio
DECLARE @defColD varchar(10) = '<EMPTY>'; -- <EMPTY> come NON Value per usare il DEFAULT di appoggio
-- /CONST
-- utilizzo di MERGE per verificare/aggiornare la tabella di appoggio default
riscrivo i COMANDI in italiano per evitare che il parser di validazione delle regole del forum blocchi il messaggio, dove {usando}={USING}
MERGE [dbo].[DefaultValues] AS target
{usando} ( SELECT '[dbo].[tabellaX].[colA]', CAST( @ColA AS SQL_VARIANT)
UNION SELECT '[dbo].[tabellaX].[colB]', CAST( @ColB AS SQL_VARIANT)
UNION SELECT '[dbo].[tabellaX].[colC]', CAST( @ColC AS SQL_VARIANT)
UNION SELECT '[dbo].[tabellaX].[colD]', CAST( @ColD AS SQL_VARIANT)
) AS source ( [TabNameColName], [DefaultVal] )
ON target.[TabNameColName] = source.[TabNameColName]
WHEN MATCHED
AND (target.[DefaultVal] <> source.[DefaultVal] AND source.[DefaultVal] NOT IN ( @defColA, @defColB, @defColC, @defColD )
) THEN
UPDATE SET [DefaultVal] = source.[DefaultVal]
WHEN NOT MATCHED BY target THEN
INSERT ([TabNameColName], [DefaultVal])
VALUES ( source.[TabNameColName], source.[DefaultVal]);
-- recupero dei default da per tutte le colonne che lo prevedono
WITH cte AS (
SELECT CASE WHEN df.[TabNameColName] = '[dbo].[tabellaX].[colA]' AND df.[DefaultVal] IS NOT NULL THEN df.[DefaultVal] ELSE NULL END AS '[dbo].[tabellaX].[colA]'
, CASE WHEN df.[TabNameColName] = '[dbo].[tabellaX].[colB]' AND df.[DefaultVal] IS NOT NULL THEN df.[DefaultVal] ELSE NULL END AS '[dbo].[tabellaX].[colB]'
, CASE WHEN df.[TabNameColName] = '[dbo].[tabellaX].[colC]' AND df.[DefaultVal] IS NOT NULL THEN df.[DefaultVal] ELSE NULL END AS '[dbo].[tabellaX].[colC]'
, CASE WHEN df.[TabNameColName] = '[dbo].[tabellaX].[colD]' AND df.[DefaultVal] IS NOT NULL THEN df.[DefaultVal] ELSE NULL END AS '[dbo].[tabellaX].[colD]'
FROM [dbo].[DefaultValues] df
WHERE df.[TabNameColName] IN ( '[dbo].[tabellaX].[colA]', '[dbo].[tabellaX].[colB]', '[dbo].[tabellaX].[colC]', '[dbo].[tabellaX].[colD]' )
),
cteRes AS (
SELECT MAX(cte.[[dbo]].[tabellaX]].[colA]]]) AS '[dbo].[tabellaX].[colA]'
, MAX(cte.[[dbo]].[tabellaX]].[colB]]]) AS '[dbo].[tabellaX].[colB]'
, MAX(cte.[[dbo]].[tabellaX]].[colC]]]) AS '[dbo].[tabellaX].[colC]'
, MAX(cte.[[dbo]].[tabellaX]].[colD]]]) AS '[dbo].[tabellaX].[colD]'
FROM cte
)
-- ed infine
INSERT INTO [dbo].[tabellaX]
SELECT CAST(c.[[dbo]].[tabellaX]].[colA]]] AS int)
, CAST(c.[[dbo]].[tabellaX]].[colB]]] AS decimal(18,4))
, CAST(c.[[dbo]].[tabellaX]].[colC]]] AS date)
, CAST(c.[[dbo]].[tabellaX]].[colD]]] AS varchar(10))
, @ColNoDefault
FROM cteRes c;
END;
ed infine un test di utilizzo...
partiamo inserendo SOLO i default,
poi modifichiamo un parametro/default alla volta giusto per verifica...
-- CONST
DECLARE @defColA int = -2147483648; -- integer.minValue come NON Value per usare il DEFAULT di appoggio
DECLARE @defColB decimal(18, 4) = -2147483648; -- integer.minValue come NON Value per usare il DEFAULT di appoggio
DECLARE @defColC date = '0001-01-01'; -- date.minValue come NON Value per usare il DEFAULT di appoggio
DECLARE @defColD varchar(10) = '<EMPTY>'; -- <EMPTY> come NON Value per usare il DEFAULT di appoggio
-- /CONST
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, @defColB, @defColC, @defColD, 1;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] 1, @defColB, @defColC, @defColD, 2;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, 1234.56, @defColC, @defColD, 3;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, @defColB, @defColC, @defColD, 4;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, @defColB, '2019-01-01', @defColD, 5;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, @defColB, @defColC, @defColD, 6;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, @defColB, @defColC, 'pippo', 7;
SELECT * FROM [dbo].[tabellaX];
EXEC [dbo].[usp_INSERT_from_ValuesAndDefaults] @defColA, @defColB, @defColC, @defColD, 8;
SELECT * FROM [dbo].[tabellaX];
--<------------------------
TabNameColName DefaultVal
---------------------------- --------------------------------
[dbo].[tabellaX].[colA] 5
[dbo].[tabellaX].[colB] 98582.29
[dbo].[tabellaX].[colC] 2019-09-17 14:07:33.577
[dbo].[tabellaX].[colD] pippo
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
3 1 1234.5600 2019-09-17 pippo 3
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
3 1 1234.5600 2019-09-17 pippo 3
4 1 1234.5600 2019-09-17 pippo 4
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
3 1 1234.5600 2019-09-17 pippo 3
4 1 1234.5600 2019-09-17 pippo 4
5 1 1234.5600 2019-01-01 pippo 5
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
3 1 1234.5600 2019-09-17 pippo 3
4 1 1234.5600 2019-09-17 pippo 4
5 1 1234.5600 2019-01-01 pippo 5
6 1 1234.5600 2019-01-01 pippo 6
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
3 1 1234.5600 2019-09-17 pippo 3
4 1 1234.5600 2019-09-17 pippo 4
5 1 1234.5600 2019-01-01 pippo 5
6 1 1234.5600 2019-01-01 pippo 6
7 1 1234.5600 2019-01-01 pippo 7
Warning: Null value is eliminated by an aggregate or other SET operation.
Id colA ColB ColC ColD ColNoDefault
----------- ----------- --------------------------------------- ---------- ---------- ------------
1 5 98582.2900 2019-09-17 pippo 1
2 1 98582.2900 2019-09-17 pippo 2
3 1 1234.5600 2019-09-17 pippo 3
4 1 1234.5600 2019-09-17 pippo 4
5 1 1234.5600 2019-01-01 pippo 5
6 1 1234.5600 2019-01-01 pippo 6
7 1 1234.5600 2019-01-01 pippo 7
8 1 1234.5600 2019-01-01 pippo 8
dove, man mano che modifichiamo i nostri default, questi verranno propagati per i successivi inserimenti...
ricordarsi alla fine del clean up cancellando da tempdb tutti gli oggetti qui generati, PROCEDURA [dbo].[usp_INSERT_from_ValuesAndDefaults] e TABELLE [dbo].[DefaultValues], [dbo].[tabellaX];
come vedi, non e' assolutamente "elegante", ed in questo caso e' direttamente cablata (nella rotazione di colonne su riga) sulla specificita' della tabella...
forse pero' puo' essere di spunto per il tuo ragionamento...
saluti omnia
--
Andrea