I have a table with a column which has default value to 0. However when null is inserted to this table, I want it to set it to default.
As the insert query is generic and used by other databases too, I cannot make any changes to the insert statement.
Can I have constraints or case statement on create table, so that default 0 value is inserted whenever null is passed.
If you can not change an insert statement you have no way other then creating an instead of insert trigger:
CREATE TRIGGER trTableName
ON SchemaName.TableName
INSTEAD OF INSERT
AS
BEGIN
INSERT INTO TableName (ColumnA, ColumnB, ...)
SELECT ISNULL(ColumnA, 0), ISNULL(ColumnB, 0), ...
FROM INSERTED
END
You can do an update using a trigger on insert.
CREATE TRIGGER [dbo].[YourTriggerName]
ON [dbo].[YourTable]
AFTER INSERT
AS
BEGIN
UPDATE t SET YourCol = 0
FROM YourTable t
JOIN Inserted i ON t.Id = i.Id
WHERE i.YourCol IS NULL
END
Inserting null is the same as inserting a specific value, and so the default value is bypassed.
To use the default setting the insert statement shouldn't insert anything to this column.
If you can't use Coalesce (value, 0) in the select bit of the into statement, try using it in your select queries to disguise the result.
Related
I am working in SQL Server Management Studio v18, and I have the following trigger:
CREATE TRIGGER [dbo].[update_surface]
ON [dbo].[my_table]
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #surface_m2 REAL
SET #surface_m2 = (SELECT cast(round(CAST(Dimension1*Dimension2 as decimal)/ cast(1000000 as decimal),3,3) as decimal(10,3)) AS surface FROM my_table WHERE Surface_m2 IS NULL)
UPDATE dbo.my_table SET Surface_m2 = #surface_m2
END
I have two columns in my_table, which are Dimesion1 and Dimension2. I want that the trigger multiplies them, and set the result to other column in the same table, which is Surface_m2, whenever this column is null. The trigger does his function, but based on the type of insert I do:
If I insert a row in my_table by the graphic environment the trigger works as I wish. With each new row, Surface_m2 has his own result.
But if I insert by INSERT INTO my_table VALUES ().... (query) the trigger updates Surface_m2 column of all previous rows with the result of each new insert.
Why is the trigger working like that? Is there any other simple way to do what I am trying to do?
Thanks.
Insert trigger gives you actual values that are inserted in a special table called... "inserted".
So what you need to do is join this table against your main table and perform the logic needed, no variables required.
Something like this untested code
create trigger...
begin
UPDATE t
SET Surface_m2 = cast(round(CAST(t.Dimension1*t.Dimension2 as decimal)
/ cast(1000000 as decimal),3,3) as decimal(10,3))
from dbo.my_table t
inner join inserted i
ON i.ID = t.ID
WHERE t.Surface_m2 IS NULL
end
This begs the question though, why can't you just insert the Surface_m2 value yourself. Or even better, change Surface_m2 to be a computed column if it's always depends on Dimension1 and Dimension2
I have a code about Insert into a table, for example:
Insert Into MyTable(PropertyName,PropertyID)
values('PropertyName1', (if exists(select 1 from PropertyTable where propertyName='PropertyName1') return null
else
insert into PropertyTable(Name) values('PropertyName1')
return scope_Identity()))
my problem is at there:
insert into PropertyTable(Name) values('PropertyName1')
return scope_Identity()
I need if my row isn't exist in my table, at first insert new value in a table and then return ID for use in above insert.
but i don't know how do it?
I don't know if your code is completely ok, but a alternative solution for the use of scope_identity is output clause.
Try this and tell me if works:
Insert Into MyTable (PropertyName,PropertyID) values('PropertyName1',
(if exists(select 1 from PropertyTable where propertyName='PropertyName1')
return null
else
insert into PropertyTable(Name)
output inserted.nameOfYourIDColumn
values('PropertyName1')));
We have an Instead-Of-Insert trigger on a view which copies all values from the INSERTED virtual-table to another table.
One of the fields in the list is non-nullable for the target table, and has a default value specified.
What we are experiencing, is, some application code is sending an insert command, and not specifying the non-nullable field - which (if the insert were executed against the actual table) would normally result in SQL Server inserting the column's default value. But, the trigger is explicit for all fields, so the trigger tries to insert null for that field... resulting in an error.
What I DONT want, is code like this...
INSERT INTO XXXX (col1, col2, col3)
SELECT
ISNULL(col1, 0), ISNULL(COL2, 0), ISNULL(COL3, 0)
FROM INSERTED
I don't want the trigger to need to know what the actual default values of each column should be (from a maintainability perspective)...
Does anyone have a better solution?
Thanks
when your application is sending NULL values to a not nullable column, there are not to many options. specialy when you dont want to use input validation with isnull.
we are using default values in this case. if it is possible you can alter your table:
ALTER TABLE xxxx ADD CONSTRAINT DF_col1 DEFAULT N'default' FOR col1;
I can think of an ugly and inefficient way of doing this. The idea is to insert a default row and then update the columns one at a time, using try/catch to ignore errors.
declare #Id int;
insert int XXX DEFAULT VALUES;
set #id = ##IDENTITY;
begin try
update XXX set col1 = val1 where id = #id;
end try
begin catch
end catch;
begin try
update XXX set col2 = val2 where id = #id;
end try
begin catch
end catch;
. . .
If you have to do this on 100 columns, then that could be a bad idea. If you only have two or three columns causing the problems, then this might solve your problem.
all id columns has auto_increment
In my trigger:
ALTER trigger [dbo].[mytrig]
on [dbo].[requests]
after INSERT, UPDATE
as
begin
declare #MyId1 int
set #MyId1 = (select Id from inserted)
declare #MyId2 int
declare #MyId3 int
if (select column1 from inserted) = 1
begin
insert into [dbo].[contracts] select column1,column2,column3 .... from inserted
set #MyId2 = SCOPE_IDENTITY()
insert into [dbo].[History] select column1,column2,column3 .... from inserted
set #MyId3 = SCOPE_IDENTITY()
insert into [dbo].[contracts_depts](Id_Contract ,column5) select #MyId2,column6 from request_depts where Id_request=#MyId1
insert into [dbo].[History_depts] (Id_InHistory,column5) select #MyId3,column6 from request_depts where Id_request=#MyId1
end
end
#MyId1 returns value only after update but not after insert. Do I have to use scope_identity() or something ?
Your main issue is: you're assuming the triggers is called once per row - that is NOT the case!
The trigger is called once per statement, and if your statement affects multiple rows, the Inserted pseudo table will contain multiple rows - so your statement here
set #MyId1 = (select Id from inserted)
really isn't going to work - it will select one arbitrary row (out of however many there are).
You'll need to rewrite your trigger to take this fact into account! Assume that Inserted contains 100 rows - how do you want to deal with that? What are you trying to achieve? Triggers don't return values - they will record into an audit table, or update other rows, or something like that ....
INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)
Now what to check:
If inserted value1 = null, change it to 0
How to do it via trigger? I googled for examples and I have never ever done a trigger, so it is rather confusing.
So far got only this:
CREATE TRIGGER testTrigger
ON myTable
AFTER INSERT, UPDATE, DELETE
You can add default value . This is how it's done for a new column. For existing one you should add constraint. Check Update 2
ALTER TABLE table_name
ADD column1 int NOT NULL DEFAULT(0)
Add a column with a default value to an existing table in SQL Server
UPDATE:
To set default value, you should update NULL values at first.
UPDATE table_name
SET column1 = 0
WHERE column1 IS NULL
UPDATE 2:
Try adding constraint
ALTER TABLE table_name
ADD CONSTRAINT DF_column1 DEFAULT 0 FOR column1
You could write this in the trigger:
UPDATE T SET value1 =0
FROM table_name T
JOIN INSERTED I
ON T.<id>=I.<id>
WHERE I.value1 is null
INSERTED table which is accessible only within trigger will store the values that have inserted..
use ISNULL on the INSERTED value
SELECT ISNULL(INSERTED,0) FROM INSERTED