sql atomic exists/insert - multiple unique fields - sql

Ok, so I've learned from other posts/sites, that the following style of query will execute atomically:
INSERT INTO Foo(field1, field2)
SELECT #field1, #field2
WHERE NOT EXISTS (SELECT * FROM Foo
WHERE Field1 = #field1
OR Field2 = #field2)
This would be used to satisfy a design requirement that both field1 and field2 be unique. So far, all is fine and dandy.
BUT, in the case of such a record already existing (where the query inserts 0 rows) what if I want to know WHICH field already had a record with the same value. (i.e., which of the following statements are true?
there was already an existing record where Field1 = #field1
there was already an existing record where Field2 = #field2
both of the above
You would need to know which field is at fault in order to show an error message that tells the user which field they need to change to a unique value. I could always check with a second query, but that would not be atomic. The data may have changed between the attempted insert and the 2nd query to determine which field was at fault, and the error message may not reflect the actual state of the DB.
Any ideas on how to handle this case?

Assumptions:
You expect most INSERTs to succeed.
You have a unique contraint such that a bad INSERT will fail.
You aren't concerned about matching NULLs.
set transaction isolation level serializable;
begin transaction;
begin try
insert into Foo ( Field1, Field2 ) values ( #Field1, #Field2 );
end try
begin catch
-- Really ought to confirm that the error was the expected one here.
select
#Field1Match = case when Field1 = #Field1 then Cast( 1 as Bit ) else Cast( 0 as Bit ) end,
#Field2Match = case when Field2 = #Field2 then Cast( 1 as Bit ) else Cast( 0 as Bit ) end
from Foo
where Field1 = #Field1 or Field2 = #Field2;
end catch;
commit transaction;

Based on my research (here & here), unless you have a very high confidence that over 95% of the inserts will succeed, I would use the opposite approach as HABO. Borrowing from the same assumption that you aren't concerned about matching NULLs:
DECLARE #Col1Match VARCHAR(20), #Col2Match VARCHAR(20), #msg NVARCHAR(4000);
SET ANSI_WARNINGS OFF;
BEGIN TRANSACTION;
SELECT #Col1Match = MAX(CASE Field1 WHEN #Field1 THEN 'Field1 exists:' END),
#Col2Match = MAX(CASE Field2 WHEN #Field2 THEN 'Field2 exists:' END)
FROM dbo.Foo WITH (HOLDLOCK)
WHERE Field1 = #Field1 OR Field2 = #Field2;
IF #Col1Match IS NULL AND #Col2Match IS NULL
BEGIN
INSERT dbo.Foo(Field1, Field2) SELECT #Field1, #Field2;
END
ELSE
BEGIN
SET #msg = LTRIM(COALESCE(' ' + #Col1Match + ' (' + #Field1 + ')', '')
+ COALESCE(' ' + #Col2Match + ' (' + #Field2 + ')', ''));
END
COMMIT TRANSACTION;
IF #msg IS NOT NULL
BEGIN
RAISERROR(#msg, 11, 1);
END

Related

Implicit conversion of varchar value to varchar cannot be performed due to a collation conflict

When I try to change the collation of a column in SQL Server I get the following error.
Implicit conversion of varchar value to varchar cannot be performed because the collation of the value is unresolved due to a collation conflict between "Latin1_General_CS_AI" and "SQL_Latin1_General_CP1_CI_AS" in add operator.
Below is the specific query I am trying to run. I get the same error regardless of whether I run the query manually or use the GUI.
ALTER TABLE myTable ADD myColumn NVARCHAR(152) COLLATE Latin1_General_CS_AI NULL;
Edit:
Upon doing some more digging I think the issue may occur when sql server tries to rebuild one of the triggers on the table. Partially shown below... I apologize for the awful formatting but I can't seem to get it to format properly
Edit 2: Thanks for fixing my formatting! :) The line at the bottom of the code section below seems to be where the error is originating.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER trigger [dbo].[payee_audit_update_trigger] on [dbo].[payee] for update as
begin
set nocount on
declare #userId varchar(50), #sqlStatement varchar(255), #appId int, #transactionId int, #insertChangedValues varchar(255), #auditEnabled char(1), #timezoneOffsetMinutes int
exec AuditGetSessionInfo ##rowcount, #userId output, #sqlStatement output, #appId output, #transactionId output, #insertChangedValues output, #auditEnabled output, #timezoneOffsetMinutes output
if (#auditEnabled = 'N')
return
declare #auditDate datetime
set #auditDate = dateadd(MINUTE, #timezoneOffsetMinutes, getutcdate())
insert into audit_log_tx (company_id, application_id, change_date_time, id, table_name, transaction_id, user_id, sql_statement, primary_key_crc, primary_key_values, changed_values)
select inserted.company_id,#appId, #auditDate, dbo.AuditGetRowId(newId()), 'payee', #transactionId, #userId, #sqlStatement, binary_checksum(rtrim(inserted.id)), rtrim(inserted.id),
case when (inserted.company_id = deleted.company_id) or (inserted.company_id is null and deleted.company_id is null) then '' else 'company_id|' + case when deleted.company_id is null then '<null>' else rtrim(deleted.company_id) end + '|' + case when inserted.company_id is null then '<null>' else rtrim(inserted.company_id) end + '^' end + ...
------
case when (inserted.w4_status = deleted.w4_status) or (inserted.w4_status is null and deleted.w4_status is null) then '' else 'w4_status|' + case when deleted.w4_status is null then '<null>' else rtrim(deleted.w4_status) end + '|' + case when inserted.w4_status is null then '<null>' else rtrim(inserted.w4_status) end + '^' end +
how about forcing the collation in the query:
if for example is happening at field1 = field2
you can force it like:
field1 collate Latin1_General_CI_AS = field1 collate Latin1_General_CI_AS

SQL partial update of columns based on case statement?

Recently I have had to do a few variable updates to a table, and although I am aware of the MERGE statement (although need to catch up on all of that!), I also performed the following statement to optional update a table and wish to check if this is "a good idea" or has some hidden consequences that I not aware of.
So in my case, I pass a primary key to a table, however depending on if parameters passed are null or not, I update the column.. obviously if you had to ensure a forceful update (of a status etc.) then you would just update the column.. this is to save having multiple "IF / THEN" type structures..
create procedure sp_myprocedure
as
#id bigint,
#field1 int = null,
#field2 varchar(255) = null,
#field3 char(1) = null
begin
update my_table
set
field1 = case when #field1 is not null then #field1 else field1 end,
field2 = case when #field2 is not null then #field2 else field2 end,
field3 = case when #field3 is not null then #field3 else field3 end,
where
id = #id
end
Just after some thoughts of the above or is it best to pursue the MERGE statement for scenarios like the above?
Many thanks in advance,
This is fine although it can be written in a cleaner way.
update my_table
set
field1 = coalesce (#field1,field1)
,field2 = coalesce (#field2,field2)
,field3 = coalesce (#field3,field3)
where
id = #id and coalesce(#field1,#field2,#field3) is not null
You can also move the coalesce(#field1,#field2,#field3) is not null to a wrapper block
if coalesce(#field1,#field2,#field3) is not null
begin
update my_table
set
field1 = coalesce (#field1,field1)
,field2 = coalesce (#field2,field2)
,field3 = coalesce (#field3,field3)
where
id = #id
end
MERGE statement is not relevant here.
With MERGE the decision is if to INSERT, UPDATE or DELETE a record base on the non-existent/existent of a record with the same merge keys in the source/target table.
In your case it is always UPDATE.
create procedure sp_myprocedure
#id bigint,
#field1 int = null,
#field2 varchar(255) = null,
#field3 char(1) = null
as
begin
IF coalesce(#field1,#field2,#field3) is not null
update dbo.my_table
set
field1 = coalesce (#field1,field1),
field2 = coalesce (#field2,field2),
field3 = coalesce (#field3,field3)
where id = #id
END
Responding to the answer by #Dudu Markovitz:
MERGE statement is not relevant here.
I disagree , I think MERGE is entirely relevant here.
The idea is to create a source table expression using the parameter values with which to update the target table:
MERGE my_table T
USING ( VALUES ( #id, #field1, #field2, #field3 ) )
AS S ( id, field1, field2, field3 )
ON T.id = S.id
WHEN MATCHED THEN
UPDATE
SET field1 = COALESCE( S.field1, T.field1 ),
field2 = COALESCE( S.field2, T.field2 ),
field3 = COALESCE( S.field3, T.field3 );
Of course, if there was a single table-valued parameter (as arguable there should be) then the relevance of MERGE is even more obvious.

Why WHEN MATCHED' cannot appear more than once in a 'UPDATE' clause of a MERGE statement?

I'm taking a bunch of CRUD opertations and creating merge storedprocs off the CUD. My stored proc looks like this
CREATE PROCEDURE usp_AdministrationHistoryMerge
#AdministrationHistoryID int out,
#AdministratorID int,
#DateCreated datetime,
#CreatedBy nvarchar(50),
#ModifiedBy nvarchar(50),
#Action int
AS
SET NOCOUNT OFF
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
DECLARE #ERROR_SEVERITY int,
#MESSAGE varchar(1000),
#ERROR_NUMBER int,
#ERROR_PROCEDURE nvarchar(200),
#ERROR_LINE int,
#ERROR_MESSAGE nvarchar(4000),
#IsActive bit,
#DateModified datetime;
begin try
if #Action = 1
begin
set #IsActive = 1
set #AdministrationHistoryID = SCOPE_IDENTITY()
end
merge [AdministrationHistory] as target
using (select #AdministratorID, #DateCreated, #CreatedBy, #DateModified, #ModifiedBy, #IsActive)
as source (AdministratorID, DateCreated, CreatedBy, DateModified, ModifiedBy, IsActive)
on (target.AdministrationHistoryID = source.AdministrationHistoryID)
when matched and #Action = -1 then
update
set IsActive = 0
when matched and #Action = 0 then
update
set ModifiedBy = #ModifiedBy,
DateModified = GETDATE()
when matched and #Action = 1 then
insert
(AdministratorID, DateCreated, CreatedBy, IsActive)
values
(#AdministratorID, #DateCreated, #CreatedBy, #IsActive);
end try
BEGIN CATCH
SET #ERROR_SEVERITY = ISNULL(ERROR_SEVERITY(),'');
SET #ERROR_NUMBER = ISNULL(ERROR_NUMBER(),'');
SET #ERROR_PROCEDURE = ISNULL(ERROR_PROCEDURE(),'');
SET #ERROR_LINE = ISNULL(ERROR_LINE(),'');
SET #ERROR_MESSAGE = ISNULL(ERROR_MESSAGE(),'');
-- Test if the transaction is uncommittable.
IF (XACT_STATE()) = -1
BEGIN
--PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
-- Test if the transaction is active and valid.
IF (XACT_STATE()) = 1
BEGIN
--PRINT N'The transaction is committable. Committing transaction.'
COMMIT TRANSACTION;
END;
SET #MESSAGE = 'Error Occured in Stored Procedure ' + cast(#ERROR_PROCEDURE as varchar(200)) +
'; Line Number ' + cast(#ERROR_LINE as varchar) +
'; Message: [' + cast(#ERROR_NUMBER as varchar) + '] - '
+ cast(#ERROR_MESSAGE as varchar(255))
RAISERROR(#MESSAGE, #ERROR_SEVERITY, 1);
END CATCH;
When I go to execute this I am getting this full error
Msg 10714, Level 15, State 1, Procedure usp_AdministrationHistoryMerge, Line 36
An action of type 'WHEN MATCHED' cannot appear more than once in a 'UPDATE' clause of a MERGE statement.
I have looked around on SO and found a couple ways to resolve this, but what I have found aren't suitable solutions for this error, as instead of a delete and I need to update the record's IsActive to a 0.
Also, in my searching no one really explains why this error is being thrown, yes I know its obvious because the error is right there, but why is this not allowed to happen? and based on this circumstance are there any idea's on how to accomplish this? or should I have this merge call another storedproc when #Action is 0?
In your MERGE statement, you have three WHEN MATCHED clauses
Two with an UPDATE statement
One with an INSERT statement.
However, that is not allowed. It is clearly stated in the Documentation on MERGE:
The MERGE statement can have at most two WHEN MATCHED clauses.
And
If there are two WHEN MATCHED clauses, then one must specify an UPDATE action and one must specify a DELETE action.
Also important to know is:
If UPDATE is specified in the <merge_matched> clause, and more than one row of <table_source> matches a row in target_table based on <merge_search_condition>, SQL Server returns an error. The MERGE statement cannot update the same row more than once, or update and delete the same row.
The SQL standard (and e.g. Db2) allows this, but not SQL Server. This article documents how you can emulate several WHEN MATCHED THEN UPDATE clauses also in SQL Server. In your case
MERGE INTO [AdministrationHistory] AS target
USING (
SELECT #AdministratorID, #DateCreated, #CreatedBy, #DateModified, #ModifiedBy, #IsActive
) AS source (AdministratorID, DateCreated, CreatedBy, DateModified, ModifiedBy, IsActive)
ON (target.AdministrationHistoryID = source.AdministrationHistoryID)
-- Combine both predicates using OR. This is optional.
WHEN MATCHED AND #Action = -1 OR #Action = 0 THEN UPDATE SET
-- UPDATE clause from the first "WHEN MATCHED AND #Action = -1" clause
IsActive = CASE WHEN #Action = -1 THEN 0 ELSE IsActive END,
-- UPDATE clauses from the second "WHEN MATCHED AND #Action = 0" clause
ModifiedBy = CASE WHEN #Action = 0 THEN #ModifiedBy ELSE ModifiedBy END,
DateModified = CASE WHEN #Action = 0 THEN GETDATE() ELSE DateModified END
WHEN NOT MATCHED AND #Action = 1 THEN INSERT
(AdministratorID, DateCreated, CreatedBy, IsActive)
VALUES
(#AdministratorID, #DateCreated, #CreatedBy, #IsActive);

Sql If statement based on COUNT return

Basically, I am looking to modify a stored procedure that I have in my database already that updates a table's records (table x) with data coming from a web application. After updating table x, I want to develop that stored procedure to check table x to see if there exist anymore records for that instance of the primary key where column_z is null. Basically, something like
ALTER PROCEDURE [cred].[UpdateTablex]
(#field0 int,
#field1 int,
#field2 int,
#field3, int,
#field4 VARCHAR(100),
#field5 datetime,
#field6 datetime)
AS
UPDATE tablex
SET field4 = #field4,
field6 = #field6
WHERE field1 = #field1 AND
field2 = #field2 AND
field3 = #field3 AND
field0 = #field0 AND
field5 = #field5;
The rest of this will be psuedocode for my idea and the way I thought it might be developed
IF ((SELECT COUNT(field0) FROM tablex WHERE field6 is null AND field2 = #field2
AND field3 = #field3 AND field5 = #field5) equals 0)
exec cred.Demobilize(#field0, #field1);
Or simply, if that Select statement returns any results indicating that field6 is null anywhere then we do nothing. Obviously that would mean then that if the Select statement returns nothing, then I want to execute another stored procedure.
This is probably something simple so please forgive me as I'm kinda new to certain types of SQL syntax and usage, this being one of them.
Also, could anybody point me in a proper direction to further educate myself on topics like this?
Thank you.
You can do the if without using a variable:
IF (0 = (SELECT COUNT(field0)
FROM tablex
WHERE field6 is null AND field2 = #field2 AND field3 = #field3 AND field5 = #field5
)
)
begin
exec cred.Demobilize(#field0, #field1);
end;
In practice, I think this would more commonly be written using not exists:
IF (not exists (SELECT 1
FROM tablex
WHERE field6 is null AND field2 = #field2 AND field3 = #field3 AND field5 = #field5
)
)
begin
exec cred.Demobilize(#field0, #field1);
end;
The not exists version can be faster, because the first row encountered will satisfy the condition clause. The count(*) version has to find all matching rows and count them.

Insert default value when parameter is null

I have a table that has a column with a default value:
create table t (
value varchar(50) default ('something')
)
I'm using a stored procedure to insert values into this table:
create procedure t_insert (
#value varchar(50) = null
)
as
insert into t (value) values (#value)
The question is, how do I get it to use the default when #value is null? I tried:
insert into t (value) values ( isnull(#value, default) )
That obviously didn't work. Also tried a case statement, but that didn't fair well either. Any other suggestions? Am I going about this the wrong way?
Update: I'm trying to accomplish this without having to:
maintain the default value in multiple places, and
use multiple insert statements.
If this isn't possible, well I guess I'll just have to live with it. It just seems that something this should be attainable.
Note: my actual table has more than one column. I was just quickly writing an example.
Christophe,
The default value on a column is only applied if you don't specify the column in the INSERT statement.
Since you're explicitiy listing the column in your insert statement, and explicity setting it to NULL, that's overriding the default value for that column
What you need to do is "if a null is passed into your sproc then don't attempt to insert for that column".
This is a quick and nasty example of how to do that with some dynamic sql.
Create a table with some columns with default values...
CREATE TABLE myTable (
always VARCHAR(50),
value1 VARCHAR(50) DEFAULT ('defaultcol1'),
value2 VARCHAR(50) DEFAULT ('defaultcol2'),
value3 VARCHAR(50) DEFAULT ('defaultcol3')
)
Create a SPROC that dynamically builds and executes your insert statement based on input params
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
The following 2 commands should give you an example of what you want as your outputs...
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
I know this is a very convoluted way of doing what you need to do.
You could probably equally select the default value from the InformationSchema for the relevant columns but to be honest, I might consider just adding the default value to param at the top of the procedure
Try an if statement ...
if #value is null
insert into t (value) values (default)
else
insert into t (value) values (#value)
As far as I know, the default value is only inserted when you don't specify a value in the insert statement. So, for example, you'd need to do something like the following in a table with three fields (value2 being defaulted)
INSERT INTO t (value1, value3) VALUES ('value1', 'value3')
And then value2 would be defaulted. Maybe someone will chime in on how to accomplish this for a table with a single field.
Probably not the most performance friendly way, but you could create a scalar function that pulls from the information schema with the table and column name, and then call that using the isnull logic you tried earlier:
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
And then call it like this:
INSERT INTO t (value) VALUES ( ISNULL(#value, SELECT dbo.GetDefaultValue('t', 'value') )
This is the best I can come up with. It prevents sql injection uses only one insert statement and can ge extended with more case statements.
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
chrisofspades,
As far as I know that behavior is not compatible with the way the db engine works,
but there is a simple (i don't know if elegant, but performant) solution to achive your two objectives of DO NOT
maintain the default value in multiple places, and
use multiple insert statements.
The solution is to use two fields, one nullable for insert, and other one calculated to selections:
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
This method even let You centralize the management of business defaults in a parameter table, placing an ad hoc function to do this, vg changing:
selValue AS ISNULL(insValue, 'something')
for
selValue AS ISNULL(insValue, **getDef(t,1)**)
I hope this helps.
The best option by far is to create an INSTEAD OF INSERT trigger for your table, removing the default values from your table, and moving them into the trigger.
This will look like the following:
create trigger dbo.OnInsertIntoT
ON TablenameT
INSTEAD OF INSERT
AS
insert into TablenameT
select
IsNull(column1 ,<default_value>)
,IsNull(column2 ,<default_value>)
...
from inserted
This makes it work NO MATTER what code tries to insert NULLs into your table, avoids stored procedures, is completely transparent, and you only need to maintain your default values in one place, namely this trigger.
You can use default values for the parameters of stored procedures:
CREATE PROCEDURE MyTestProcedure ( #MyParam1 INT,
#MyParam2 VARCHAR(20) = ‘ABC’,
#MyParam3 INT = NULL)
AS
BEGIN
-- Procedure body here
END
If #MyParam2 is not supplied, it will have the 'ABC' value...
You can use the COALESCE function in MS SQL.
INSERT INTO t ( value ) VALUES( COALESCE(#value, 'something') )
Personally, I'm not crazy about this solution as it is a maintenance nightmare if you want to change the default value.
My preference would be Mitchel Sellers proposal, but that doesn't work in MS SQL. Can't speak to other SQL dbms.
Don't specify the column or value when inserting and the DEFAULT constaint's value will be substituted for the missing value.
I don't know how this would work in a single column table. I mean: it would, but it wouldn't be very useful.
Hope To help to -newbie as i am- Ones who uses Upsert statements in MSSQL.. (This code i used in my project on MSSQL 2008 R2 and works simply perfect..May be It's not Best Practise.. Execution time statistics shows execution time as 15 milliSeconds with insert statement)
Just set your column's "Default value or binding" field as what you decide to use as default value for your column and Also set the column as Not accept null values from design menu and create this stored 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)
-- in my project #Value13 is a photo column which storing as byte array..
--And i planned to use a default photo when there is no photo passed
--to sp to store in db..
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`
With enough defaults on a table, you can simply say:
INSERT t DEFAULT VALUES
Note that this is quite an unlikely case, however.
I've only had to use it once in a production environment. We had two closely related tables, and needed to guarantee that neither table had the same UniqueID, so we had a separate table which just had an identity column, and the best way to insert into it was with the syntax above.
The most succinct solution I could come up with is to follow the insert with an update for the column with the default:
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
The pattern I generally use is to create the row without the columns that have default constraints, then update the columns to replace the default values with supplied values (if not null).
Assuming col1 is the primary key and col4 and col5 have a default contraint
-- 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
If you want the actual values defaulted into the 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
Cheers...
The easiest way to do this is to modify the table declaration to be
CREATE TABLE Demo
(
MyColumn VARCHAR(10) NOT NULL DEFAULT 'Me'
)
Now, in your stored procedure you can do something like.
CREATE PROCEDURE InsertDemo
#MyColumn VARCHAR(10) = null
AS
INSERT INTO Demo (MyColumn) VALUES(#MyColumn)
However, this method ONLY works if you can't have a null, otherwise, your stored procedure would have to use a different form of insert to trigger a default.
The questioner needs to learn the difference between an empty value provided and null.
Others have posted the right basic answer: A provided value, including a null, is something and therefore it's used. Default ONLY provides a value when none is provided. But the real problem here is lack of understanding of the value of null.
.