How to insert into the table a user name record - sql

I've a table. In this table I have two columns - 'insert_name' and 'modified_name'. I need to insert into this columns data about who has inserted data into the table('insert_name') and who has changed these data in the table (modified_name). How it can be done?

You are looking for basic DML statements.
If your record is already in the table, then you need to UPDATE it. Otherwise, when you are about to add your record to it and it doesn't already exist in the destination table then you are looking for INSERT INTO statement.
Example of updating information for record with first id:
UPDATE yourtable SET insert_name = 'value1', modified_name = 'value2' WHERE id = 1
Example of inserting new record:
INSERT INTO yourtable(id, company_name, product_name, insert_name)
VALUES (1, 'Google', 'PC', 'value1')
If you are looking for automatic changes to those columns then you need to look into triggers.
Remember that more often than not you may find that the application connecting to the database is using single database user in which case you probably know the context within the application itself (who inserts, who updates). This does eliminate triggers and put the task straight on simple insert/update commands from within your application layer.

You might be able to use the CURRENT_USER function to find the name of the user making the change.
The value from this function could then be used to update the appropriate column. This update could be done as part of the INSERT or UPDATE statement. Alternatively use an INSERT or UPDATE trigger.
Personally I avoid triggers if I can.

For those 2 columns add Current_User as Default constraint.
As the first time Insert Statement will save them with current login user names. For update write an Update trigger with the same Current_User statement for the column Modified_Name.
If and only if your application business logic can't update the column modified_nme then only go for Trigger.
See the use of Current_Use
https://msdn.microsoft.com/en-us/library/ms176050.aspx

Related

Is is safe to use ##IDENTITY in a transaction?

