J'ai une table qui a une colonne avec une valeur par défaut:
create table t (
value varchar(50) default ('something')
)
J'utilise une procédure stockée pour insérer des valeurs dans cette table:
create procedure t_insert (
@value varchar(50) = null
)
as
insert into t (value) values (@value)
La question est, comment puis-je le faire utiliser la valeur par défaut lorsque @value
est null
? J'ai essayé:
insert into t (value) values ( isnull(@value, default) )
Cela n'a évidemment pas fonctionné. Également essayé une déclaration case
, mais cela n’a pas non plus très bien fonctionné. D'autres suggestions? Est-ce que je m'y prends mal?
Mise à jour: j'essaie d'accomplir ceci sans avoir à:
default
à plusieurs endroits, etinsert
.Si cela n’est pas possible, je suppose que je devrai vivre avec. Il semble juste que quelque chose que cela devrait être réalisable.
Remarque: ma table actuelle comporte plusieurs colonnes. Je viens juste d'écrire un exemple rapidement.
Essayez une déclaration si ...
if @value is null
insert into t (value) values (default)
else
insert into t (value) values (@value)
Christophe,
La valeur par défaut d'une colonne n'est appliquée que si vous ne spécifiez pas la colonne dans l'instruction INSERT.
Étant donné que vous listez explicitement la colonne dans votre instruction insert et que vous définissez explicitement la valeur sur NULL, la valeur par défaut de cette colonne est prioritaire.
Ce que vous devez faire est "si un null est passé dans votre sproc, ne tentez pas d'insérer pour cette colonne".
Ceci est un exemple rapide et méchant de la façon de procéder avec du SQL dynamique.
Créer une table avec des colonnes avec des valeurs par défaut ...
CREATE TABLE myTable (
always VARCHAR(50),
value1 VARCHAR(50) DEFAULT ('defaultcol1'),
value2 VARCHAR(50) DEFAULT ('defaultcol2'),
value3 VARCHAR(50) DEFAULT ('defaultcol3')
)
Créez un SPROC qui construit et exécute de manière dynamique votre instruction insert en fonction de paramètres d'entrée
ALTER PROCEDURE t_insert (
@always VARCHAR(50),
@value1 VARCHAR(50) = NULL,
@value2 VARCHAR(50) = NULL,
@value3 VARCAHR(50) = NULL
)
AS
BEGIN
DECLARE @insertpart VARCHAR(500)
DECLARE @valuepart VARCHAR(500)
SET @insertpart = 'INSERT INTO myTable ('
SET @valuepart = 'VALUES ('
IF @value1 IS NOT NULL
BEGIN
SET @insertpart = @insertpart + 'value1,'
SET @valuepart = @valuepart + '''' + @value1 + ''', '
END
IF @value2 IS NOT NULL
BEGIN
SET @insertpart = @insertpart + 'value2,'
SET @valuepart = @valuepart + '''' + @value2 + ''', '
END
IF @value3 IS NOT NULL
BEGIN
SET @insertpart = @insertpart + 'value3,'
SET @valuepart = @valuepart + '''' + @value3 + ''', '
END
SET @insertpart = @insertpart + 'always) '
SET @valuepart = @valuepart + + '''' + @always + ''')'
--print @insertpart + @valuepart
EXEC (@insertpart + @valuepart)
END
Les 2 commandes suivantes devraient vous donner un exemple de ce que vous voulez comme sorties ...
EXEC t_insert 'alwaysvalue'
SELECT * FROM myTable
EXEC t_insert 'alwaysvalue', 'val1'
SELECT * FROM myTable
EXEC t_insert 'alwaysvalue', 'val1', 'val2', 'val3'
SELECT * FROM myTable
Je sais que c’est une façon très compliquée de faire ce que vous devez faire .. Vous pouvez probablement également sélectionner la valeur par défaut dans InformationSchema pour les colonnes pertinentes, mais pour être honnête, je pourrais envisager d’ajouter la valeur par défaut à param à le haut de la procédure
Autant que je sache, la valeur par défaut n'est insérée que si vous ne spécifiez pas de valeur dans l'instruction d'insertion. Ainsi, par exemple, vous devrez faire quelque chose comme ce qui suit dans une table avec trois champs (valeur2 étant la valeur par défaut)
INSERT INTO t (value1, value3) VALUES ('value1', 'value3')
Et alors valeur2 serait par défaut. Peut-être que quelqu'un expliquera comment y parvenir pour une table avec un seul champ.
chrisofspades,
Autant que je sache, ce comportement n’est pas compatible avec le fonctionnement du moteur de base de données, mais il existe une solution simple (je ne sais pas si elle est élégante, mais performante) pour atteindre vos deux objectifs de NE PAS
La solution consiste à utiliser deux champs, l'un nullable pour l'insertion et l'autre calculé en fonction des sélections:
CREATE TABLE t (
insValue VARCHAR(50) NULL
, selValue AS ISNULL(insValue, 'something')
)
DECLARE @d VARCHAR(10)
INSERT INTO t (insValue) VALUES (@d) -- null
SELECT selValue FROM t
Cette méthode vous permet même de centraliser la gestion des valeurs par défaut dans une table de paramètres, en plaçant une fonction ad hoc pour le faire, par exemple en changeant:
selValue AS ISNULL(insValue, 'something')
for
selValue AS ISNULL(insValue, **getDef(t,1)**)
J'espère que ça aide.
Ce n’est probablement pas la solution la plus conviviale, mais vous pouvez créer une fonction scalaire extraite du schéma d’information avec le nom de la table et de la colonne, puis appeler celle-ci en utilisant la logique isnull que vous avez précédemment testée:
CREATE FUNCTION GetDefaultValue
(
@TableName VARCHAR(200),
@ColumnName VARCHAR(200)
)
RETURNS VARCHAR(200)
AS
BEGIN
-- you'd probably want to have different functions for different data types if
-- you go this route
RETURN (SELECT TOP 1 REPLACE(REPLACE(REPLACE(COLUMN_DEFAULT, '(', ''), ')', ''), '''', '')
FROM information_schema.columns
WHERE table_name = @TableName AND column_name = @ColumnName)
END
GO
Et puis appelez ça comme ça:
INSERT INTO t (value) VALUES ( ISNULL(@value, SELECT dbo.GetDefaultValue('t', 'value') )
C'est le meilleur que je puisse trouver. Cela empêche l'injection SQL n'utilise qu'une seule instruction insert et peut être étendue avec plus d'instructions case.
CREATE PROCEDURE t_insert ( @value varchar(50) = null )
as
DECLARE @sQuery NVARCHAR (MAX);
SET @sQuery = N'
insert into __t (value) values ( '+
CASE WHEN @value IS NULL THEN ' default ' ELSE ' @value ' END +' );';
EXEC sp_executesql
@stmt = @sQuery,
@params = N'@value varchar(50)',
@value = @value;
GO
Vous pouvez utiliser les valeurs par défaut pour les paramètres des procédures stockées:
CREATE PROCEDURE MyTestProcedure ( @MyParam1 INT,
@MyParam2 VARCHAR(20) = ‘ABC’,
@MyParam3 INT = NULL)
AS
BEGIN
-- Procedure body here
END
Si @ MyParam2 n'est pas fourni, il aura la valeur 'ABC' ...
Ne spécifiez pas la colonne ou la valeur lors de l'insertion et la valeur de la constaint DEFAULT sera substituée à la valeur manquante.
Je ne sais pas comment cela fonctionnerait dans une table à une seule colonne. Je veux dire: ce serait, mais ce ne serait pas très utile.
Le modèle que j'utilise généralement consiste à créer la ligne sans les colonnes qui ont des contraintes par défaut, puis à mettre à jour les colonnes pour remplacer les valeurs par défaut par les valeurs fournies (si non nul).
En supposant que col1 est la clé primaire et que col4 et col5 ont une sous-indication par défaut
-- create initial row with default values
insert table1 (col1, col2, col3)
values (@col1, @col2, @col3)
-- update default values, if supplied
update table1
set col4 = isnull(@col4, col4),
col5 = isnull(@col5, col5)
where col1 = @col1
Si vous voulez que les valeurs réelles par défaut dans la table ...
-- create initial row with default values
insert table1 (col1, col2, col3)
values (@col1, @col2, @col3)
-- create a container to hold the values actually inserted into the table
declare @inserted table (col4 datetime, col5 varchar(50))
-- update default values, if supplied
update table1
set col4 = isnull(@col4, col4),
col5 = isnull(@col5, col5)
output inserted.col4, inserted.col5 into @inserted (col4, col5)
where col1 = @col1
-- get the values defaulted into the table (optional)
select @col4 = col4, @col5 = col5 from @inserted
À votre santé...
La solution la plus succincte que je puisse trouver est de suivre l'insertion avec une mise à jour de la colonne avec la valeur par défaut
IF OBJECT_ID('tempdb..#mytest') IS NOT NULL DROP TABLE #mytest
CREATE TABLE #mytest(f1 INT DEFAULT(1), f2 INT)
INSERT INTO #mytest(f1,f2) VALUES (NULL,2)
INSERT INTO #mytest(f1,f2) VALUES (3,3)
UPDATE #mytest SET f1 = DEFAULT WHERE f1 IS NULL
SELECT * FROM #mytest
Avec suffisamment de valeurs par défaut sur une table, vous pouvez simplement dire:
INSERT t DEFAULT VALUES
Notez qu'il s'agit d'un cas peu probable, cependant.
Je n'ai eu à l'utiliser qu'une seule fois dans un environnement de production. Nous avions deux tables étroitement liées et nous devions garantir qu'aucune des tables ne contenait le même identifiant UniqueID. Nous avions donc une table distincte qui ne contenait qu'une colonne d'identité.
La meilleure option est de loin de créer un déclencheur INSTEAD OF INSERT pour votre table, en supprimant les valeurs par défaut de votre table et en les déplaçant dans le déclencheur.
Cela ressemblera à ceci:
create trigger dbo.OnInsertIntoT
ON TablenameT
INSTEAD OF INSERT
AS
insert into TablenameT
select
IsNull(column1 ,<default_value>)
,IsNull(column2 ,<default_value>)
...
from inserted
Cela le fait fonctionner, peu importe ce que le code essaie d'insérer des NULL dans votre table, évite les procédures stockées, est complètement transparent et vous n'avez besoin de conserver vos valeurs par défaut qu'à un seul endroit, à savoir ce déclencheur.
Vous pouvez utiliser la fonction COALESCE dans MS SQL.
INSERT INTO t (valeur) VALEURS (COALESCE (@value, 'quelque chose'))
Personnellement, je ne suis pas folle de cette solution car il s’agit d’un cauchemar de maintenance si vous souhaitez modifier la valeur par défaut.
Ma préférence irait à la proposition de Mitchel Sellers, mais cela ne fonctionne pas dans MS SQL. Impossible de parler à d'autres dbms SQL.
J'espère pouvoir aider à -newbie tel que je suis. Ceux qui utilisent les instructions Upsert dans MSSQL .. (Ce code est utilisé dans mon projet sur MSSQL 2008 R2 et fonctionne tout simplement de manière parfaite. temps comme 15 millisecondes avec l'instruction insert)
Définissez simplement le champ "Valeur par défaut ou liaison" de votre colonne comme ce que vous décidez d'utiliser comme valeur par défaut pour votre colonne et définissez également la colonne comme Ne pas accepter les valeurs Null du menu Création et créez ce Proc ..
`USE [YourTable]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[YourTableName]
@Value smallint,
@Value1 bigint,
@Value2 varchar(50),
@Value3 varchar(20),
@Value4 varchar(20),
@Value5 date,
@Value6 varchar(50),
@Value7 tinyint,
@Value8 tinyint,
@Value9 varchar(20),
@Value10 varchar(20),
@Value11 varchar(250),
@Value12 tinyint,
@Value13 varbinary(max)
- dans mon projet @ Value13 est une colonne de photo qui stocke sous forme de tableau d'octets ..-- Et je prévoyais d'utiliser une photo par défaut lorsqu'aucune photo n'est transmise -- à sp à stocker dans la base de données ..
AS
--SET NOCOUNT ON
IF @Value = 0 BEGIN
INSERT INTO YourTableName (
[TableColumn1],
[TableColumn2],
[TableColumn3],
[TableColumn4],
[TableColumn5],
[TableColumn6],
[TableColumn7],
[TableColumn8],
[TableColumn9],
[TableColumn10],
[TableColumn11],
[TableColumn12],
[TableColumn13]
)
VALUES (
@Value1,
@Value2,
@Value3,
@Value4,
@Value5,
@Value6,
@Value7,
@Value8,
@Value9,
@Value10,
@Value11,
@Value12,
default
)
SELECT SCOPE_IDENTITY() As InsertedID
END
ELSE BEGIN
UPDATE YourTableName SET
[TableColumn1] = @Value1,
[TableColumn2] = @Value2,
[TableColumn3] = @Value3,
[TableColumn4] = @Value4,
[TableColumn5] = @Value5,
[TableColumn6] = @Value6,
[TableColumn7] = @Value7,
[TableColumn8] = @Value8,
[TableColumn9] = @Value9,
[TableColumn10] = @Value10,
[TableColumn11] = @Value11,
[TableColumn12] = @Value12,
[TableColumn13] = @Value13
WHERE [TableColumn] = @Value
END
GO`