Searching and inserting data if not exist using stored procedure - sql-server

I am trying to insert data using a stored procedure while searching based on Customer and AccountNumber. Is there any way I can write following code in shorter form? Should I create a stored procedure in database for this or just use this to insert from VB directly?
declare #Customer int ,#AccountNumber int
IF NOT EXISTS (SELECT * FROM Table_A
WHERE AccountNumber = #AccountNumber AND Customer = #Customer)
BEGIN
INSERT INTO Table_A
SELECT TOP 1 *
FROM Table_B
WHERE AccountNumber = #AccountNumber AND Customer = #Customer
END
IF NOT EXISTS (SELECT * FROM Table_A
WHERE AccountNumber = #AccountNumber AND Customer = #Customer)
BEGIN
INSERT INTO Table_A
SELECT TOP 1 *
FROM Table_C
WHERE AccountNumber = #AccountNumber AND Customer = #Customer
END
IF NOT EXISTS (SELECT * FROM Table_A
WHERE AccountNumber = #AccountNumber AND Customer = #Customer)
BEGIN
INSERT INTO Table_A
SELECT TOP 1 *
FROM Table_D
WHERE AccountNumber = #AccountNumber AND Customer = #Customer
END

Combining all the comments here is some shorter code. Points to note:
Its recommended to always fully list the columns involved in an INSERT statement. Its clearer what is happening, and not going to cause issues if you have IDENTITY columns, or change your table definition in future.
TOP 1 without an ORDER BY is going to return random results which is not usually what you want.
INSERT INTO Table_A
SELECT *
FROM (
SELECT TOP 1 *
FROM Table_B
WHERE AccountNumber = #AccountNumber AND Customer = #Customer
UNION ALL
SELECT TOP 1 *
FROM Table_C
WHERE AccountNumber = #AccountNumber AND Customer = #Customer
UNION ALL
SELECT TOP 1 *
FROM Table_D
WHERE AccountNumber = #AccountNumber AND Customer = #Customer
) X
WHERE NOT EXISTS (
SELECT 1
FROM Table_A A
WHERE A.AccountNumber = X.AccountNumber AND A.Customer = X.Customer
)

Related

I need to insert rows in bulk like in 1000's using triggers having different value in one column

Here is the trigger
CREATE TRIGGER [dbo].[Teacher]
ON [dbo].[Teacher]
After INSERT
AS
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Set #Mycounter =1
While #Mycounter <5
BEGIN
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
I need to insert 1000's of rows in HeadofDep table when any row is inserted in Teacher table. I have done by applying looping but all rows that get inserted in HeadofDep table have same #PR. Need it different against each row.
Also need sessionid incremented.
How can I achieve that?
Just, increment the SessionID then and put the other stuff in the loop:
Declare #fid int, #PR NVARCHAR(MAX),#Mycounter as INT
Set #Mycounter =1
While #Mycounter <5
BEGIN
Select top 1 #fid = eid from human where TypeID = 2
order by NewID()
Select top 1 #PR = Pid from [dbo].[Program] Where Depid = 1
order by NewID()
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID, #fid,#PR,NULL,null from INSERTED
Where eid in (Select eid from human where TypeID = 3)
set #MyCounter = #MyCounter + 1;
END
Also, doing such LOOPs in triggers is bad.In this case, you can change 1000 inserts with one like this:
Insert Into HeadofDep(SessionID,fid,pid,name,createddate)
Select SessionID + N, #fid,#PR,NULL,null
from INSERTED
CROSS APPLY
(
SELECT TOP (1000) -1+row_number() over(order by t1.number) as N
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) DS
Where eid in (Select eid from human where TypeID = 3)

Creating duplicates with a different ID for test in SQL

I have a table with 1000 unique records with one of the field as ID. For testing purpose, my requirement is that To update the last 200 records ID value to the first 200 records ID in the same table. Sequence isn't mandatory.
Appreciate help on this.
Typically I charge for doing other ppls homework, don't forget to cite your source ;)
declare #example as table (
exampleid int identity(1,1) not null
, color nvarchar(255) not null
);
insert into #example (color)
select 'black' union all
select 'green' union all
select 'purple' union all
select 'indigo' union all
select 'yellow' union all
select 'pink';
select *
from #example;
declare #max int = (select max(exampleId) from #example);
declare #min int = #max - 2
;with cte as (
select top 2 color
from #example
)
update #example
set color = a.color
from cte a
where exampleid <= #max and exampleid > #min;
select *
from #example
This script should solve the issue and will cover scenarios even if the id column is not sequential.I have included the comments to help you understand the joins and the flow of the script.
declare #test table
(
ID int not null,
Txt char(1)
)
declare #counter int = 1
/*******This variable is the top n or bottom n records in question it is 200 ,
for test purpose setting it to 20
************/
declare #delta int = 20
while(#counter <= 50)
begin
Insert into #test values(#counter * 5,CHAR(#counter+65))
set #counter = #counter + 1
end
/************Tag the records with a row id as we do not know if ID's are sequential or random ************/
Select ROW_NUMBER() over (order by ID) rownum,* into #tmp from #test
/************Logic to update the data ************/
/*Here we first do a self join on the tmp table with first 20 to last 20
then create another join to the test table based on the ID of the first 20
*/
update t
set t.ID = tid.lastID
--Select t.ID , tid.lastID
from #test t inner join
(
Select f20.rownum as first20 ,l20.rownum as last20,f20.ID as firstID, l20.ID lastID
from #tmp f20
inner join #tmp l20 on (f20.rownum + #delta) = l20.rownum
)tid on tid.firstID = t.ID and tid.first20 < = #delta
Select * from #test
drop table #tmp

SQL Server - Insert XML to every row in a column

I have 2 tables
Customer (CustomerID int, Name varchar(20), OrderHistory xml)
Order (OrderID int, CustomerID int, OrderDate date)
And I would like to insert into every row in OrderHistory column, an OrderDate of that Customer based on CustomerID.
Here is my query:
UPDATE Customer
SET OrderHistory = (SELECT OrderDate
FROM Order
WHERE CustomerID = 1
FOR XML AUTO)
WHERE CustomerID = 1
However, I have to change CustomerID for every new customer. Is there any way to insert into every customer at once ?
Applying UPDATE ... FROM ... construct to your initial SQL to make it update all customer data at once should be straightforward :
UPDATE Customer
SET OrderHistory =
(SELECT OrderDate
FROM Order o
WHERE o.CustomerID = c.CustomerID
FOR XML AUTO)
FROM Customer c
For Updating table via using Join another table use the next Approach:
UPDATE A
SET foo = B.bar
FROM TableA A
JOIN TableB B
ON A.col1 = B.colx
WHERE ...
So the update query will be as next:
UPDATE A
SET OrderHistory = B.OrderDate
FROM Customer A
JOIN Order B
ON A.CustomerID = B.CustomerID
I just figured out:
DECLARE
#count int
SET
#count = 0
UPDATE Customer
WHILE #count < (SELECT COUNT (*) FROM Customer)
BEGIN
SET OrderHistory = (SELECT
OrderDate
FROM
Order
WHERE CustomerID = #count
FOR XML AUTO)
WHERE CustomerID = #count
SET #count = #count + 1
END

MSSQL Trigger - Updating newly inserted record on INSERT

I wish to make a modification (Set Deleted = 1) to rows being inserted into my table CustomerContact if the SELECT statement returns more than 0.
I have the following, but it remains untested:
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
DECLARE #numrows INT;
/* Determine if order matches criteria for marking customer contact as DELETED immediately */
SELECT #numrows = COUNT(*)
FROM [Order] o
JOIN OrderMeterDetail om
ON o.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
AND o.orderid IN (SELECT OrderID FROM INSERTED);
/* If the order matches the criteria, mark the customer contact as deleted */
IF (#numrows >= 1)
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM INSERTED);
END
Within my IF statement, I am using FROM INSERTED, assuming that this will return the newly inserted id for the record that was created by the insert.
I have two questions about this statement:
Will this part of the statement perform an UPDATE just the record
that was just inserted into CustomerContact?
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM INSERTED);
Is this the way that would be deemed correct to make a change to a row that has just been inserted based on the result of a SELECT statement?
CustomerContactID is an auto-incrementing primary key column.
You say "Just the record that was inserted". Inserted can contain more than one record. If there is only one, then your trigger will function as you expect. But if there is more than one, it won't.
I would rewrite your logic into a single update statement along the lines of...
Update CustomerContact
Set Deleted = 1
From CustomerContact
inner join inserted on CustomerContact.CustomerContactID = inserted.CustomerContactID
inner join orders on inserted.OrderID = orders.OrderID
where
-- some criteria.
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
DECLARE #numrows INT;
/* Determine if order matches criteria for marking customer contact as DELETED immediately */
-- Get all the records into a temp table
SELECT * INTO #Temp
FROM inserted
Declare #ID int;
SELECT #numrows = COUNT(*)
FROM [Order] o
JOIN OrderMeterDetail om
ON o.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
AND o.orderid IN (SELECT OrderID FROM #Temp);
IF (#numrows >= 1)
BEGIN
WHILE EXISTS (SELECT TOP 1 * FROM #Temp)
BEGIN
SELECT TOP 1 #ID = ID FROM #Temp
/* If the order matches the criteria, mark the customer contact as deleted */
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM #Temp WHERE ID = #ID);
DELETE FROM #Temp WHERE ID = #ID
END
END
DROP TABLE #Temp
END
I think you can do something like this, tweak the code to futher suit for needs, hope this will help.
Here is the final solution that I used to solve this issue:
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
UPDATE CustomerContact
SET Deleted = 1
FROM CustomerContact cc
JOIN inserted i
ON cc.CustomerContactID = i.CustomerContactID
JOIN [Order] o
ON i.OrderID = o.OrderID
JOIN OrderMeterDetail om
ON i.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
END

SQL Server Stored Procedure (Menu System) - Microsoft SQL Server 2005

Suppose - I have the following Table Structure
elementid, parentid, elementtitle, sortorder
160 0 Brand New Tutorial 1
161 160 Brand New Tutorial New Step 1
168 5 Tutorial Topic 1.1 1
171 168 Tutorial Topic 1.1.1 1
172 171 Tutorial Topic 1.1.1.1 1
I need to be able to setup a Stored Procedure that will allow me to Update the Elementid's, Parentid's relationship.
Here is my Normal SQL For Generating the tree:
WITH menu AS
(
SELECT parentid, elementid, elementtitle, sortorder FROM dbo.ta_tutorial_elements WHERE (elementid = #eid)
UNION ALL
SELECT e.parentid, e.elementid, e.elementtitle, e.sortorderFROM dbo.ta_tutorial_elements AS e INNER JOIN menu AS m ON e.parentid = m.elementid
)
SELECT * INTO [#tmpA] FROM menu
I believe it could be possible to use temp tables to copy the table over and then somehow use the identity of the insert into my standard table to start with the elementid and the root parent...however, after that I am pretty much lost on how to recursively udpate all parentid's, elementid's with their relationships...(is it possible in SQL Server?).
I am seeing something like the following:
CREATE PROCEDURE [dbo].[sp_ta_copy_tutorial_by_id]
#eid bigint
AS
SET nocount on
BEGIN
DECLARE #recid bigint
SET #recid = (SELECT IDENT_CURRENT('ta_tutorial_elements'));
WITH menu AS
(
SELECT parentid, elementid, elementtitle, sortorder, userid, createddate FROM dbo.ta_tutorial_elements WHERE (elementid = #eid)
UNION ALL
SELECT e.parentid, e.elementid, e.elementtitle, e.sortorder, e.userid, e.createddate FROM dbo.ta_tutorial_elements AS e INNER JOIN menu AS m ON e.parentid = m.elementid
)
SELECT * INTO [#tmpA] FROM menu
ALTER TABLE [#tmpA]
DROP COLUMN elementid
SELECT * INTO [#tmpB] FROM [#tmpA];
UPDATE b SET b.parentid =
CASE
WHEN b.parentid <> 0
THEN #recid
ELSE 0
END
FROM [#tmpB] as b
INSERT INTO [ta_tutorial_elements] SELECT * FROM [#tmpB]
DROP TABLE [#tmpA]
DROP TABLE [#tmpB]
END
Check out CTEs (common table expressions). You can use a CTE within the context of a stored procedure to yield your menu data after some recursion. Actually it looks like you already have a CTE; the link describes recursion within that context.
CREATE PROCEDURE [dbo].[sp_ta_copy_tutorial_by_id]
#eid bigint
AS
SET nocount on
BEGIN
/***************************************
* CREATE A
***************************************/
SELECT *
INTO #tmpA
FROM ta_tutorial_elements
WHERE elementid IN (SELECT elementid from fn_ta_tutorial_tree_by_element (#EID))
/***************************************
* DUPLICATE RECORDS
***************************************/
DECLARE #CNT INT
SET #CNT = (SELECT max(elementid) FROM ta_tutorial_elements)
INSERT
INTO ta_tutorial_elements (elementtitle, parentid)
SELECT elementtitle, parentid FROM #tmpA
/***************************************
* CREATE B
***************************************/
SELECT *
INTO #tmpB
FROM ta_tutorial_elements
WHERE elementid > #CNT
SELECT bpid.elementid as originalelementid,
brow.elementid as newparentid
INTO #tmpC
FROM #tmpB bpid LEFT OUTER JOIN
#tmpA aeid ON bpid.parentid = aeid.elementid LEFT OUTER JOIN
(
SELECT elementid, ROW_NUMBER () OVER (ORDER BY elementid ASC) as rownum
FROM #tmpA
) arow ON arow.elementid = aeid.elementid LEFT OUTER JOIN
(
SELECT elementid, ROW_NUMBER () OVER (ORDER BY elementid ASC) as rownum
FROM #tmpB
) brow ON brow.rownum = arow.rownum LEFT OUTER JOIN
#tmpB beid ON beid.elementid = brow.elementid
UPDATE #tmpC
SET newparentid = 0
WHERE newparentid IS NULL
UPDATE t2
SET parentid = t1.newparentid
FROM #tmpC t1 LEFT OUTER JOIN
ta_tutorial_elements t2 ON t1.originalelementid = t2.elementid
/***************************************
* TEMP DISPLAY
***************************************/
SELECT * FROM ta_tutorial_elements WHERE elementid > #CNT
DROP TABLE #tmpA
DROP TABLE #tmpB
DROP TABLE #tmpC
END

Resources