What is wrong in this SQL Server Stored Procedure. Please Help - sql-server-2005

CREATE PROCEDURE [dbo].[SCD1] AS
-- SLOWLY CHANGING DIMENSION'S 1 (SCD1)
-- DROP PROCEDURE SCD1
-- EXEC SCD1
SET NOCOUNT ON
BEGIN
--INSERT OF NEW SOURCE VALUES INTO TEMP TABLE
SELECT SRC.* INTO #TEMP
FROM SRC_CUST SRC
LEFT OUTER JOIN DIM_CUST TGT ON SRC.CUSTOMERID = TGT.CUSTOMERID
WHERE TGT.CUSTOMERID IS NULL
--INSERT RECORDS THAT NEEDS TO BE UPDATED INTO #TEMP1 TABLE
SELECT SRC.* INTO #TEMP1
FROM SRC_CUST SRC
INNER JOIN DIM_CUST TGT ON SRC.CUSTOMERID = TGT.CUSTOMERID
WHERE (TGT.COMPANYNAME <> SRC.COMPANYNAME
OR TGT.CONTACTNAME <> SRC.CONTACTNAME
OR TGT.CONTACTTITLE <> SRC.CONTACTTITLE
OR TGT.ADDRESS <> SRC.ADDRESS
OR ISNULL(TGT.CITY,'UNK') <> SRC.CITY
OR TGT.REGION <> SRC.REGION
OR TGT.POSTALCODE <> SRC.POSTALCODE
OR TGT.COUNTRY <> SRC.COUNTRY
OR TGT.PHONE <> SRC.PHONE
OR TGT.FAX <> SRC.FAX)
--CHECK FOR THE EXISTENCE OF VALUES IN THE #TEMP TABLE
IF EXISTS(SELECT COUNT(1) FROM #TEMP)
BEGIN
--INSERT NEW RECORDS INTO THE TARGET TABLE
INSERT INTO DIM_CUST
SELECT SRC.* FROM #TEMP SRC
DROP TABLE #TEMP
PRINT 'NEW RECORDS INSERTED'
END
ELSE
DROP TABLE #TEMP
PRINT 'NO NEW RECORDS TO INSERT';
IF EXISTS(SELECT COUNT(1) FROM #TEMP1)
BEGIN
--CHECK FOR THE EXISTENCE OF VALUES IN THE #TEMP1 TABLE
-- UPDATES THE RECORDS INTO THE TARGET TABLE
UPDATE TGT
SET TGT.COMPANYNAME = SRC.COMPANYNAME
,TGT.CONTACTNAME = SRC.CONTACTNAME
,TGT.CONTACTTITLE = SRC.CONTACTTITLE
,TGT.ADDRESS = SRC.ADDRESS
,TGT.CITY = SRC.CITY
,TGT.REGION = SRC.REGION
,TGT.POSTALCODE = SRC.POSTALCODE
,TGT.COUNTRY = SRC.COUNTRY
,TGT.PHONE = SRC.PHONE
,TGT.FAX = SRC.FAX
FROM DIM_CUST TGT
INNER JOIN #TEMP1 SRC ON TGT.CUSTOMERID = SRC.CUSTOMERID
DROP TABLE #TEMP1
PRINT 'UPDATED RECORDS'
END
ELSE
DROP TABLE #TEMP1
PRINT 'NO RECORDS THERE TO UPDATE'
END
The problem that I get when execute this stored procedure is that it goes into the else part as well even though the if condition is satisfied. Can any one help me debug this stored procedure.
The source table that I have taken is the Customer table in the Northwind database.
Thanks.

There are 2 problems
You need to BEGIN/END the ELSE clauses too. Only the DROP is being excecuted in the ELSE : the PRINT *always" is which makes it run like you've reported
...
ELSE
BEGIN
DROP TABLE #TEMP
PRINT 'NO NEW RECORDS TO INSERT';
END
...
ELSE
BEGIN
DROP TABLE #TEMP1
PRINT 'NO RECORDS THERE TO UPDATE'
END
Secondly, these are always true
IF EXISTS(SELECT COUNT(1) FROM #TEMP)
...
IF EXISTS(SELECT COUNT(1) FROM #TEMP1)
All you need is.
IF EXISTS(SELECT * FROM #TEMP)
See these answers from me to explain why:
Does COUNT(*) always return a result?
What's the best to check if item exist or not: Select Count(ID)OR Exist(...)?

Related

There is already an object named '#BaseData' in the database

Below is a snippet of my code.
I am wanting to filter my data based upon a variable.
When I try to run the code, it returns an error of "There is already an object named '#BaseData' in the database.". I am not sure as to why this is the case; I have put extra checks within the IF statements to drop the temp table if it already exists but to no avail.
Are you able to help or provide an alternative solution please?
DECLARE #Variable AS VARCHAR(20) = 'Example1'
IF OBJECT_ID(N'TEMPDB..#BaseData') IS NOT NULL
DROP TABLE #BaseData
IF #Variable = 'Example1'
BEGIN
SELECT
*
INTO
#BaseData
FROM
[Database].[schema].[table]
END
IF #Variable = 'Example2'
BEGIN
SELECT
*
INTO
#BaseData
FROM
[Database].[schema].[table]
WHERE
[column] = 1
END
IF #Variable = 'Example3'
BEGIN
SELECT
*
INTO
#BaseData
FROM
[Database].[schema].[table]
WHERE
[column] = 0
END
While code is compiled by SQL, creation of same #table is found in each condition so it doesn't work.
One possible solution would be to create table and than insert data conditionally.
-- DROP TEMP TABLE IF EXISTS
IF OBJECT_ID(N'TEMPDB..#BaseData') IS NOT NULL
DROP TABLE #BaseData
GO
-- CRATE TEMP TABLE WITH TempId, AND SAME STRUCTURE AS YOUR TABLE
SELECT TOP 0 CONVERT(INT, 0)TempId, * INTO #BaseData FROM TestTable
-- DECLARE VARIABLE
DECLARE #Variable AS VARCHAR(20)= 'Example1'
-- INSERT DATA IN TABLE DEPENDING FROM CONDITION
IF (#Variable = 'Example1')
BEGIN
INSERT INTO #BaseData SELECT * FROM TestTable
END
IF (#Variable = 'Example2')
BEGIN
INSERT INTO #BaseData SELECT * FROM TestTable WHERE Id = 1
END
IF (#Variable = 'Example3')
BEGIN
INSERT INTO #BaseData SELECT * FROM TestTable WHERE Id = 2
END

Multiple conditions without using multiple if else in SQL

I have to write a program in SQL that has multiple conditions but I shouldn't write it with multiple if else (because of the cost that if has). I'm new in this field and I have no idea how else could I write it which would be better
here is my sample code:
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA= 'dbo' AND TABLE_NAME = 'Food_tbl')
BEGIN
IF NOT EXISTS (SELECT TOP 1 FID FROM dbo.Food_tbl)
BEGIN
INSERT INTO dbo.Food_tbl
SELECT *
FROM DataFoodView
END
ELSE IF (SELECT COUNT(*) FROM dbo.Food_tbl)=20
BEGIN
PRINT N'Table Exists'
SELECT *
FROM Food_tbl
END
ELSE IF (SELECT COUNT(*) FROM dbo.FoodSara_tbl)<>20
BEGIN
print N'there isnt 20'
INSERT INTO Food_tbl (Food_tbl.FID, Food_tbl.Fname, Food_tbl.Ftype, Food_tbl.Fcount, Food_tbl.Datetype, Food_tbl.Fdescription)
SELECT DataFoodView.*
FROM DataFoodView
LEFT JOIN FoodSara_tbl ON Food_tbl.FID = DataFoodView.FID
WHERE Food_tbl.FID IS NULL;
END
END
PS: I have at first check if the table is exits and if it hasn't any record insert all the data, if it has 20 records show the table, if the table doesn't have 20 records find the missing data then insert that.
First, the condition in the ELSE part isn't needed :
change
ELSE IF (SELECT COUNT(*) FROM dbo.FoodSara_tbl)<>20
BEGIN
to
ELSE
BEGIN
Next, you may regroup the two INSERT parts because having no element is also having else than 20 elements.
The result will be something like that :
IF EXISTS
(
SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA= 'dbo' AND TABLE_NAME = 'Food_tbl'
)
BEGIN
IF (SELECT COUNT(*) FROM dbo.Food_tbl)=20
BEGIN
PRINT N'Table Exists'
SELECT *
FROM Food_tbl
END
ELSE
BEGIN
print N'there isnt 20'
INSERT INTO Food_tbl (Food_tbl.FID, Food_tbl.Fname, Food_tbl.Ftype,
Food_tbl.Fcount, Food_tbl.Datetype, Food_tbl.Fdescription)
SELECT DataFoodView.*
FROM DataFoodView
LEFT JOIN FoodSara_tbl ON Food_tbl.FID = DataFoodView.FID
WHERE Food_tbl.FID IS NULL;
END
END
Not understood the exact requirement from the description what you have provided but just review the following logic
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA= 'dbo' AND TABLE_NAME = 'Food_tbl')
BEGIN
DECLARE #RCount INT
SELECT #RCount= COUNT(FID) FROM dbo.Food_tbl
IF #RCount=0
BEGIN
//Your Logic 1 (for inserting data since no records found)
END
ELSE
BEGIN
PRINT N'Table Exists'
IF #RCount=20
BEGIN
//Your Logic 2
END
ELSE
BEGIN
//Your Logic 3
END
END
END
Please explain the requirement in details or build your queries based on the requirement and add in place of Logic 1,2,3

Alternative to Iteration for INSERT SELECT UPDATE in a sequence

I have a table with around 17k unique rows for which I need to run these set of statements in sequence
INSERT INTO TABLE1 using MASTERTABLE data (MASTERTABLE have 6 column)
SELECT value of column ID (Primary Key) of newly inserted row from TABLE1
Update that ID value in TABLE2 using a Stored Procedure
I have tried:
while loop: took around 3 hours to complete the execution
cursor: cancelled the query after executing it overnight
In my understanding I can not use JOIN as I need to execute the statements in a sequence
The questions is not detailed enough. The general idea I would like to use something like this
-- create a output table to hold new id, and key columns to join later
DECLARE #OutputTbl TABLE (ID INT, key_Columns in MASTERTABLE)
INSERT INTO TABLE1
OUTPUT INSERTED.ID, MASTERTABLE.key_columns INTO #OutputTbl
SELECT *
FROM MASTERTABLE
UPDATE T2
SET ID = o.ID
FROM TABLE2 t2
INNER JOIN OutputTbl o
ON t2.key_column = o.key_column
Maybe you can consider a TRIGGER on TABLE1 from which to call the stored procedure on TABLE2, and then you can call your INSERT as you wish/need.. one by one or in blocks..
DROP TRIGGER TR_UPD_TABLE2
GO
CREATE TRIGGER TR_UPD_TABLE2 ON TABLE1 AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE #columnID INT = NULL
IF (SELECT COUNT(*) FROM INSERTED)=1 BEGIN
-- SINGLE INSERT
SET #columnID = (SELECT columnID FROM INSERTED)
EXEC TableTwoUpdateProcedure #columnID
END ELSE BEGIN
-- MASSIVE INSERT (IF NEEDED)
SET #columnID = 0
WHILE #columnID IS NOT NULL BEGIN
SET #columnID = (SELECT MIN(columnID) FROM INSERTED WHERE columnID > #columnID)
IF #columnID IS NOT NULL BEGIN
EXEC TableTwoUpdateProcedure #columnID
END
END
END
END

How to identify the operation type(insert,update,delete) in SQL Server trigger

We are using the following trigger in SQL Server to maintain the history now I need to identify the operations just like insert,update or delete. I found some information HERE but it doesn't works with the SQL Server.
CREATE TRIGGER audit_guest_details ON [PMS].[GSDTLTBL]
FOR INSERT,UPDATE,DELETE
AS
DECLARE #SRLNUB1 INT;
DECLARE #UPDFLG1 DECIMAL(3,0);
SELECT #SRLNUB1 = I.SRLNUB FROM inserted I;
SELECT #UPDFLG1 = I.UPDFLG FROM inserted I;
BEGIN
/* Here I need to identify the operation and insert the operation type in the GUEST_ADT 3rd field */
insert into dbo.GUEST_ADT values(#SRLNUB1,#UPDFLG1,?);
PRINT 'BEFORE INSERT trigger fired.'
END;
GO
But here I need to identify the operation and want to insert operation type accordingly.
Here I don't want to create three trigger for every operations
For Inserted : Rows are in inserted only.
For Updated: Rows are in inserted and deleted.
For Deleted: Rows are in deleted only.
DECLARE #event_type varchar(42)
IF EXISTS(SELECT * FROM inserted)
IF EXISTS(SELECT * FROM deleted)
SELECT #event_type = 'update'
ELSE
SELECT #event_type = 'insert'
ELSE
IF EXISTS(SELECT * FROM deleted)
SELECT #event_type = 'delete'
ELSE
--no rows affected - cannot determine event
SELECT #event_type = 'unknown'
This is a simplified version of Mikhail's answer that uses a searched CASE expression.
DECLARE #Operation varchar(7) =
CASE WHEN EXISTS(SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
THEN 'Update'
WHEN EXISTS(SELECT * FROM inserted)
THEN 'Insert'
WHEN EXISTS(SELECT * FROM deleted)
THEN 'Delete'
ELSE
NULL --Unknown
END;
Since you can get multiple rows at once we do it as follows.
INSERT INTO Log_Table
(
LogDate
,LogAction
-- your field list here
,Field0
-- Example : Tracking new and old value for a specific field
-- Make sure that the [Field1_Old] is nullable or has a default value
,Field1,Field1_Old
)
SELECT
LogDate=GETDATE()
,LogAction = CASE WHEN d.[PK_Field] IS NULL THEN 'I' ELSE 'U' END
,i.Field0
,i.Field1, d.Field1
FROM inserted i
LEFT JOIN deleted d on i.[PK_Field]=d.[PK_Field]
WHERE i.[PK_Field] IS NOT NULL
INSERT INTO Log_Table
(
LogDate
,LogAction
-- your field list here
,Field0
-- Example : Tracking new and old value for a specific field
-- Make sure that the [Field1_Old] is nullable or has a default value
,Field1,Field1_Old
)
SELECT
LogDate=GETDATE()
,LogAction = 'D'
,d.Field0
,d.Field1, NULL
FROM deleted d
LEFT JOIN inserted i on i.[PK_Field]=d.[PK_Field]
WHERE i.[PK_Field] IS NULL
create trigger my_trigger on my_table
after update , delete , insert
as
declare #inserting bit
declare #deleting bit
declare #updating bit = 0
select #inserting = coalesce (max(1),0) where exists (select 1 from inserted)
select #deleting = coalesce (max(1),0) where exists (select 1 from deleted )
select #inserting = 0
, #deleting = 0
, #updating = 1
where #inserting = 1 and #deleting = 1
print 'Inserting = ' + ltrim (#inserting)
+ ', Deleting = ' + ltrim (#deleting)
+ ', Updating = ' + ltrim (#updating)
If all three are zero, there are no rows affected and I think there is no way to tell whether it is an update/delete/insert.

SQL: Query timeout expired

I have a simple query for update table (30 columns and about 150 000 rows).
For example:
UPDATE tblSomeTable set F3 = #F3 where F1 = #F1
This query will affected about 2500 rows.
The tblSomeTable has a trigger:
ALTER TRIGGER [dbo].[trg_tblSomeTable]
ON [dbo].[tblSomeTable]
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
declare #operationType nvarchar(1)
declare #createDate datetime
declare #UpdatedColumnsMask varbinary(500) = COLUMNS_UPDATED()
-- detect operation type
if not exists(select top 1 * from inserted)
begin
-- delete
SET #operationType = 'D'
SELECT #createDate = dbo.uf_DateWithCompTimeZone(CompanyId) FROM deleted
end
else if not exists(select top 1 * from deleted)
begin
-- insert
SET #operationType = 'I'
SELECT #createDate = dbo..uf_DateWithCompTimeZone(CompanyId) FROM inserted
end
else
begin
-- update
SET #operationType = 'U'
SELECT #createDate = dbo..uf_DateWithCompTimeZone(CompanyId) FROM inserted
end
-- log data to tmp table
INSERT INTO tbl1
SELECT
#createDate,
#operationType,
#status,
#updatedColumnsMask,
d.F1,
i.F1,
d.F2,
i.F2,
d.F3,
i.F3,
d.F4,
i.F4,
d.F5,
i.F5,
...
FROM (Select 1 as temp) t
LEFT JOIN inserted i on 1=1
LEFT JOIN deleted d on 1=1
END
And if I execute the update query I have a timeout.
How can I optimize a logic to avoid timeout?
Thank you.
This query:
SELECT *
FROM (
SELECT 1 AS temp
) t
LEFT JOIN
INSERTED i
ON 1 = 1
LEFT JOIN
DELETED d
ON 1 = 1
will yield 2500 ^ 2 = 6250000 records from a cartesian product of INSERTED and DELETED (that is all possible combinations of all records in both tables), which will be inserted into tbl1.
Is that what you wanted to do?
Most probably, you want to join the tables on their PRIMARY KEY:
INSERT
INTO tbl1
SELECT #createDate,
#operationType,
#status,
#updatedColumnsMask,
d.F1,
i.F1,
d.F2,
i.F2,
d.F3,
i.F3,
d.F4,
i.F4,
d.F5,
i.F5,
...
FROM INSERTED i
FULL JOIN
DELETED d
ON i.id = d.id
This will treat update to the PK as deleting a record and inserting another, with a new PK.
Thanks Quassnoi, It's a good idea with "FULL JOIN". It is helped me.
Also I try to update table in portions (1000 items in one time) to make my code works faster because for some companyId I need to update more than 160 000 rows.
Instead of old code:
UPDATE tblSomeTable set someVal = #someVal where companyId = #companyId
I use below one:
declare #rc integer = 0
declare #parts integer = 0
declare #index integer = 0
declare #portionSize int = 1000
-- select Ids for update
declare #tempIds table (id int)
insert into #tempIds
select id from tblSomeTable where companyId = #companyId
-- calculate amount of iterations
set #rc=##rowcount
set #parts = #rc / #portionSize + 1
-- update table in portions
WHILE (#parts > #index)
begin
UPDATE TOP (#portionSize) t
SET someVal = #someVal
FROM tblSomeTable t
JOIN #tempIds t1 on t1.id = t.id
WHERE companyId = #companyId
delete top (#portionSize) from #tempIds
set #index += 1
end
What do you think about this? Does it make sense? If yes, how to choose correct portion size?
Or simple update also good solution? I just want to avoid locks in the future.
Thanks