Right way to subtract in a stored procedure - sql

I have the following query in my stored procedure
DECLARE #I INT
DECLARE #TenPercent int
DECLARE #RowsCount int
SET #TenPercent =10
SET #I = 1
SELECT
#I, dbo.tblVegetationType.VegTypeCode, dbo.tblVegetationType.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegTypeVegFormationLink ON dbo.tblVegetationType.VegTypeID = dbo.tblVegTypeVegFormationLink.VegTypeID
INNER JOIN
tblCMAVegTypeLink ON dbo.tblVegetationType.VegTypeID = dbo.tblCMAVegTypeLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >= (#PercentCleared - #TenPercent)
AND dbo.tblVegTypeVegFormationLink.VegetationFormationID = #VegetationFormationID
AND dbo.tblCMAVegTypeLink.CMAID = #CMAID
I have following condition
dbo.tblVegetationType.PercentageCleared >= (#PercentCleared - #TenPercent)
What I am trying to do here: if PercentCleared is 60% then I want to query to pick the list from 50 %.
So I just add the SET #TenPercent = 10 and subtract from the condition.
Is that a right way to do?

Another way of writing the query can be:
SELECT #I,
VT.VegTypeCode,
VT.VegTypeName
FROM dbo.tblVegetationType VT
INNER JOIN dbo.tblVegTypeVegFormationLink VTVF
ON VT.VegTypeID = VTVF.VegTypeID
INNER JOIN tblCMAVegTypeLink CVT
ON VT.VegTypeID = CVT.VegTypeID
WHERE 1= case when #PercentCleared >= 60 and VT.PercentageCleared <= 50 then 1
-- you can add condition when #PercentCleared < 60 then what values of
-- VT.PercentageCleared are to be considered
when #PercentCleared < 60 and VT.PercentageCleared <= 50 then 1
end
AND VTVF.VegetationFormationID = #VegetationFormationID
AND CVT.CMAID = #CMAID

Related

Stored procedure sometimes takes a long time to execute query in SQL Server

I have strange issue and I am getting more confused about this. I am using UWP on the .NET framework and using SQL Server as database. The problem is my application working too much slow and when I check my stored procedure execution time then I am notice that may be a problem is from the database stored procedure side.
My stored procedure sometimes takes 4-5 seconds to execute and sometimes takes more like 15-16 seconds and sometimes it takes more than 1 minute.
My questions are:
Why is it taking a lot more time sometimes, but not every time?
How can I solve this issue and boost my application execution time?
This is the stored procedure:
ALTER PROCEDURE [dbo].[SPNAME]
#HouseID INT,
#FromDate DATETIME,
#ToDate DATETIME,
#PageNumber INT,
#PageSize INT,
#RollID INT
AS
BEGIN
DECLARE #RoomID INT = 0
DECLARE #UnitID INT = 0
DECLARE #HouseCode INT = 0
DECLARE #StartRow INT
DECLARE #EndRow INT
SET #StartRow = #PageNumber
SET #StartRow = ((#StartRow-1) * #PageSize) + 1
SET #EndRow = (#StartRow + #PageSize) - 1;
IF OBJECT_ID('tempdb.dbo.#TableName') IS NOT NULL
DROP TABLE dbo.#TableName
SELECT
#HouseCode = [HouseCode],
#UnitID = UnitId
FROM
[dbo].[tblHouse]
WHERE
[HouseId] = #HouseID
SELECT #RoomID = RoomCode
FROM [dbo].[tblUnit] u
LEFT JOIN tblRoom h ON u.RoomID = h.Room
WHERE UnitID = #UnitID
SELECT MAX(RoNum) RoNum
INTO dbo.#tableName
FROM [dbo].[TAbleNAme]
WHERE FanId = #HouseCode
AND InActive = 0
AND ((InactivatedOn IS NULL AND StopDate IS NULL)
OR (ISNULL(InactivatedOn, StopDate) BETWEEN #FromDate AND #ToDate)
OR (ISNULL(InactivatedOn,StopDate) >= #ToDate))
AND (FirstFillDate <= #ToDate)
GROUP BY
OrigRoNum
SELECT
K.Topic, K.Comment, K.RoNum
INTO
#TmptblRoCom
FROM
[dbo].[TableNAme] K
LEFT JOIN
#TableName T ON K.RoNum = T.RoNum
WHERE
K.Topic = 'Nar Auto'
AND ISNUMERIC(SUBSTRING(K.Comment, 0, 3)) = 1
SELECT ButtonTypeID, ISNULL(SortOrder, 17) AS SortOrder
INTO dbo.#TableName
FROM [dbo].[TAbleName]
WHERE NHID = #RoomID AND NHSortID = 29
SELECT
DIN,
'LU: ' + LTRIM(RTRIM(ReasonCode)) +
'Exp:' + ISNULL(FORMAT(ExpiryDate, 'dd/MM/yyyy'), 'Indefinite') AS HLCode
INTO
dbo.#TableName
FROM
[dbo].[TableNAme]
WHERE
PatID = #HouseCode
AND (ExpiryDate IS NULL OR ExpiryDate > GETDATE())
SELECT
X.DgID AS DumbID,
X.ID AS RID,
CASE
WHEN DR.BandName IS NULL
THEN '#' + dm.Description
ELSE CONCAT(BandName, ' ', strength)
END AS DugName,
StrengthType, FormType,
CASE
WHEN GericName IS NULL
THEN
CASE
WHEN BandName IS NULL
THEN '#' + dm.Description
ELSE CONCAT(DR.BandName, ' ', DR.strength)
END
ELSE CONCAT(DR.GericName, ' ', DR.strengthTypr)
END AS GericName,
DR.[Description],
dbo.GetDirectionWithFullForm (X.IG,' ') AS Direction,
CAST(X.RoNum AS BIGINT) AS RoNum,
FORMAT(X.FirstFillDate,'dd/MM/yyyy') AS FirstFillDate,
FORMAT(X.LastFillDate,'dd/MM/yyyy') AS DugOrderDate,
ISNULL(TP.[ID],0) AS RollID,
TP.[Cont] AS Cont,
TP.[DisContinue] AS Disc,
TP.[Hold] AS Hold,
CAST(m.OrderType AS INT) AS OrderType,
pl.HLCode,
rc.Comment,
TP.[Comments]
FROM
dbo.#TAbleNAme rn
INNER JOIN
[dbo].[RollRx] X ON rn.RoNum = X.RoNum
INNER JOIN
[dbo].[RollDg] DR ON X.[DgID] = DR.ID
LEFT JOIN
[dbo].[RollDgMix] DM ON X.MixID = DM.ID
LEFT JOIN
[dbo].[RollPreviousNumber] TP ON X.DrgID = TP.[RollMedicationID]
AND X.[ID] = TP.[RoID]
AND TP.[HouseID] = #HouseID
AND TP.[TableName] = #RollID
LEFT JOIN
dbo.#TableNAme m ON m.TypeID = X.TypeID
LEFT JOIN
dbo.#TableName pl ON pl.DNNUM = X.DNNUM
LEFT JOIN
dbo.#TableName rc ON rc.RoNum = X.RoNum
END
Execution Plan
Yes sounds like parameter sniffing or lack of memory issue (this has made it block for me at times when I am running to much on my box), look at the execution plan.
Run the stored proc with your parameters and see if there is a difference here, by right clicking on the execution plan select, below shows an example.

Need to arrange a record using while loop

While fetching details using while loop I am not able to get it as I want. What I want is to apply a loop and get details of each date. I am using SQL 2008.
Set #i = 1;
While (#NoOfDays >= #i)
Begin
SET #ManufactureQty = (Select isnull(SUM(Quantity),0) as Manufactured from IGN1 inner join OIGN on (OIGN.DocEntry = IGN1.DocEntry)
inner join OITM on (OITM.ItemCode = IGN1.ItemCode)
where Convert(Date,Cast(OIGN.DocDate as DATE)) = Convert(Date,DATEADD(d, #i, #date)) and OITM.ItmsGrpCod = #ItemGroup)
Select #i as D,OpeningBalance = case
when #i > 1 then ((isnull(SUM(OINM.InQty),0)-isnull(SUM(OINM.OutQty),0)) + ((isnull(SUM(OINM.InQty),0)-isnull(SUM(OINM.OutQty),0))))
when #i = 1 then (isnull(SUM(OINM.InQty),0)-isnull(SUM(OINM.OutQty),0))
end
,
isnull(#ManufactureQty,0) as Manufacture
From OITM
Inner Join OINM On (OINM.ItemCode = OITM.ItemCode and Convert(Date,Cast(OINM.DocDate as DATE)) = Convert(Date,DATEADD(d, #i, #date))) --and Convert(Date,Cast(OINM.DocDate as DATE)) > Convert(Date,'2014-05-01'))
Where OITM.ItmsGrpCod = #ItemGroup group by OINM.DocDate
SET #i = #i + 1
End
It Gives
D OpeningBalance Manufacture
1 123 23
D OpeningBalance Manufacture
2 143 773
D OpeningBalance Manufacture
3 126 27
.
But I need it like
D OpeningBalance Manufacture
1 123 23
2 143 773
3 126 27
.
Before loop:
create table #results (D int, OpeningBalance Int, Manufacture Int)
in loop
begin
insert into #results ...
select ...
end
--after
select * from #results

Any other way to avoid if else condition

I have a following stored procedure. I have variable #PercentCleared .
IF #PercentCleared <= 70 then I have to subtract PercentCleared-10 else use as it is. Can you please advise me the right way to do?
DECLARE #PercentCleared INT
DECLARE #TenPercent int
SET #TenPercent = 10
IF(#PercentCleared <=70)
BEGIN
SELECT
#I, dbo.tblV.VegTypeCode, dbo.tblV.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegFormationLink ON dbo.tblV.VegTypeID = dbo.tblVegFormationLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >=(#PercentCleared - #TenPercent)
WHERE
a.VegTypeID = dbo.tblVegetationType.VegTypeID
AND dbo.tblVegetationType.VegTypeID <> (SELECT VegTypeID
FROM #EcosystemCredits eco
WHERE eco.theID = #I)
END
ELSE IF
BEGIN
SELECT
#I, dbo.tblV.VegTypeCode, dbo.tblV.VegTypeName
FROM
dbo.tblVegetationType
INNER JOIN
dbo.tblVegFormationLink ON dbo.tblV.VegTypeID = dbo.tblVegFormationLink.VegTypeID
WHERE
dbo.tblVegetationType.PercentageCleared >=#PercentCleared
WHERE
a.VegTypeID = dbo.tblVegetationType.VegTypeID
AND dbo.tblVegetationType.VegTypeID <> (SELECT VegTypeID
FROM #EcosystemCredits eco WHERE eco.theID = #I)
End
I think you can do this by using a CASE statement in the WHERE clause
SELECT #I, dbo.tblV.VegTypeCode, dbo.tblV.VegTypeName FROM dbo.tblVegetationType
INNER JOIN dbo.tblVegFormationLink
ON dbo.tblV.VegTypeID = dbo.tblVegFormationLink.VegTypeID
WHERE dbo.tblVegetationType.PercentageCleared
>= #PercentCleared
- CASE WHEN (#PercentCleared <=70) THEN #TenPercent ELSE 0 END -- change here
WHERE a.VegTypeID = dbo.tblVegetationType.VegTypeID
AND dbo.tblVegetationType.VegTypeID
<> (SELECT VegTypeID FROM #EcosystemCredits eco WHERE eco.theID = #I)
You can put the logic in the where clause.
SELECT #I, dbo.tblV.VegTypeCode, vt.VegTypeName
FROM dbo.tblVegetationType vt INNER JOIN
dbo.tblVegFormationLink vfl
ON vt.VegTypeID = vlt.VegTypeID
WHERE (vt.PercentageCleared >= #PercentCleared - (CASE WHEN #PercentCleared <= 70 THEN #TenPercent ELSE 0 END)) AND
(vt.VegTypeID <> (SELECT VegTypeID FROM #EcosystemCredits eco WHERE eco.theID = #I) );
I simplified the query by using table aliases. Also, you had two where clauses and the second was redundant.
You can achieve this without a CASE or IF statement by re-writing your SQL like this...
WHERE
(#PercentCleared <=70 AND dbo.tblVegetationType.PercentageCleared >=(#PercentCleared - #TenPercent))
OR
(#PercentCleared > 70 AND dbo.tblVegetationType.PercentageCleared >= #PercentCleared)
Hope it helps not only in this situation but many similar situtations.

Updating table based on the interval from another. SQL Server

I need to count how many men was working each hour. I have two tables:
Hour Men
------------
6 0
7 0
8 0
9 0
10 0
11 0
12 0
where "Men" column is the count of men. Another table is:
ClockedInHour ClockedOutHour
6 10
7 10
8 12
6 11
9 12
So for every entry in the second table, I need to increment "Men" column in the first table for every hour between "ClockedInHour" and "ClockedOutHour" including those in the table, and, if possible, to do it without cursor.
Additional condition: it will be a part of the table-valued function.
Thanks in advance for your help.
Solved!
DECLARE #Hour6 INT
SET #Hour6 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 6 and ClockedInHour <= 6)
DECLARE #Hour7 INT
SET #Hour7 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 7 and ClockedInHour <= 7)
DECLARE #Hour8 INT
SET #Hour8 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 8 and ClockedInHour <= 8)
DECLARE #Hour9 INT
SET #Hour9 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 9 and ClockedInHour <= 9)
DECLARE #Hour10 INT
SET #Hour10 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 10 and ClockedInHour <= 10)
DECLARE #Hour11 INT
SET #Hour11 = (SELECT COUNT(*) FROM #table2 where ClockedOutHour >= 11 and ClockedInHour <= 11)
DECLARE #Hour12 INT
SET #Hour12 = (SELECT COUNT(*) FROM #tc where ClockedOutHour >= 12 and ClockedInHour <= 12)
UPDATE #table1 SET Man = #Hour6 WHERE Hour = 6
UPDATE #table1 SET Man = #Hour7 WHERE Hour = 7
UPDATE #table1 SET Man = #Hour8 WHERE Hour = 8
UPDATE #table1 SET Man = #Hour9 WHERE Hour = 9
UPDATE #table1 SET Man = #Hour10 WHERE Hour = 10
UPDATE #table1 SET Man = #Hour11 WHERE Hour = 11
UPDATE #table1 SET Man = #Hour12 WHERE Hour = 12
You can do this using a Insert Trigger as:
Go --terminate all preceding batch of statements
CREATE TRIGGER tg_MenCount ON dbo.table2 For INSERT
AS
SET XACT_ABORT, NOCOUNT ON
--Ignore zero row updates, inserts
IF NOT EXISTS (SELECT * FROM INSERTED) RETURN;
BEGIN TRY
UPDATE T1
set T1.men = T1.men +1
FROM
table1 T1
INNER JOIN INSERTED I
ON T1.hour between I.ClockedInHour and I.ClockedOutHour
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK TRANSACTION
--RAISERROR [rethrow caught error using #ErrorNumber, #ErrorMessage, etc]
END CATCH
GO

NULL value returned when using SUM function on two columns while populating table in SQL Server 2008

INSERT INTO table is producing a NULL value for the returned recordset. I'm trying to add the SUM(m.earnings + m.fpearn) from pfinancial table and userid & minpay from the userbase table.
What am I doing wrong? Also is there a better way to reiterate through the temp table of id's ?
From the tables below I should populate the publsher_monthly table with one unique id per userid, the minpay amount from the userbase and the sum of the m.earnings + m.fpearn columns from the pfinancial table
publisher_monthly table
pmuseris pmminpay pmearnings
5 20 75
6 30 27
userbase table
userid minpay
5 20
6 30
pfinancial table
userid earnings fpearn
5 10 30
5 20 15
6 15 12
My query:
DECLARE #realuserid bigint
CREATE TABLE #tmppmuserids(
idx bigint Primary Key IDENTITY(1,1),
tmppmuserid bigint NULL
)
INSERT INTO #tmppmuserids
SELECT DISTINCT userid FROM pfinancial
DECLARE #i bigint
DECLARE #numrows bigint
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #tmppmuserids)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #tmppmuserids))
BEGIN
SET #realuserid = (SELECT tmppmuserid FROM #tmppmuserids WHERE idx = #i)
--PROBLEM HERE
INSERT INTO publisher_monthly (pmearnings, pmuserid, pmminpay)
SELECT
SUM(m.earnings + m.fpearn), MAX(#realuserid), MAX(u.minpay)
FROM pfinancial m
INNER JOIN userbase u on u.userid = m.userid
WHERE
m.userid = #realuserid AND
(m.created >= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()),0)) AND
(m.created < DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE()) + 1, 0))
--END PROBLEM
SET #i = #i + 1
END
SELECT * FROM #tmppmuserids
SELECT * FROM publisher_monthly
DROP TABLE #tmppmuserids
Place an IsNull around them:
SELECT SUM(IsNull(m.earnings, 0) + IsNull(m.fpearn, 0))
or even around the whole thing:
SELECT IsNull(SUM(m.earnings + m.fpearn), 0)