当参数为空时插入默认值

我有一个表有一个默认值的列:

create table t ( value varchar(50) default ('something') ) 

我正在使用存储的过程将值插入到此表中:

 create procedure t_insert ( @value varchar(50) = null ) as insert into t (value) values (@value) 

问题是,如何在@valuenull时使用默认null ? 我试过了:

 insert into t (value) values ( isnull(@value, default) ) 

这显然不起作用。 也试过了一个case陈述,但这也不太公平。 还有其他build议吗? 我是否以错误的方式去做这件事?

更新:我试图做到这一点, 不必:

  1. 保持多个地方的default值,并
  2. 使用多个insert语句。

如果这是不可能的,那么我想我只能忍受它。 这似乎应该是可以实现的。

注意:我的实际表格有多个列。 我只是在写一个例子。

尝试一个if语句…

 if @value is null insert into t (value) values (default) else insert into t (value) values (@value) 

克里斯托夫,

只有在INSERT语句中未指定列的情况下才应用列上的默认值。

由于您明确地列出了插入语句中的列,并将其明确设置为NULL,所以这将覆盖该列的默认值

你需要做的是“如果null传递到你的存储过程,那么不要插入该列”。

这是一个快速和肮脏的例子,如何做一些dynamic的SQL。

使用默认值创build一些列的表…

 CREATE TABLE myTable ( always VARCHAR(50), value1 VARCHAR(50) DEFAULT ('defaultcol1'), value2 VARCHAR(50) DEFAULT ('defaultcol2'), value3 VARCHAR(50) DEFAULT ('defaultcol3') ) 

创build一个基于input参数dynamic构build和执行插入语句的SPROC

 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 

下面的2个命令应该给你一个你想要的作为你的输出的例子…

 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 

我知道这是一个非常复杂的方式来做你需要做的事情。 你也许可以同样从InformationSchema中select相关列的默认值,但说实话,我可能会考虑在程序的顶部添加默认值param

据我所知,默认值只在插入语句中没有指定值时插入。 所以,举个例子,你需要在一个有三个字段(value2为默认值)的表中做如下的事情:

 INSERT INTO t (value1, value3) VALUES ('value1', 'value3') 

然后value2将被默认。 也许有人会就如何完成一个单一的领域的表。

这是我能想到的最好的。 它可以防止SQL注入只使用一个插入语句,并可以扩展更多的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 

可能不是性能最友好的方式,但是可以创build一个标量函数,从信息模式中抽取表名和列名,然后使用之前尝试的isnull逻辑调用该函数:

  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 

然后像这样调用它:

 INSERT INTO t (value) VALUES ( ISNULL(@value, SELECT dbo.GetDefaultValue('t', 'value') ) 

chrisofspades,

据我所知,行为与数据库引擎的工作方式不兼容,但有一个简单的(我不知道是否优雅,但性能)解决scheme来实现你的两个目标

  1. 保持多个地方的默认值,并
  2. 使用多个插入语句。

解决方法是使用两个字段,一个是可插入的,另一个是计算select的:

 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 

这种方法甚至可以让您将业务默认值的pipe理集中在一个参数表中,通过设置一个特别的函数来完成这个任务:

 selValue AS ISNULL(insValue, 'something') 

对于

 selValue AS ISNULL(insValue, **getDef(t,1)**) 

我希望这有帮助。

您可以使用存储过程参数的默认值:

 CREATE PROCEDURE MyTestProcedure ( @MyParam1 INT, @MyParam2 VARCHAR(20) = 'ABC', @MyParam3 INT = NULL) AS BEGIN -- Procedure body here END 

如果未提供@ MyParam2,它将具有“ABC”值…

您可以在MS SQL中使用COALESCE函数。

INSERT INTO t(value)VALUES(COALESCE(@value,'something'))

就我个人而言,我对这个解决scheme并不着迷,因为如果你想改变默认值,这是一个维护的噩梦。

我的首选是Mitchel Sellers提案,但在MS SQL中不起作用。 无法与其他SQL dbms对话。

插入时不要指定列或值,而用DEFAULT常量的值代替缺失值。

我不知道这将如何工作在一个单独的列表中。 我的意思是:它会的,但它不会很有用。

希望以帮助新手,因为我 – 在MSSQL中使用Upsert语句的人。(这个代码我用在MSSQL 2008 R2的项目中,工作简单完美..可能不是最佳实践..执行时间统计信息显示执行时间与插入语句15毫秒)

只需将列的“默认值或绑定”字段设置为您决定用作列的默认值,并将列设置为“不接受devise菜单中的空值”并创build此存储的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) 

– 在我的项目@ Value13是一个照片列存储为字节数组.. – 而且我计划使用默认的照片,当没有照片传递 – 要sp存储在分贝..

 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` 

在桌面上有足够的默认值,你可以简单地说:

 INSERT t DEFAULT VALUES 

请注意,这是一个不太可能的情况,但是。

我只需要在生产环境中使用它一次。 我们有两个密切相关的表,并且需要保证这两个表都没有相同的UniqueID,所以我们有一个单独的表,它只有一个标识列,插入它的最好的方法是使用上面的语法。

我能想出的最简洁的解决scheme是跟随插入与列的默认更新:

 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 

到目前为止,最好的select是为您的表创build一个INSTEAD OF INSERT触发器,从您的表中删除默认值,并将它们移动到触发器中。

这将如下所示:

 create trigger dbo.OnInsertIntoT ON TablenameT INSTEAD OF INSERT AS insert into TablenameT select IsNull(column1 ,<default_value>) ,IsNull(column2 ,<default_value>) ... from inserted 

这使得它不工作什么代码试图将NULL插入到您的表中,避免存储过程,是完全透明的,你只需要维护你的默认值在一个地方,即这个触发器。

提问者需要了解提供的空值与空值之间的区别。

其他人已经发布了正确的基本答案:提供的值(包括null)是某种东西 ,因此被使用。 默认只在没有提供时提供一个值。 但这里真正的问题是缺乏对null值的理解。

最简单的方法是修改表声明

 CREATE TABLE Demo ( MyColumn VARCHAR(10) NOT NULL DEFAULT 'Me' ) 

现在,在你的存储过程中,你可以做类似的事情。

 CREATE PROCEDURE InsertDemo @MyColumn VARCHAR(10) = null AS INSERT INTO Demo (MyColumn) VALUES(@MyColumn) 

但是,这种方法只适用于不能有null的情况,否则,你的存储过程将不得不使用不同forms的插入触发默认值。