Alter Trigger [dbo].[DiscountUpdate]
on [dbo].[t_PromoDtl]
Instead of insert
as
begin
Declare #Barcode nvarchar(25);
Declare #disper decimal(18,0);
Declare #status int;
Declare #BranchID nvarchar(15);
set #Barcode = (Select barcodeFull from inserted); ---/// I think error happens in here.
set #disper = (Select disPer from inserted); ---/// I think error happens in here.
set #status = (Select p.status from inserted p); ---/// I think error happens in here.
begin
if #status = 2
begin
update t_Prd
set PrdDiscnt = #disper
where BarcodeFull = #Barcode;
end
else
begin
update t_Prd
set PrdDiscnt = 0
where BarcodeFull = #Barcode;
end
end
end
Here is my C# code..
using (var sqlBulk3 = new SqlBulkCopy(_connectionString, SqlBulkCopyOptions.FireTriggers | SqlBulkCopyOptions.CheckConstraints))
{
using (SqlConnection con6 = new SqlConnection(_connectionString))
{
con6.Open();
SqlCommand cmdtt = new SqlCommand("Truncate Table t_PromoDtl", con6);
cmdtt.CommandType = CommandType.Text;
cmdtt.ExecuteNonQuery();
con6.Close();
}
sqlBulk3.DestinationTableName = "t_PromoDtl";
sqlBulk3.WriteToServer(PromoDtl);
}
When Bulk insert starts, the trigger throws this error:
Sub query returns more than one value....
I looked at this trigger which updates t_Prd table instead of insert on t_PromoDtl table.
set #Barcode = (Select barcodeFull from inserted); ---/// I think error happens in here.
set #disper = (Select disPer from inserted); ---/// I think error happens in here.
set #status = (Select p.status from inserted p); ---/// I think error happens in here.
You seem to assume that the SQL Server trigger will be fired separately for each row - this is NOT the case - the trigger is fired only once for a statement. And if this is a BULK INSERT, then the Inserted pseudo table will contain multiple rows - so your statements like
set #Barcode = (Select barcodeFull from inserted);
are in fact the source of the problem - which one of the 250 rows inserted are you selecting here? It's not determined - you'll get back one arbitrary row - and what happens to the other 249 rows also inserted?? They're just plain ignored and not handled.
You need to rewrite your entire trigger logic to be set-based and handle the fact that the Inserted pseudo table will most likely contain multiple rows.
Try something like this:
ALTER TRIGGER [dbo].[DiscountUpdate]
ON [dbo].[t_PromoDtl]
INSTEAD OF INSERT
AS
BEGIN
-- update "dbo.T_Prd.PrdDiscnt" to "disPer" when status is 2
UPDATE p
SET PrdDiscnt = i.disPer
FROM dbo.T_Prd p
INNER JOIN Inserted i ON i.BarcodeFull = p.BarcodeFull
WHERE i.Status = 2;
-- update "dbo.T_Prd.PrdDiscnt" to "0" when status is not 2
UPDATE p
SET PrdDiscnt = 0
FROM dbo.T_Prd p
INNER JOIN Inserted i ON i.BarcodeFull = p.BarcodeFull
WHERE i.Status <> 2;
I'm assuming here that BarcodeFull is your primary key column that uniquely identifies each row in your table - if that's not the case, you might need to adapt the JOIN condition to match your situation.
We have our main database on a server, there is this stored procedure; when we run it against the database, it returns wrong values.
But when I take a back up of this database and restore it on another server and run the exact same query, it returns the correct answer.
What can I do?
Is it possible that the configuration of SQL Server affects how a query returns results?
If yes where can I start looking for problem ?
Here is the stored procedure, the exact same procedure runs on both databases and both databases are identical.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[S_GheymatGozaryFIFOFroosh]
#AYear SMALLINT,
#LDate CHAR(8),
#OdCd VARCHAR(17),
#FromFirst BIT,
#SCd TINYINT
AS
DECLARE #LHId Int, #LHRadif SmallInt,
#LHFact_Date CHAR(8), #LHFact_No INT,
#LHStock_Cd TinyInt, #LQnt_Resid DECIMAL(18,4),
#LPrc_Resid DECIMAL(30,8)
DECLARE #LRId INT, #LRRadif SmallInt,
#LRFact_Date CHAR(8), #LRFact_No INT,
#LRStock_Cd TinyInt
DECLARE #Kind_Cd TINYINT, #StartDate CHAR(8)
DECLARE #Cnt INT
SET #Cnt = 0
IF #ldate IS NOT NULL AND #FromFirst = 1
BEGIN
DELETE FROM S_Fifo_Gheymat
WHERE (Acc_Year = #Ayear)
AND (#SCd = 0 OR H_Stock_Cd = #SCd)
AND (Od_Cd = #OdCd)
END
IF #SCd = 0
SET #Kind_Cd = 2
ELSE
SET #Kind_Cd = 1
SET #StartDate = Right(CAST(#AYear AS VARCHAR(4)), 2) + '/01/01'
SELECT
#LHId = H_Id,
#LHRadif = H_Radif,
#LHFact_Date = H_Fact_Date,
#LHFact_No = H_Fact_No,
#LHStock_Cd = H_Stock_Cd,
#LQnt_Resid = Qnt_Resid,
#LPrc_Resid = Prc_Resid,
#LRId = R_Id,
#LRRadif = R_Radif,
#LRFact_Date = R_Fact_Date,
#LRFact_No = R_Fact_No,
#LRStock_Cd = R_Stock_Cd
FROM
S_Fifo_Gheymat
WHERE
Acc_Year = #AYear
AND Od_Cd = #OdCd
AND (#SCd = 0 OR H_Stock_Cd = #SCd)
AND EXISTS (SELECT Id
FROM S_Dtl_Fct
WHERE Id = H_Id
AND Radif = H_Radif
AND Stock_Cd = H_Stock_Cd
AND Od_Cd = S_Fifo_Gheymat.Od_Cd)
AND EXISTS (SELECT Id
FROM S_Dtl_Fct
WHERE Id = R_Id
AND Radif = R_Radif
AND Stock_Cd = R_Stock_Cd
AND Od_Cd = S_Fifo_Gheymat.Od_Cd)
SELECT #LHId=ISNULL(#LHId,0),#LHRadif=IsNull(#LHRadif,0),#LHFact_Date=IsNull
(#LHFact_Date,#StartDate),#LHFact_No=IsNull(#LHFact_No,0),#LHStock_Cd=ISNULL
(#LHStock_Cd,0)
,#LQnt_Resid=ISNULL(#LQnt_Resid,0),#LPrc_Resid=ISNULL(#LPrc_Resid,0)
,#LRId=ISNULL(#LRId,0),#LRRadif=IsNull(#LRRadif,0),#LRFact_Date=IsNull
(#LRFact_Date,#StartDate),#LRFact_No=IsNull(#LRFact_No,0),#LRStock_Cd=ISNULL
(#LRStock_Cd,0)
---------------------------------------
IF #LDate IS NULL BEGIN
SELECT TOP 1 #LDate=Fact_Date
FROM S_Dtl_Fct D
LEFT OUTER JOIN S_Hed_Fct H ON D.Id=H.Id
LEFT OUTER JOIN dbo.S_STOCKS S ON D.Stock_Cd=S.Stock_Cd
LEFT OUTER JOIN U_Log U ON H.Id_Log=U.Id_Log AND U.Action_Cd=5
WHERE (H.Acc_Year=#AYear) AND (H.Flag=6) AND (D.Od_Cd=#OdCd) AND
(H.Tamam=0) AND (#SCd<>0 OR S.Estesna_Gp=0)
AND (
(H.Fact_Date>#LHFact_Date)
OR (H.Fact_Date=#LHFact_Date AND
H.Fact_No>#LHFact_No)
OR (H.Fact_Date=#LHFact_Date AND
H.Fact_No=#LHFact_No AND D.Radif>#LHRadif)
OR (H.Fact_Date=#LHFact_Date AND
H.Fact_No=#LHFact_No AND D.Radif=#LHRadif AND D.Stock_Cd>#LHStock_Cd)
)
AND (#SCd=0 OR D.Stock_Cd=#SCd) AND (H.VAZEIAT<>2) AND
(U.Id_Log IS NOT NULL)
ORDER BY H.Fact_Date
End
DECLARE #H TABLE ( H_Id INT,H_Radif SMALLINT,H_Fact_Date CHAR
(8),H_Fact_No INT,H_Stock_Cd TINYINT,Quantity Decimal(18,4),Un_Prc
MONEY,HTamam Bit
,R_Id INT,R_Radif SMALLINT,R_Fact_Date
CHAR(8),R_Fact_No INT,R_Stock_Cd TINYINT,Qnt_Resid Decimal(18,2),Prc_Resid
Decimal(30,8))
INSERT INTO #H
(H_Id,H_Radif,H_Fact_Date,H_Fact_No,H_Stock_Cd,Quantity,HTamam)
SELECT D.Id,D.Radif,H.Fact_Date,H.Fact_No,D.Stock_Cd,D.Quantity,H.Tamam
FROM S_Dtl_Fct D
LEFT OUTER JOIN S_Hed_Fct H ON D.Id=H.Id
LEFT OUTER JOIN dbo.S_STOCKS S ON D.Stock_Cd=S.Stock_Cd
WHERE (H.Acc_Year=#AYear) AND (H.Flag=6) AND (D.Od_Cd=#OdCd) AND
(H.Fact_Date<=#LDate) AND (#SCd<>0 OR S.Estesna_Gp=0)
AND (
(H.Fact_Date>#LHFact_Date)
OR (H.Fact_Date=#LHFact_Date AND H.Fact_No>#LHFact_No)
OR (H.Fact_Date=#LHFact_Date AND H.Fact_No=#LHFact_No
AND D.Radif>#LHRadif)
OR (H.Fact_Date=#LHFact_Date AND H.Fact_No=#LHFact_No
AND D.Radif=#LHRadif AND D.Stock_Cd>#LHStock_Cd)
)
AND (#SCd=0 OR D.Stock_Cd=#SCd) AND (H.VAZEIAT<>2)
ORDER BY H.Fact_Date,H.Fact_No,D.Radif,D.Stock_Cd
Delete S_Related_RH FROM #H H LEFT OUTER JOIN S_Related_RH R ON
H.H_Id=R.H_Id AND H.H_Radif=R.H_Radif
------------------------------------------
DECLARE #HQnt DECIMAL(18,4),#HDate CHAR(8),#SumQ DECIMAL(18,4),#SumG
MONEY,#HQntWithPrc DECIMAL(18,4)
SET #SumG=#LQnt_Resid*#LPrc_Resid
SET #SumQ=#LQnt_Resid
--
DECLARE Cr CURSOR FOR SELECT Quantity,H_Fact_Date,H_Id,H_Radif FROM #H FOR
UPDATE OF Un_Prc
Open Cr
Fetch Next From Cr InTo #HQnt,#HDate,#LHId,#LHRadif
While (##Fetch_Status=0) AND (#LRId IS NOT NULL)
Begin
IF #HQnt<=#LQnt_Resid BEGIN
SET #LQnt_Resid=#LQnt_Resid-#HQnt
UPDATE #H SET
Un_Prc=#SumG/#SumQ,R_Id=#LRId,R_Radif=#LRRadif,R_Fact_Date=#LRFact_Date,
R_Fact_No=#LRFact_No,R_Stock_Cd=#LRStock_Cd
,Qnt_Resid=#LQnt_Resid,Prc_Resid=#LPrc_Resid
WHERE CURRENT OF Cr
IF #HQnt>0 BEGIN
INSERT INTO dbo.S_Related_RH
(H_Id,H_Radif,R_Id,R_Radif,Quantity)
VALUES (#LHId,#LHRadif,#LRId,#LRRadif,#HQnt)
END
SET #SumG=#LQnt_Resid*#LPrc_Resid
SET #SumQ=#LQnt_Resid
Fetch Next From Cr InTo #HQnt,#HDate,#LHId,#LHRadif
END ELSE BEGIN
IF #LQnt_Resid>0 BEGIN
INSERT INTO dbo.S_Related_RH
(H_Id,H_Radif,R_Id,R_Radif,Quantity)
VALUES (#LHId,#LHRadif,#LRId,#LRRadif,#LQnt_Resid)
END
SET #HQnt=#HQnt-#LQnt_Resid --مقدار باقیمانده حواله
SELECT TOP 1
#LRId=D.Id,#LRRadif=D.Radif,#LRFact_Date=H.Fact_Date,#LRFact_No=H.Fact_No,
#LRStock_Cd=D.Stock_Cd,#LQnt_Resid=D.QUANTITY
,#LPrc_Resid=CASE D.QUANTITY WHEN 0
THEN 0 ELSE ( (Un_Prc*D.QUANTITY)+ISNULL(Qnt_1,0) )/ D.QUANTITY END
FROM S_Dtl_Fct D
LEFT OUTER JOIN S_Hed_Fct H ON D.Id=H.Id
LEFT OUTER JOIN dbo.S_STOCKS S ON D.Stock_Cd=S.Stock_Cd
WHERE (H.Acc_Year=#AYear) AND (H.Flag=5) AND (D.Od_Cd=#OdCd)
AND (H.Fact_Date<=#HDate) AND (H.Tamam=1) AND (#SCd<>0 OR S.Estesna_Gp=0)
AND (
(H.Fact_Date>#LRFact_Date)
OR (H.Fact_Date=#LRFact_Date AND
H.Fact_No>#LRFact_No)
OR (H.Fact_Date=#LRFact_Date AND
H.Fact_No=#LRFact_No AND D.Radif>#LRRadif)
OR (H.Fact_Date=#LRFact_Date AND
H.Fact_No=#LRFact_No AND D.Radif=#LRRadif AND D.Stock_Cd>#LRStock_Cd)
)
AND (#SCd=0 OR D.Stock_Cd=#SCd) AND (H.VAZEIAT<>2)
ORDER BY H.Fact_Date,H.Fact_No,D.Radif,D.Stock_Cd
--
IF #LRId IS NOT NULL BEGIN
IF #HQnt<=#LQnt_Resid SET #HQntWithPrc=#HQnt ELSE SET
#HQntWithPrc=#LQnt_Resid
SET #SumG=#SumG+(#HQntWithPrc*#LPrc_Resid)
SET #SumQ=#SumQ+#HQntWithPrc
End
IF ISNULL(#LQnt_Resid,0)=0 Break
End
END
Close Cr
Deallocate Cr
DECLARE #E Int
SET #E=0
BEGIN TRAN
UPDATE D SET Un_Prc=G.Un_Prc
FROM S_Dtl_Fct D
INNER JOIN #H G ON D.Id=G.H_Id AND D.Radif=G.H_Radif
WHERE (G.HTamam=0) And (G.R_Id IS NOT NULL)
SET #Cnt=##ROWCOUNT
Set #E=#E+##Error
DELETE F FROM S_Fifo_Gheymat F
WHERE (Acc_Year=#Ayear) AND (#SCd=0 OR H_Stock_Cd=#SCd) AND
(Od_Cd=#OdCd)
And EXISTS (SELECT TOP 1 Od_Cd
FROM #H
WHERE (H_Stock_Cd=F.H_Stock_Cd) AND
(Od_Cd=#OdCd) AND (R_Id IS NOT NULL)
ORDER BY H_Fact_Date DESC ,H_Fact_No
DESC ,H_Radif DESC ,H_Stock_Cd DESC)
Set #E=#E+##Error
INSERT INTO S_Fifo_Gheymat
(Acc_Year,H_Stock_Cd,OD_CD,R_Stock_Cd,H_Id,H_Fact_Date,H_Fact_No,
H_Radif,R_Id,R_Fact_Date,R_Fact_No,R_Radif,Qnt_Resid,Prc_Resid)
SELECT TOP 1
#AYear,H_Stock_Cd,#OdCd,R_Stock_Cd,H_Id,H_Fact_Date,H_Fact_No,H_Radif,
R_Id,R_Fact_Date,R_Fact_No,R_Radif,Qnt_Resid,Prc_Resid
FROM #H
WHERE R_Id IS NOT Null
ORDER BY H_Fact_Date DESC ,H_Fact_No DESC ,H_Radif DESC ,H_Stock_Cd Desc
Set #E=#E+##Error
IF #E=0 COMMIT TRAN ELSE ROLLBACK TRAN
SELECT #Cnt Cnt,#LHFact_No LHFactNo,#LHFact_Date LHFactDate,#LHStock_Cd
LHStock_Cd,#LRFact_No LRFactNo,#LRFact_Date LRFactDate,#LRStock_Cd
LRStock_Cd
Without a copy of your db (not a request) it's not possible to answer this.
Is it possible that the configuration of SQL Server affects how a
query returns results?
Yes this is a possibility. For example, if your ANSI NULL settings are different between the two servers then NULL will be equal to NULL on the server has ANSI_NULL set to on OFF but not on the server where ANSI_NULL is ON. Collation is another. If one server has a case sensitive collation the "A" and "a" are not equal whereas the opposite is true using the SQL Server default. These are just a couple examples.
That said, they way to isolate the problem is to break the stored proc up into parts and try to identify where the differences are starting. In the first steps, where you assign variables, add a step to dump them into a temp table that you can summarize and compare across both servers. If there's no differences keep moving down the proc running each part until you find a difference. Often I'll comment everything out then uncomment code from top-to-bottom until I isolate the problem.
Lastly, you are using couple cursors here and don't need to. You can simplify your code by making it more set-based and therefore less verbose. It will be much easier to troubleshoot and will perform much, much better.
I'm trying to update a column in a table which has ~90,000 rows. Is there is any optimized way to update the table?
I have added necessary indexes.. so that no table scans/lookups are not happening. But still it takes much time to run (1hr).
My scenario:
DECLARE #ParentID NVARCHAR(100),
#Con_ERID INT
DECLARE #MaxCount INT,
#MinCount INT,
#Id INT
SELECT #MaxCount = MAX(Id) from [dbo].[ParentIDStaging] where Type='grid'
SET #MinCount = 1
WHILE #MinCount <= #MaxCount
BEGIN
SELECT #Id = ConID FROM [dbo].[ParentIDStaging] WHERE Id = #MinCount and Type = 'grid'
IF #Id IS NOT NULL
BEGIN
SELECT #Con_ERID = ErId FROM Context (NOLOCK) Where ConId = #Id
SELECT #ParentID = Identifier FROM Recording (NOLOCK) where ErId = #Con_ERID
BEGIN TRAN
UPDATE [ParentIDStaging] WITH (ROWLOCK)
SET [ParentID] = #ParentID
WHERE ContentType = 'grid'
AND ConID = #Id
COMMIT
END
SET #MinCount = #MinCount + 1
END
Looping is slow. Try doing it in one update with include the relevant other tables using joins. Your query can probably be writen like this (don't know your actual schema):
UPDATE PS
SET PS.ParentID = Recording.Identifier
FROM ParetnIDStaging PS
JOIN Context on (Context.ConId = PS.ConId)
JOIN Recording on (Recording.ErId = Context.ErId)
WHERE ...
It is because you are looping and updating one record at a time and using explicit locks/transactions.
Without knowing your underlying structure - I would bet you could do what you are trying with an update from a select.
UPDATE ParentIDStaging
SET parentIdStaging.ParentID=recording.Identifier
from ParentIDStaging
join Context on context.ConId = ParentIDStaging.ConId
join recording on contect.erid=recording.erId
WHERE parentIdStaging.ContentType = 'grid'
AND parentidStaging.Type='grid'
I have the following SP for SQL Server. Strangely the SP has weired behaviour when executing the query
Select #max_backup_session_time = Max(MachineStat.BackupSessionTime) from MachineStat where MachineStat.MachineID = #machine_id;
It takes 1 second if the MachineStat table has rows pertaining to #machine_id but if there are no rows for a #machine_id then it takes more than half a minute to execute. Can someone please help me understand this.
SET NOCOUNT ON;
DECLARE #MachineStatsMId TABLE (
MachineId INT NULL,
BackupSessiontime BIGINT NULL,
MachineGroupName NVARCHAR(128) NULL )
DECLARE #machine_id AS INT;
DECLARE #Machine_group_id AS INT;
DECLARE #machine_group_name AS NVARCHAR(128);
DECLARE #max_backup_session_time AS BIGINT;
SET #machine_id = 0;
SET #Machine_group_id = 0;
SET #machine_group_name = '';
DECLARE MachinesCursor CURSOR FOR
SELECT m.MachineId,
m.MachineGroupId,
mg.MachineGroupName
FROM Machines m,
MachineGroups mg
WHERE m.MachineGroupId = mg.MachineGroupId;
OPEN MachinesCursor;
FETCH NEXT FROM MachinesCursor INTO #machine_id, #machine_group_id, #machine_group_name;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #max_backup_session_time = Max(MachineStat.BackupSessionTime)
FROM MachineStat
WHERE MachineStat.MachineID = #machine_id;
INSERT INTO #MachineStatsMId
VALUES (#machine_id,
#max_backup_session_time,
#machine_group_name);
FETCH NEXT FROM MachinesCursor INTO #machine_id, #machine_group_id, #machine_group_name;
END;
SELECT *
FROM #MachineStatsMId;
CLOSE MachinesCursor;
DEALLOCATE MachinesCursor;
GO
Here is an alternate version that avoids a cursor and table variable entirely, uses proper (modern) joins and schema prefixes, and should run a lot quicker than what you have. If it still runs slow in certain scenarios, please post the actual execution plan for that scenario as well as an actual execution plan for the fast scenario.
ALTER PROCEDURE dbo.procname
AS
BEGIN
SET NOCOUNT ON;
SELECT
m.MachineId,
BackupSessionTime = MAX(ms.BackupSessionTime),
mg.MachineGroupName
FROM dbo.Machines AS m
INNER JOIN dbo.MachineGroups AS mg
ON m.MachineGroupId = mg.MachineGroupId
INNER JOIN dbo.MachineStat AS ms -- you may want LEFT OUTER JOIN here, not sure
ON m.MachineId = ms.MachineID
GROUP BY m.MachineID, mg.MachineGroupName;
END
GO