Conditional query with a parameter stored procedure - sql

I'm learning SQL so I don't know yet all the subtlety of the language,
I wrote the following stored procedure (simplified here):
ALTER PROCEDURE [dbo].[SelectAllIssues]
#Status nvarchar(1) = 0
AS
BEGIN
SET NOCOUNT ON;
IF #Status = 1 OR #Status = 2
BEGIN
SELECT IssueStatuses.Id AS 'StatusId'
FROM Issues
INNER JOIN IssueStatuses ON Issues.IssueStatusId = IssueStatuses.Id
WHERE Issues.IssueStatusId = #Status
ORDER BY Created
END
ELSE
BEGIN
SELECT IssueStatuses.Id AS 'StatusId'
FROM Issues
INNER JOIN IssueStatuses ON Issues.IssueStatusId = IssueStatuses.Id
ORDER BY Created
END
END
But it doesn't look like a natural way to do that and there is a lot of repeated code.
I want to avoid something like
EXEC sp_executesql #sqlStrComplet
But if it's the only way.
I don't know the correct tag but sqllocaldb info MSSQLLocalDB return
Version : 13.1.4001.0
and I use SQL Server Management Studio (SSMS)

Just:
select s.Id as StatusId
from issues i
inner join IssueStatuses s on i.IssueStatusId = s.Id
where (i.IssueStatusId = #Status and #status in (1, 2)) or #status not in (1, 2)
Order By created
The where clause can be simplified:
where i.IssueStatusId = #Status or #status not in (1, 2)

Related

How can i execute a stored procedure inside another stored procedure in SQL Server?

I´m working with SQLServer and I have two storedprocedures
The first one:
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
DECLARE #FECHAFIN AS datetime;
SET #FECHAFIN = #FECHAINICIO + '23:59:59.999'
-- Insert statements for procedure here
SELECT
HC.idCorrida AS Referencia,
T.part AS Parte,
T.idTrabajo AS Trabajo,
HC.cantidadFabricado AS Piezas,
HC.cantidadRechazado AS Rechazo,
CONVERT(varchar(8), HC.tiempoProduccion) AS TiempoDeProduccion,
CONVERT(varchar(8), HC.tiempoMuerto) AS TiempoMuerto,
HC.fechaInicio AS Fecha,
U.nombreUsuario AS Usuario,
MA.nombre AS NombreMaquina,
TR.nombre AS NombreTripulacion,
TXM.idTurno AS Turno,
FROM [Produccion].[HistorialCorridas] AS HC
INNER JOIN [Produccion].[Trabajos] AS T
ON HC.idTrabajo = T.idTrabajo
INNER JOIN [Administracion].[Usuarios] AS U
ON U.idUsuario = HC.idUsuario AND U.idTripulacion = #IDTRIPULACION
INNER JOIN [Administracion].[Tripulaciones] AS TR
ON U.idTripulacion = TR.idTripulacion
WHERE HC.idTurnoXMaquina = #IDTURNOXMAQUINA
AND HC.fechaInicio >= #FECHAINICIO AND HC.fechaInicio <= #FECHAFIN
GROUP BY HC.idCorrida, T.part, T.idTrabajo, HC.cantidadFabricado, HC.cantidadRechazado,
HC.tiempoProduccion, HC.tiempoMuerto, HC.fechaInicio, U.nombreUsuario, MA.nombre, TR.nombre, TXM.idTurno
END
The second one:
BEGIN
SET NOCOUNT ON
SELECT
CONVERT(VARCHAR(8), DATEADD(SECOND,SUM(DATEDIFF(SECOND, '00:00:00', TiempoMuerto)),0),114) AS TotalTiempoMuerto,
P.etiqueta AS TipoParo
FROM [Produccion].[TiemposMuertos]
INNER JOIN [Administracion].[ParosXMaquina] AS PM
ON PM.id = idParoXMaquina
INNER JOIN [Administracion].[Paros] AS P
ON P.idParo = PM.idParo
WHERE idCorrida = #IDCORRIDA
GROUP BY P.etiqueta
END
The second one receives as a parameter a field called Referencia from the first stored procedure. What I want to do, is execute the second stored procedure from the first one, passing that parameter.
How could I achieve this? Is it possible to get the result in just one query?
Thanks in advance!!!
To call a PROCEDURE from another PROCEDURE that returns a value as output, you must use the out keyword for the output, which may be a table or other data type.
The following two procedures are defined.
In test1 procedure, the return parameter is specified with out.
In the second procedure, the first procedure is called as follows:
DECLARE #result int
EXEC test1 #result OUTPUT
CREATE PROCEDURE test1
(#outID int output)
AS
BEGIN
SET #outID = (select top 1 ID from table1)
END
CREATE PROCEDURE test2
AS
BEGIN
BEGIN
DECLARE #result int
EXEC test1 #result OUTPUT
SELECT ID from table2 where ID = #result
END;
END
GO
EXEC test2

Strange exec and sp_executesql different behavior

I have a small stored procedure (SQl Server 2012).
IF I run it using:
exec spSelRegion #bOver21 = 1
I Get different results than if I run it using:
exec sp_executesql N'spSelRegion',N'#bOver21 bit',#bOver21=1
What is the difference?
ALTER PROCEDURE [dbo].[spSelRegion]
(
#ID int = NULL
,#Name varchar(128) = NULL
,#OrderBy varchar(16) = 'ID'
,#bOver21 bit = null
)
AS
SELECT distinct
r.[ID],
r.[Name],
r.[dInserted],
r.[sInserted],
r.[dUpdated],
r.[sUpdated],
r.[timestamp]
FROM
[dbo].[tblRegion] r
left outer join tblCountyRegion cr
on r.ID = cr.RegionNbr
WHERE
(r.[ID] = #ID or #ID is null)
AND (r.[Name] = #Name or #Name is null)
AND (#bOver21 is null and r.[ID] >20
OR (#bOver21 = 1 and r.[ID] > 20 and cr.IsActive=1)
OR (#bOver21 = 0 and r.[ID] >= 21 and r.id < 31))
I don't want to make this more complecated than it is . But after a microsoft update today , some stored procedures are now runnig using sp_executesql instead of Exec and this is source of the issue.
You would need to run your dynamic SQL with the parameter specified. Without that, it assumes a null value passed. So this:
exec sp_executesql N'spSelRegion #bOver21 = #bOver21',N'#bOver21 bit',#bOver21=1

TSQL Cursor calls Stored Procedure 'View Nesting Level Exceeded'

Being a bit of a SQL Newb, I tried to create a SQL script to execute a stored procedure on a number of rows using a cursor. I found the code to create the cursor and the stored procedure works as expected.
However, sometimes during execution I get the error
Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)
Here is the SQL script in question. Any ideas why I get this error?
CREATE PROCEDURE p_MigrateRenewalOptions
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #OrderId VARCHAR(255) = NULL
DECLARE #RenewalId INT = 0
DECLARE #DiscountCode VARCHAR(255) = NULL
DECLARE #UpgradeCode VARCHAR(255) = NULL
DECLARE #ProductCode VARCHAR(255) = NULL
DECLARE rCursor CURSOR FOR
SELECT RenewalId FROM t_Renewals WHERE DiscountCode IS NOT NULL AND UpgradeCode IS NOT NULL
OPEN rCursor
FETCH NEXT FROM rCursor INTO #RenewalId
-- Iterate over t_Renewals with DiscountCode, UpgradeCode
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #OrderId = OrderId from t_Renewals where RenewalId = #RenewalId
SELECT #DiscountCode = DiscountCode from t_Renewals where RenewalId = #RenewalId
SELECT #UpgradeCode = UpgradeCode from t_Renewals where RenewalId = #RenewalId
SELECT #ProductCode = ProductCode from t_Order Where OrderId = #OrderId
-- Create renewal options for the t_Renewal entry
EXEC p_SelectOrCreateRenewalOptions #OrderId
-- Migrate the DiscountCode, UpgradeCode from the renewal record
UPDATE t_Renewal_Option
SET CouponCode = #DiscountCode
WHERE RenewalId = #RenewalId AND OptionType = 0 AND CouponCode IS NULL
UPDATE t_Renewal_Option
SET CouponCode = #UpgradeCode
WHERE RenewalId = #RenewalId AND OptionType = 1 AND CouponCode IS NULL
-- NULL the Renewal record DiscountCode, UpgradeCode
UPDATE t_Renewals
SET DiscountCode = NULL, UpgradeCode = NULL
WHERE RenewalId = #RenewalId
FETCH NEXT FROM rCursor INTO #RenewalId
END
CLOSE rCursor
DEALLOCATE rCursor
END
GO
One thing I noted, that the statement
-- Create renewal options for the t_Renewal entry
EXEC p_SelectOrCreateRenewalOptions #OrderId
returns a set, e.g. if you run this code outside of a stored procedure, inside SQL Server Management Studio, you get several sets of results in the output window. Is this the cause? Is it possible to dump the data as I don't need the returned rows from p_SelectOrCreateRenewalOptions
EDIT: As requested, here is the code for p_SelectOrCreateRenewalOptions
CREATE PROCEDURE p_SelectOrCreateRenewalOptions
(
#OrderId VARCHAR(255) = NULL
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #ProductCode VARCHAR(255);
SELECT #ProductCode = ProductCode FROM t_Order WHERE OrderId = #OrderId;
DECLARE #StaticOptionCount INT;
SET #StaticOptionCount = dbo.f_QueryRenewalOptionCount(#ProductCode);
DECLARE #OptionCount INT;
SELECT #OptionCount = COUNT(*) FROM t_Renewal_Option ro INNER JOIN t_Renewals r ON r.RenewalId = ro.RenewalId WHERE r.OrderId = #OrderId
IF (#OptionCount != #StaticOptionCount)
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT #OptionCount = COUNT(*) FROM t_Renewal_Option ro INNER JOIN t_Renewals r ON r.RenewalId = ro.RenewalId WHERE r.OrderId = #OrderId
IF (#OptionCount != #StaticOptionCount)
BEGIN
DECLARE #RenewalId INT;
SELECT #RenewalId = RenewalId FROM t_Renewals r WHERE r.OrderId = #OrderId;
DELETE FROM t_Renewal_Option WHERE RenewalId = #RenewalId;
INSERT INTO t_Renewal_Option (RenewalId, OptionProductCode, OptionType, LastUpdated)
SELECT #RenewalId, sro.OptionProductCode, sro.OptionTypeId, GETDATE()
FROM t_Static_Renewal_Option sro
WHERE sro.ProductCode = #ProductCode
END
COMMIT TRANSACTION
END
SELECT ro.* FROM t_Renewal_Option ro INNER JOIN t_Renewals r ON r.RenewalId = ro.RenewalId WHERE r.OrderId = #OrderId
END
GO
f_QueryRenewalOptionCount simply does a select:
-- f_QueryRenewalOptionCount
SELECT #Count = COUNT(*) FROM t_Static_Renewal_Option o WHERE o.ProductCode = #ProductCode
Triggers wise, I don't think we have any triggers. There is a trigger on the t_Order table on INSERT but apart from that, nothing else.
UPDATE 12-SEP-14:
This 'works' but I don't understand the problem fully. I wrapped the EXEC call into a Begin/End Transaction
Note this script is called once to migrate some old part of the schema to a new part. Its not performance intensive and just has to 'work once'
Do you have a trigger on any of your tables? If an update trigger updates its own table, it will trigger itself again, which will update the table again, etc.
Do you use view or function anywhere in your code? Views can call on other views or functions, which call other views / functions.
The cursor here, while makes my skin crawl, is likely not the cause of the error your seeing. Without being able to see what the nested stored procedure is doing, this is just an educated guess, but that's probably where the issue lies.
The error you're seeing happens whenever a recursive SQL operation basically gets stuck in an infinite loop. The two ways I have had it happen is with a poorly written recursive CTE (basically a table which infinitely unions to itself) or when, as is more likely in this case, a store procedure calls a stored procedure which calls a stored procedure... and so on down the line. For instance (and I haven't tested this) if p_selectOrCreateRenewalOptions called p_MigrateRenewalOptions, you'd probably see a similar error.

How to execute a Stored Procedure on the results of a SQL Server CTE

I have a CTE which returns DISTINCT ID's. I want to execute a scalar function on each of the Id's returned.
WITH cte (reqID) as
(SELECT DISTINCT pol.ReqID FROM
LOG_PackingListItems pli
JOIN
v_PO_LN pol on pol.PO_ID = pli.PoId
WHERE
pli.PackingListHeaderID = 1)
EXEC dbo.spUpdateLOG_ReqCompleteCheck reqID -- Error "Incorrect Syntax near EXEC"
The EXEC line is what I want to make work but I get a syntax error. Not sure if what I want to do is possible or if I do in fact have a syntax error. Any ideas?
EDIT:
I'm adding the code for the Stored Procedure since I am now using a Table-Valued Parameter as suggested by realnumber3012
EDIT:
I have changed my CTE code so it populates a Table-Type as realnumber has suggested. I now get an error when executing spUpdateLOG_ReqCompleteCheck "Subquery returns more than one value."
DECLARE #ReqIdTVP as ReqIdType;
DELETE FROM #ReqIDTVP;
with cte (reqID) as
(select distinct pol.ReqID from
LOG_PackingListItems pli
join
v_PO_LN pol on pol.PO_ID = pli.PoId
where
pli.PackingListHeaderID = #PackingListHeaderID)
INSERT INTO #ReqIdTVP
SELECT * FROM cte
EXEC dbo.spUpdateLOG_ReqCompleteCheck #ReqIdTVP
Sproc code :
Alter PROCEDURE spUpdateLOG_ReqCompleteCheck
(#ReqIdTVP ReqIdType READONLY )
AS
BEGIN
DECLARE #TotalOrd int
DECLARE #TotalRx int
DECLARE #ReqID char(8)
SET #ReqID = (SELECT ReqID FROM #ReqIdTVP)
SET #TotalOrd = (SELECT ISNULL(SUM(ORD_QTY),0)
FROM dbo.v_PoLnNonFreight l
WHERE l.ReqID = #reqID)
SET #TotalRx = (SELECT ISNULL(SUM(TotalRxSite),0)
FROM dbo.v_PoLnNonFreight l
WHERE l.ReqID = #reqID)
IF #TotalRx >= #TotalOrd
BEGIN
DECLARE #curDate datetime
SET #CurDate = ISNULL(#CurDate,GetDate())
SET NOCOUNT ON;
UPDATE LOG_ReqHeader
SET
ReqCompleteDate = #curDate,
ReqStatus = 'Complete'
WHERE ReqID = #ReqID
END
END
Seems that the only thing your stored proc does is to update a logging table: (it only changes state via this statement and doesn't return anything????
UPDATE LOG_ReqHeader
SET
ReqCompleteDate = #curDate,
ReqStatus = 'Complete'
WHERE ReqID = #ReqID
How about splitting the logic out and write a function (inline if possible that will evaluate the condition you are looking for (didn't really understand what you are doind there) -- run the function on the results of the CTE (wrapping it in another CTE if you want) with the CROSS APPLY OPERATOR.
You'd end up with a result set that looks like [ReqId], [UpdateLog] (where updateLog is a BIT)
Then simply do a set based upadete JOINING to the results:
UPDATE l SET
ReqCompleteDate = #curDate,
ReqStatus = 'Complete'
FROM
LOG_ReqHeader AS l
JOIN <CTE> AS c ON c.[ReqID] = l.[ReqID]
WHERE
c.[UpdateLog] = 0x1
Does this make any sense?

TSQL Number of reads significantly different after query and stored procedure execution

After query optimization I got results that are ok and I wanted to alter stored procedure, but got much worst results after SP execution, than it was after query execution!
Firstly, I think at number of reads. What can be reason for so different results?
Query is identical like in SP, only difference is that in query I declared parameter, but in SP that was input parameter. Value that is set to parameter is also same. To avoid 'recorded data' first I recompiled SP and after that done DROP and CREATE, but results were also much different.
Query is like this (table and column names are changed because of simplification, and number of columns is reduced):
DECLARE #Var1 varchar(20)
SET #Var1 = #Var1 + '%'
DECLARE #Var2 TIMESTAMP
SELECT #Var2 = CONVERT(TIMESTAMP, ID, 0)
FROM
X_TIMESTAMPS (NOLOCK)
WHERE
TABLE = 'T1'
declare #Var3 varbinary(8)
SELECT #Var3 = max(IdTimeStamps)
FROM
T1 (NOLOCK)
SELECT o.c1
, o.c2
, o.c3
, v.c4
, v.c5
, p.c6
, p.c7
, va.c8
, isnull(s.c9, '') AS c9
, CASE o.c10
WHEN 1 THEN
0
ELSE
1
END c10
, o.c11
FROM
T1 o (NOLOCK)
JOIN T2 p (NOLOCK)
ON o.c1 = p.c12
JOIN T3 i (NOLOCK)
ON (o.c13 = i.c14)
JOIN T4 v (NOLOCK)
ON (v.c4 = i.c15)
LEFT JOIN T5 s (NOLOCK)
ON (o.c16 = s.c17)
JOIN T6 va (NOLOCK)
ON o.c11 = va.c18
WHERE
o.c1 LIKE #Var1
AND o.c2 > #Var2
And procedure is like this:
CREATE PROCEDURE [dbo].[SP1] #Var1 varchar(20) =''
WITH RECOMPILE
AS
BEGIN
PREVIOUS QUERY WITHOUT DECLARATION FOR #Var1
END
TnX in advance!
Nemanja
It's because different execution plans are used for query with constants and sp with parameeters. You can try a few tricks
Create inline table function and try it
create function sf_test
(
#param1 int
)
returns table
as
return
your query using #in_param1
or
declare additional parameters in your procedure like this
create procedure sp_test
(
#param1 int
)
as
begin
declare #in_param1 int
select #in_param1 = #param1
your query using #in_param1
end
you can also try using option with recompile in your procedure, or use dynamic SQL
This is almost certainly a parameter sniffing issue. Personally, I liked the dummy variable option to work around this issue and (only when I run into this problem) create variable(s) that are set to the value of the incoming parameter(s).