Sql job when certain things happen - sql

lets say I have the table below
Table User
UserId int
Username varchar(50)
Table History
ID int
WhoWasAdded varchar(50)
The SQl Job must insert a row into Table History every time a new user is added to Table User
WhoWasAdded comes from Username

Sample insert trigger code...
CREATE TABLE User
(
[NAME] NVARCHAR(50)
)
GO
CREATE TABLE History
(
[name] NVARCHAR(50)
)
GO
CREATE TRIGGER tblUpdateTrigger ON User
AFTER INSERT
AS
BEGIN
INSERT INTO History ([name])
SELECT T.[name]
FROM user T
INNER JOIN inserted i ON T.[name]=I.[name]
END
GO

Related

SQL Inserted table trigger

If I run the following select statement inside an insert trigger, is it possible that it will return more than one result?:
DECLARE #variable char(1) = (SELECT ID FROM inserted)
If so, then what's the best to handle it?
Here is the problem that I am trying to solve: Every time when the new record is inserted into a table, I want to take the newly inserted ID and insert it into another table(if it doesn't exists).
Thank you!
Instead of
DECLARE #variable char(1) = (SELECT ID FROM inserted)
You can do something like following:
Declare #VarTempTbl as table (id int)
Insert into #VarTempTbl (id)
Select id from inserted
So that you can get those values for further processing
Now, I had created Two tables One for Master table and another for When any Insertion happens in that Master table, that entry has to inserted into the another table.
CREATE TABLE tblEmployee
(
Id int Primary Key,
Name nvarchar(30),
Gender nvarchar(10),
DepartmentId int
)
CREATE TABLE tblEmployee_New
(
Id int Primary Key,
Name nvarchar(30),
Gender nvarchar(10),
DepartmentId int
)
Trigger:
CREATE TRIGGER TR_EMPLOYEEDETAILS_AFTEROFINSERT
ON TBLEMPLOYEE
AFTER INSERT
AS
BEGIN
TRUNCATE TABLE tblEmployee_New
INSERT INTO TBLEMPLOYEE_NEW(ID, NAME, GENDER, DEPARTMENTID)
SELECT ID, NAME, GENDER, DEPARTMENTID
FROM INSERTED
END
Now Lets try to insert into record into a master table
Insert into tblEmployee values (1,'John', 'Male', 3)
Insert into tblEmployee values (2,'Mike', 'Male', 2)
It has automatically insert the newly inserted records into the another table.
If your want to remove the Previous records then add a drop Statement in that above Trigger.
Note: You can also use #Temp Table instead of creating a another table('tblEmployee_New')
Kinldy Share your comments

Insert Records if not exist and then update with identity in one query

I have 2 tables.
create table Sales
(CustomerKey int
,ProductKey int
,CustomersProductsKey int
,SalesAmount decimal(19,4))
Create Table CustomersProducts
(CustomersProductsKey int IDENTITY(1,1),
CustomerKey int,
ProductKey int,
Attribute1 int,
Attribute2 varchar(max))
Currently when I add data to the sales table, I need to insert any new customerkey productkey combinations into the CustomersProducts table and then update the sales table with the resulting CustomersProductsKey identity value. This works.
Is there anyway that I can do this in one step? I don't know if a Merge can do an insert and update on the same if not matched step.
I also could be just looking at this the wrong way as well.
Thanks,
EDIT:
As you can imagine, the fact that I need to use a surrogate key is part of the design. It's needed for a BO report. Otherwise there would really be no need for CustomersProductsKey at all.
If add only one step to make it work,
I think we need create a another table and create trigger on the new table and CustomersProducts
create table CustomersSalesProducts
(CustomerKey int
,ProductKey int
,SalesAmount decimal(19,4)
,Attribute1 int
,Attribute2 varchar(max))
create trigger test1 on CustomersSalesProducts After Insert
as
begin
insert Sales select CustomerKey , ProductKey , 0, SalesAmount from inserted
insert CustomersProducts select CustomerKey , ProductKey , Attribute1, Attribute2 from inserted
end
go
create trigger test2 on CustomersProducts after insert
as
begin
Update Sales set CustomersProductsKey = inserted.CustomersProductsKey
from inserted , Sales
where inserted.CustomerKey = Sales.CustomerKey
and inserted.ProductKey = Sales.ProductKey
end
go
Test Script:
insert CustomersSalesProducts select 3,3,300,3,'Attribute2'

How would I do this with SQL Server?

I have two tables users and address
users table schema
user_id
name
address_id
sent
address table schema
address_id
create_date
location
user_id
I have this query that returns 16 rows
select * from users where sent = 1;
but all the address_id are all NULL because they have not been created yet
So what I need to do is create 16 rows in the address table one for each of the users with the user_id of the user and then set the address_id in the users table of that address
For now I can leave the location field blank. All I need to do is set the create_date to CURRENT_DATE
Is there a way to do this in one query?
Try this:
declare #user table(user_id [int] IDENTITY(1,1), name varchar(25), address_id int, sent int)
declare #address table(address_id [int] IDENTITY(1,1) NOT NULL, create_date datetime default getdate(), location varchar(100), user_id int)
declare #t table(user_id int, address_id int)
insert #user (name) values('you')
insert #user (name) values('someone else')
begin Transaction
insert #address (user_id)
output inserted.user_id, inserted.address_id
into #t
select user_id from #user u
where not exists (select 1 from #address where u.user_id = user_id)
update u
set u.address_id = t.address_id
from #user u
join #t t
on u.user_id = t.user_id
commit transaction
select * from #user
select * from #address
Not exactly sure what your mean but this should at least point you in the right direction
Begin Try
Begin Transaction
Update Users
Set Users.address = Address.address, create_date = GetDate()
From Addresses
Inner Join Users On Addresses.userid = Users.userid
Commit Transaction
End Try
Begin Catch
Rollback Transaction
End Catch
It should be something like this. There are a couple of ways of doing the problem so have fun with it and hopefully this helped. For testing it write two Select * From Users statements one before and one after. Also change Commit Transaction to Rollback Transaction so you don't have to worry about making a mistake.
Just reread question yea you can't do that in one shot just replace the Update statement with
Insert Into Addresses (address_id, create_date, location, user_id)
Values ('#ddr355_1d', GetDate(), '1234theLocation', 123478)
and you will have to do that for each one but should be easy with only 16 entries in the User table. You might want to look into writing a Stored Procedure if you plan on adding more to the table. Something kind of like this
Create Procedure [dbo].[AddressesInsertData]
(
#Address Int,
#Location varchar(100),
#UserId Int
)
As
Begin Try
Begin Transaction
Insert Into Addresses (address_id, create_date, location, user_id)
Values (#Address, GetDate(), #Location, #UserId)
Commit Transaction
End Try
Begin Catch
Rollback Transaction
End Catch
Basic structure of a stored procedure. I would add an if not exists in there that would update instead of insert but this should be plenty to get you started. Hopefully these examples should clear up somethings for you and help you out.
There is a design rules of thumb that a table models EITHER an entity/class OR the relationship between entities/classes but not both.
Therefore, I suggest you remove the address_id column from the users table, remove user_id from the address table and create a third table comprising both user_id and address_id to model the relationship between users and their addresses. This will also rid you of the need to have nullable columns.

i am trying to execute the before insert trigger , but i m getting the sql errors

what i want to achieve is i have a table called orders.
i want to perform the before insert trigger on my orders table.i want to capture the
username of person performing INSERT into table.
one table called info which contain the user.
this is my code
create table orders
(
order_id int,
quantity int,
cost int,
total_cost int,
created_date datetime,
created_by varchar(20)
)
create trigger beforeInsertdata
before insert
on orders
for each row
declare
v_username varchar2(10);
begin
-- Find username of person performing INSERT into table
SELECT user INTO v_username
FROM info;
-- Update create_date field to current system date
:new.create_date := sysdate;
-- Update created_by field to the username of the person performing the INSERT
:new.created_by := v_username;
END;
--user information--
create table info
(
userid int ,
user_name varchar(10)
)
insert into info values(1,'vivek')
select * from info
Basically, triggers are classified into two main types:-
1)After Triggers (For Triggers)
2)Instead Of Triggers
and the syntax for trigger is
CREATE TRIGGER trigger_name ON table_name
[FOR|AFTER|INSTEAD OF] [INSERT|UPDATE|DELETE]
AS
//your code goes here
GO
NOTE : FOR keyword used for INSERT |UPDATE Command where as AFTER USED FOR DELETE Command.
It's hard to tell what you're really trying to do. I've modified your code sample so that it will work on SQL2K5 and made some assumptions about how you're wanting to use the connected user account.
CREATE TABLE orders (
order_id int,
quantity int,
cost int,
total_cost int,
created_date datetime,
created_by varchar(20)
);
CREATE TABLE info (
userid int,
user_name varchar(10)
);
INSERT INTO info
VALUES (1, 'vivek');
SELECT *
FROM info;
CREATE TRIGGER orders_InsteadOfInsert ON orders
INSTEAD OF INSERT AS BEGIN
SET NOCOUNT ON;
-- varchar(10) is to match your table, but probably should be larger
DECLARE #CurrentUser VarChar(10);
SELECT #CurrentUser = SYSTEM_USER;
IF (#CurrentUser NOT IN (SELECT user_name FROM info)) BEGIN
-- consider using an identity column for the key instead of this
INSERT INTO info (userid, user_name)
SELECT
ISNULL((SELECT MAX(userid) FROM info), 0) + 1,
#CurrentUser;
END;
INSERT INTO orders (order_id, quantity, cost, total_cost, created_date, created_by)
SELECT
INS.order_id,
INS.quantity,
INS.cost,
INS.total_cost,
GETDATE(),
#CurrentUser
FROM INSERTED INS;
END;

How do I insert from a table variable to a table with an identity column, while updating the the identity on the table variable?

I'm writing a SQL script to generate test data for our database. I'm generating the data in table variables (so I can track it later) and then inserting it into the real tables. The problem is, I need to track which rows I've added to the parent table, so that I can generate its child data later on in the script. For example:
CREATE TABLE Customer (
CustomerId INT IDENTITY,
Name VARCHAR(50)
)
CREATE TABLE Order (
OrderId INT IDENTITY,
CustomerId INT,
Product VARCHAR(50)
)
So, in my script, I create equivalent table variables:
DECLARE #Customer TABLE (
CustomerId INT IDENTITY,
Name VARCHAR(50)
) -- populate customers
DECLARE #Order TABLE (
OrderId INT IDENTITY,
CustomerId INT,
Product VARCHAR(50)
) -- populate orders
And I generate and insert sample data into each table variable.
Now, when I go to insert customers from my table variable into the real table, the CustomerId column in the table variable will become meaningless, as the real table has its own identity seed for its CustomerId column.
Is there a way I can track the new identity of each row inserted into the real table, in my table variable, so I can use a proper CustomerId for the order records? Or, is there a better way I should be going about this?
(Note: I originally started with an application to generate the test data, but it ran too slow during insert as > 1,000,000 records need to be generated.)
WHy do you need identity values on the table variables? If you use just int, you can isnert the ids after the insert is done. Grab them using the output clause. YOu might need an input values and an output values table varaiable to get this just right like this:
DECLARE #CustomerInputs TABLE (Name VARCHAR(50) )
DECLARE #CustomerOutputs TABLE (CustomerId INT ,Name VARCHAR(50) )
INSERT INTO CUSTOMERS (name)
OUTPUT inserted.Customerid, inserted.Name INTO #CustomerOutputs
SELECT Name FROM #CustomerInputs
SELECT * from #CustomerOutputs
You can insert the data to the table with a cursor and use the built-in function SCOPE_IDENTITY() to get the last id which was inserted in the current scope (by your script).
See this MSDN article for more information on SCOPE_IDENTITY.
Here is one way of doing it. If you can use it depends on your situation. You should not do it in production environment when users use your db.
-- Get the next identity values for Customer and Order
declare #NextCustomerID int
declare #NextOrderID int
set #NextCustomerID = IDENT_CURRENT('Customer')+1
set #NextOrderID = IDENT_CURRENT('Order')+1
-- Create tmp tables
create table #Customer (CustomerID int identity, Name varchar(50))
create table #Order (OrderID int identity, CustomerID int, Product varchar(50))
-- Reseed the identity columns in temp tables
dbcc checkident(#Customer, reseed, #NextCustomerID)
dbcc checkident(#Order, reseed, #NextOrderID)
-- Populate #Customer
-- Populate #Order
-- Allow insert to identity column on Customer
set identity_insert Customer on
-- Add rows to Customer
insert into Customer(CustomerId, Name)
select CustomerID, Name
from #Customer
-- Restore identity functionality on Customer
set identity_insert Customer off
-- Add rows to Order
set identity_insert [Order] on
insert into [Order](OrderID, CustomerID, Product)
select OrderID, CustomerID, Product
from #Order
set identity_insert [Order] off
-- Drop temp tables
drop table #Customer
drop table #Order
-- Check result
select * from [Order]
select * from Customer
The way I'd do it its first obtain the MAX(CustomerId) from your Customer Table. Then I'd get rid of the IDENTITY column on your variable table and do my own CustomerId using ROW_NUMBER() and the MaxCustomerId. It should be something like this:
DECLARE #MaxCustomerId INT
SELECT #MaxCustomerId = ISNULL(MAX(CustomerId),0)
FROM Customer
DECLARE #Customer TABLE (
CustomerId INT,
Name VARCHAR(50)
)
INSERT INTO #Customer(CustomerId, Name)
SELECT #MaxCustomerId + ROW_NUMBER() OVER(ORDER BY SomeColumn), Name
FROM YourDataTable
Or insert the values on a temp table, so you can use the same ids to fill your Order table.