I was reading this answer about different methods of getting the last identity value entered into a database.
From what I understand, ##IDENTITY is usually a very bad idea because it might return an identity that is not the one you expected--for example an identity value that was recently created by a trigger.
But what if your code is in a transaction?
For example this is a simplified version of a transaction I'm doing (using ColdFusion):
<cftransaction>
<cfquery name="queryInsertA" datasource="source">
INSERT INTO tableA (columnName) VALUES (value)
</cfquery>
<cfquery name="queryInsertB" datasource="source">
INSERT INTO tableB (fkey_tableA, columnName) VALUES (##IDENTITY, value)
</cfquery>
</cftransaction>
Since, "If a transaction is successful, all of the data modifications made during the transaction are committed and become a permanent part of the database," does this mean that it would also prevent the isses that can arise when using ##IDENTITY? Or am I misunderstanding the behavior of transactions?
The answer you linked already explains what the main issue is with ##IDENTITY: scope. If your insert triggers another insert, you get an unexpected identity back. Transactions do not change anything.
If you wanted to get the last identity value inserted to a table, use the Ident_current() function.
Select ident_current ('your table name')
Also you can use scope_identity(), It will bring the identity value of a tablein that particular scope only.
Select scope_identity()
You don't need ##Identity, nor do you need 2 separate queries. Use the Scope_identity() function for integrity and make it a part of the same connection & query - like so.
<cfquery name="putUser" datasource="#dsn#">
SET NOCOUNT ON
INSERT INTO users(username, email)
VALUES
('#usersname#','#email#' )
SELECT SCOPE_IDENTITY() AS newId FROM users
SET NOCOUNT OFF
</cfquery>
<cfoutput>#putUser.newID#</cfoutput>
This will be totally safe, but like all db transactions it will still be subject to deadlocks so tuning is still important.
CFTRANSACTION is good for multiple DB operations where some CF logic might also be involved, but let the DB locking and transactional system work for you by keeping it together.
You can also use the result attribute of cfquery. If the query performs an INSERT of an identity or auto-increment value for ID, there will be a key named GENERATEDKEY returned in the structure.
<cftransaction>
<cfquery name="queryInsertA" datasource="source" result="resultA">
INSERT INTO tableA (columnName) VALUES (value)
</cfquery>
<cfquery name="queryInsertB" datasource="source">
INSERT INTO tableB (fkey_tableA, columnName) VALUES (#resultA.generatedKey#, value)
</cfquery>
</cftransaction>
Keep in mind this is only CF9 and higher.
You can use Sequence and use that during insert as below:
CREATE SEQUENCE Testseq
START WITH 1
INCREMENT BY 1 ;
Access the sequence by using below query:
SELECT NEXT VALUE FOR Testseq;
To make it simple :
IF
You know you'r ALL ALONE in the db system, this means, no other user, or process running at the same time, no other transaction running, there is absolutly ZERO activity at the time you use it, and i mean it, ZERO ACTIVITY, then, ok...
ELSE
NO ! If anything like i listed above does occur exactly while your transact is running, you will end up with the wrong identity.
It depends on what else is running at the same time as your transaction is instantiated. If there is a trigger on a table unrelated to the transaction that can insert a new identity value, the transaction scope you are currently in will not protect you.
For example say I create a SPROC that updates Table_A and inserts a record into it. This table has an identity field on it that will increment the ID value in that table each time a new record is inserted. Inside my SPROC I create a transaction and place my insert inside the transaction. After the insert I store the value of ##IDENTITY in a variable inside the same transaction.
Now I also have another table Table_B with it's own identity value but this table is trigger maintained. If I am executing my SPROC to insert a row in Table_A and during this update Table_B is also updated via a trigger, it is possible that when I retrieve the value of ##IDENTITY, it will actually give me the value of the ID created for Table_B rather than Table_A.
You should definitely use Transactions in your stored procedures but you are better off selecting the MAX(ID) of the table you inserted into to retrieve the ID you created rather than ##IDENTITY.

Change column value after INSERT if the value fits criteria?

I have never really worked with Triggers before in MSSQL but I think it'll be what I need for this task.
The structure of the table is as such:
ID|****|****|****|****|****|****|****|TOUROPERATOR
The Tour Operator Code is the code that tells us what company owned the flight we carried out for them. Two of those codes (there are 24 in total) are outdated. Our users requested that those two be changed but the tour operator code is pulled from a database we don't control. The FlightData table however, we do control. So I was thinking a trigger could change the tour operator code if it was one of the two outdated ones, to the correct ones instead respectively when they were inserted.
So I went into good ol' SQL Management Studio and asked to make a trigger. It gave me some sample code and here is my Pseudo Code below:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER ChangeProvider
ON FlightData
AFTER INSERT
AS
BEGIN
IF(TheInsertedValue == Criteria)
UPDATE FlightData
SET TheInsertedValue = NewValue
ENDIF
END
GO
I am not that good with this type of Database Programming so excuse my mistakes.
How would I go about doing this?
You could add a computed column to your table instead of adding a trigger.
Then the new column could just use a case statement to either show
the original TourOperator column value or the new value you wanted.
You'd add a new column to your table like this
TourOperatorCorrect = CASE WHEN TourOperator = 'Whatever value' THEN 'ChangedValue'
--I just want to use what I have already in the TourOperator column
ELSE TourOperator
END AS VARCHAR(50)
Basics of computed columns are here - https://msdn.microsoft.com/en-ie/library/ms188300.aspx
Your misconception here is that the trigger runs once per inserted value - it is in fact run once per insert statement, so you can and will find more than one row inserted at once.
You'll find that your inserted values are in the pseudo table inserted, which has the same structure as your FlightData table in this case. You write a select statement against that, specifying any criteria you wish.
However, it's not immediately clear what your logic is - does the FlightData table you are updating in your trigger only have one row? Do you update every row in the table with the newest inserted value? It is hard to understand what you are trying to now, and what the purpose of the table and this trigger are - let alone what you would want to do if you inserted more than one row at once.
When inserted table contains mutiple rows,your code will fail,so change code to work with inserted table as whole
UPDATE F
SET f.TheInsertedValue = i.value
from inserted i
join
Flighttable F
on f.matchingcolumn=i.matchingcolumn
and i.somevalue='criteria'

Inserting to one table, insert the ID to second table

Is it possible to populate a second table when I insert into the first table?
Insert post to table1 -> table 2 column recieves table1 post's unique id.
What I got so far, am I on the right track?
CONSTRAINT [FK_dbo.Statistics_dbo.News_News_NewsID] FOREIGN KEY ([News_NewsID]) REFERENCES [dbo].[News] ([NewsID])
Lots of ways:
an insert trigger
read SCOPE_IDENTITY() after the first insert, and use it to do a second
use the output clause to do an insert
Examples:
1:
create trigger Foo_Insert on Foo after insert
as
begin
set nocount on
insert Bar(fooid)
select id from inserted
end
go
insert Foo (Name)
values ('abc');
2:
insert Foo (Name)
values ('abc');
declare #id int = SCOPE_IDENTITY();
insert Bar(fooid)
select #id
3:
insert Bar(fooid)
select id from (
insert Foo (Name)
output inserted.id
values ('abc')) x
The only thing I can think of is that you can use a trigger to accomplish this. There is nothing "built in" to SQL Server that would do it. Why not just do it from your .NET code?
Yes it is, it sounds like you want a SQL Trigger, this would allow you to trigger logic based on actions on one table, to perform other actions in the DB. Here's another article on creating Simple SQL Triggers
SQL Server 2008 - Help writing simple INSERT Trigger
A Word of caution, this will do all the logic of updating the new table, outside of any C# code you write, it might sound nice to not have to manage it upfront, but you also lose control over when and if it happens.
So if you need to do something different later, now you have to update your regular code, as well as the trigger code. This type of logic can definitely grow, in large systems, and become a nightmare to maintain. Consider this, the alternative would be to build a method that adds the id to the new table after it inserts into the first table.
While i don't know what you're using to do your inserts assuming it's a SQL Command you can get back the ID on an identity column from the insert using Scope_Identity, found here
How to insert a record and return the newly created ID using a single SqlCommand?
if it's EF or some other ORM tool, they should either automatically update the entity, or have other mechanisms to deliver this data.

Immutable SQL columns

Is it possible to mark a column immutable in MSSQL?
Seems like it would be a useful DDL feature; once a value is set in a row ('row' being defined as a specific relation of values to a primary key), it could not be changed without deletion of the row.
Obviously (like most things) this is more than doable in the application layer, but half the fun of SQL DDL is error-checking your application code.
If the user doing the DML is not the owner of the objects and not "db_owner" in the database itself, you can just grant "insert" privilege, but not update privilege for that table:
Assuming a table with id, col1, col2
grant insert, select, delete on the_table to the_user;
grant update (id, col2) on the_table to the_user;
With these grants the_user can insert rows and supply values for all three columns. He can also update the id and the col2 column, but not the col1 column.
The db_owner (and possibly the creator/owner of the table) can always update all columns. I don't know if there is a way to revoke that privilege from those rolws.
It's possible, using an UPDATE TRIGGER like this:
CREATE TRIGGER trgAfterUpdateAsset ON dbo.Asset
FOR UPDATE AS
IF UPDATE(AssetTypeID) AND EXISTS (SELECT * FROM inserted i JOIN deleted d ON i.ID = d.ID WHERE i.AssetTypeID <> d.AssetTypeID)
BEGIN
RAISERROR ('AssetTypeID cannot change.', 16, 1);
ROLLBACK TRAN
END
(Note: The table has a Primary Key column, called ID).
I'm only rejecting the update if the value of AssetTypeID changes. So the column could be present in an update, and if it specified the old value, than it would pass through. (I needed this way)
No, there is no such feature in SQL Server.
The closest I can think about is an update trigger on the table that checks if the values in the specific column are the same for the INSERTED and DELETED logical tables and rejects the updates for the changed rows.
To my knowledge, this is not possible with DDL. However, you could implement BEFORE UPDATE triggers to meet your requirement. In the BEFORE UPDATE trigger, you could raise an exception or do whatever you want rather than update the row.
Another approach is to deny update rights to the table and create a stored procedure (which users do have the right to execute) that does not update the immutable field.

Need some help with Sql Server and a simple Trigger

I wish to make a trigger but i'm not sure how to grab the data for whatever caused the trigger.
I have a simlpe table.
FooId INT PK NOT NULL IDENTITY
Name VARCHAR(100) NOT NULL
I wish to have a trigger so that when an UPDATE, INSERT or DELETE occurs, i then do the following.
Pseduocode
IF INSERT
Print 'Insert' & Name
ELSE IF UPDATE
Print 'Update' & FooId & Name
ELSE IF DELETE
Print 'Delete' & FooId & Name
Now, I know how to make a trigger for a table.
What i don't know how to do is figure out the values based on what the trigger type is.
Can anyone help?
Edit: Not sure if it helps, but db is Sql Server 2008
the pseudo table "inserted" contains the new data, and "deleted" table contains the old data.
You can do something like
create trigger mytrigger on mytable for insert, update, delete
as
if ( select count(*) from inserted ) > 0
-- insert or update
select FooId, Name from inserted
else
-- delete
select FooId, Name from deleted
To clarify all the comments made by others, on an insert, the inserted table contains data and deleted is empty. On a delete, the situation is reversed. On an update, deleted and inserted contain the "before" and "after" copy of any updated rows.
When you are writing a trigger, you have to account for the fact that your trigger may be called by a statement that effects more than one row at a time.
As others have pointed out, you reference the inserted table to get the values of new values of updated or inserted rows, and you reference the deleted table to get the value of deleted rows.
SQL triggers provide an implicitly-defined table called "inserted" which returns the affected rows, allowing you to do things like
UPDATE mytable SET mytimestamp = GETDATE() WHERE id IN (SELECT id FROM inserted)
Regarding your code sample, you'll want to create separate INSERT, UPDATE and DELETE triggers if you are performing separate actions for each.
(At least, this is the case in SQL Server... you didn't specify a platform.)
On 2008, there is also MERGE command. How do you want to handle it?
Starting from 2008, there are four commands you can modify a table with:
INSERT, UPDATE, DELETE, and MERGE:
http://blogs.conchango.com/davidportas/archive/2007/11/14/SQL-Server-2008-MERGE.aspx
http://sqlblogcasts.com/blogs/grumpyolddba/archive/2009/03/11/reasons-to-move-to-sql-2008-merge.aspx
What do you want your trigger to do when someone issues a MERGE command against your table?