One stored procedure calls another - however getting a table error - mysql

I am trying to call one stored procedure withing another - using an if statement.
I am getting an error so I believe that I have something out of sequence
CREATE PROCEDURE reportFreeCoolingTrackerCalls (
IN fromDate varchar (50),
IN toDate varchar (50),
IN timeZone varchar (50))
BEGIN
DECLARE startDate varchar (50);
DECLARE endDate varchar (50);
DECLARE mylogID Int;
SET startDate = FROM_UNIXTIME(fromDate/1000);
SET endDate = FROM_UNIXTIME(toDate/1000);
IF (l1.activityId = t2.activityId)
THEN CALL reportFreeCoolingTrackerError (
fromDate,
toDate,
timeZone );
ELSEIF (l1.activityId != t2.activityId)
THEN CALL reportFreeCoolingTracker (
fromDate,
toDate,
timeZone );
END IF;
SELECT l1.activityId,t2.activityId
FROM logs l
INNER JOIN groups g ON g.groupId = l.groupId
LEFT JOIN groups g1 ON g.parentId = g1.groupId
LEFT JOIN groups g2 ON g1.parentId = g2.groupId
LEFT JOIN groups g3 ON g2.parentId = g3.groupId
INNER JOIN activities a ON l.logId = a.logId
INNER JOIN log1644 l1 ON a.activityId = l1.activityId
INNER JOIN log1644 t2 ON t2.recordId = l1.recordid + 1
INNER JOIN items i ON l.logId = i.logId AND i.name LIKE '%KW%'
INNER JOIN users u ON l1.userId = u.userId AND i.name LIKE '%KW%'
WHERE i.itemID = "31985" AND l1.activityId = 1257
AND l1.started
BETWEEN startDate
AND endDate
ORDER BY l1.recordId,l1.started;
END //
DELIMITER ;
ERROR
Unknown table 'l1' in field list

I think this code is causing the trouble for you:
IF (l1.activityId = t2.activityId) --Here l1 and t2 are not known
THEN CALL reportFreeCoolingTrackerError (
fromDate,
toDate,
timeZone );
ELSEIF (l1.activityId != t2.activityId) --Here l1 and t2 are not known
THEN CALL reportFreeCoolingTracker (
fromDate,
toDate,
timeZone );
END IF;
as in this line l1 is not known. Similarly t2 is also not known

Table aliases (such as INNER JOIN log1644 l1 ON... are only visible in the statement (in your case a SELECT) that contains them.
You'll need to refer to the full table name outside of that select.
As for the logic.... you'll need to populate the values you need in the SP call by using a select, and populating them into variables. Alternatively, use a select subquery in the call itself, but that would be a maintenance headache!

Related

Comparing primary Id of the same row in same table

Can't find the same questions as mine I'm hoping you guys can help me.
I have this query for my SP what I need to do is check if the company Id is the same based on the parameter given by the user.
I have two parameters which are paramOrgA and paramOrgB which will be supplied by the user.
What I did was repeat the same query and set the returned value in two variables which is
orgAId and orgBId then use the IF statement to compare the value.
is there another way to accomplish this or should I say optimized way to do this?
Below is the query I wrote.
BEGIN
declare orgAId int;
declare orgBId int;
declare orgStatus bool;
SET orgAId = (SELECT c.Id
FROM Members as `m`
INNER JOIN Company as `c`
ON m.CompanyId = c.Id
WHERE m.Id = paramOrgA);
SET orgBId = (SELECT c.Id
FROM Members as `m`
INNER JOIN Company as `c`
ON m.CompanyId = c.Id
WHERE m.Id = paramOrgB);
IF (orgAId = orgBId) THEN
set orgStatus = true;
ELSE
set orgStatus = false;
END IF;
select orgStatus as 'CompanyStatus';
END IF;
END
One query will do
SELECT count(distinct c.Id) > 1 as 'CompanyStatus'
FROM Members as `m`
INNER JOIN Company as `c` ON m.CompanyId = c.Id
WHERE m.Id IN (paramOrgA, paramOrgB)
Even fewer keystrokes:
SELECT COUNT(DISTINCT CompanyId) > 1 as 'CompanyStatus'
FROM Members
WHERE Id IN (paramOrgA, paramOrgB)

How can I update a column value of a table in DB1 with a column value from a table in DB2?

I'm trying to perform a simple update in SQL between 2 tables from different DB's. The challenge is that in order for the value to be updated it must meet certain conditions. I have used the join statements to meet the conditions and when I go to test the value from table B it is not being updated into table A. Here is what I've done so far.
USE [dbo]
GO
CREATE PROCEDURE
(
#User_ID = INT,
#Batch_ID VARCHAR(32)
)
DECLARE #locid int
SELECT #locid
FROM OtherDB.dbo.User AS UL
WHERE UL.User_ID = #User_Id
and User_Type = 1;
UPDATE M
SET
M.Number = W.Number
FROM dbo.tableA AS W
JOIN dbo.tableB AS B ON B.ID = W.ID
JOIN dbo.tableC AS C ON C.ToolA = B.ToolA
JOIN dbo.tableD as D ON D.Zone = W.Zone_Name
JOIN OtherDB.dbo.tableMax AS M ON M.LID = #locid
AND M.Tool = C.Other_Tool
AND M.Zone = D._Other_Zone
AND M.Station = W.Station
WHERE W.User_ID = #User_ID
AND W.Batch_ID = #Batch_ID
SET NOCOUNT OFF;
The update statement is updating table M in otherDB, not table A on the current database.
You might revise the stored procedure to be
Update A
Set A.Number = W.Number
From dbo.tableA A
....

SQL left join is not including all records from left table

I have a requirement to get monthly total hours worked on different tasks for each employee. For that purpose I am writing a stored procedure. But left join is not populating all record from employee table.
I know somehow the where condition is filtering out the null values but I really don't know how to overcome this problem.
ALTER PROCEDURE [dbo].[GetEmployeeWorkHours]
#PageSize smallint = 10,
#CurrentPage smallint = 1,
#EmployeeId varchar(1000) = null,
#StartDate datetime = null,
#EndDate datetime = null
AS
BEGIN
if(#StartDate is null)
select #StartDate = DATEADD(month, DATEDIFF(month, 0, getDate()), 0)
if(#EndDate is null)
select #EndDate = getDate()
select e.Id,
e.FirstName + ' ' + e.LastName as [Name],
sum([Minutes]/60.0) as [WorkedHours]
from Employees e
left join TaskResources tr on (e.Id = tr.EmployeeId)
inner join ResourceTaskSchedules rts on (tr.Id = rts.TaskResourceId)
inner join TaskTimeSheets tts on (rts.Id = tts.ResourceTaskScheduleId)
where
((#EmployeeId is null) or (e.Id in (select splitdata from dbo.SplitEmployeeIds(#EmployeeId, ',')))) and
cast(tts.CheckIn as date) >= #StartDate
and cast(tts.CheckIn as date) <= #EndDate
group by
e.Id
ORDER BY
e.Id
OFFSET (#CurrentPage-1)*#PageSize ROWS
FETCH NEXT #PageSize ROWS ONLY;
END
Once you use left join in a from clause, you normally continue with left join. This is critical if the second table is used for any conditions.
Then, any filtering conditions on any of the left join'ed tables need to be in the on clauses, not the where clause. So:
from Employees e left join
TaskResources tr
on e.Id = tr.EmployeeId left join
ResourceTaskSchedules rts
on tr.Id = rts.TaskResourceId left join
TaskTimeSheets tts
on rts.Id = tts.ResourceTaskScheduleId and
cast(tts.CheckIn as date) >= #StartDate and
cast(tts.CheckIn as date) <= #EndDate
where ((#EmployeeId is null) or
(e.Id in (select splitdata from dbo.SplitEmployeeIds(#EmployeeId, ','))))

MSSQL stored procedure - Timeout expired

We have a Web Api service for report building. This service uses MS SQL 2008 database as a data source. The data base works as a mirror in readonly mode.
The service and the database are hosted on different computers of a single local net.
There is a stored procedure in the database named TicketSaleByAggregator, that selects report data. Sometimes the procedure throws following exception:
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
Then the procedure is throwing this exception again and again until we recompile it:: ALTER PROCEDURE [dbo] [TicketSaleByAggregator].
After the command ALTER PROCEDURE, the procedure runs perfectly even on big data sets, but after about 10-15 hours the error throws again: Timeout expired
The procedure parameters:
DECLARE #PeriodFrom DATETIME = '2016-12-30 00:00:00'
DECLARE #PeriodTo DATETIME = '2016-12-30 23:59:59'
DECLARE #Dealers Identities
DECLARE #Branches Identities
DECLARE #SaleChannels Identities
DECLARE #Carriers Identities
INSERT INTO #Dealers (Id) VALUES(10068)
INSERT INTO #Branches(Id) VALUES(1),(2),(3)
INSERT INTO #SaleChannels(Id)VALUES (7)
exec TicketSaleByAggregator #PeriodFrom, #PeriodTo, #Dealers, #Branches, #SaleChannels, #Carriers
If we call the procedure locally (on the machine where it is hosted) in SQL Management Studio, then it executes for 15 seconds
If we call the procedure on the machine where the web api service is hosted, in SQL Management Studio, then it executes for 15-16 seconds
.The Result data contains 82540 records
Code of stored procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[TicketSaleByAggregator]
(
#PeriodFrom DATETIME,
#PeriodTo DATETIME,
#Dealers Identities READONLY,
#Branches Identities READONLY,
#SaleChannels Identities READONLY,
#Carriers Identities READONLY
)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON
;WITH ParentDealer(childId, parentId, BIN)
AS(
SELECT d.Id,
parentDealer.pId,
parentDealer.BIN
FROM Dealer AS d
JOIN (
SELECT d.Id,
parentDealer.Id pId,
parentDealer.BIN
FROM Dealer d
JOIN Dealer parentDealer
ON parentDealer.Hid = d.Hid.GetAncestor(d.[Hid].[GetLevel]() -1)
) parentDealer
ON d.Id = parentDealer.Id
),
CarrierNames
AS(
SELECT c.Name AS CarrierName
FROM Carrier AS c
INNER JOIN #Carriers crs ON c.Id = crs.Id
),
Result
AS(
SELECT *
FROM
(
SELECT t.[ExpressId] AS TicketExpressId,
o.[OrderCreateDate] AS OperationDate,
1 AS TicketCount,
t.[Tariff] AS Tariff,
6 AS OperationTypeId,
sc.Name AS SalesChannelName,
b.ShortName AS BranchName,
o.CarrierName,
o.PaymentType AS PaymentType,
--financial dealers
uDealer.Surname AS FinancialDealerSurname,
uDealer.Name AS FinancialDealerName,
uDealer.Middlename AS FinancialDealerPatronymic,
d.BIN AS FinancialDealerBin,
uparentDealer.Surname AS FinancialParentDealerSurname,
uparentDealer.Name AS FinancialParentDealerName,
uparentDealer.Middlename AS FinancialParentDealerPatronymic,
parentDealer.BIN AS FinancialParentDealerBin,
--place dealers
uDealer.Surname AS PlaceDealerSurname,
uDealer.Name AS PlaceDealerName,
uDealer.Middlename AS PlaceDealerPatronymic,
d.BIN AS PlaceDealerBin,
uparentDealer.Surname AS PlaceParentDealerSurname,
uparentDealer.Name AS PlaceParentDealerName,
uparentDealer.Middlename AS PlaceParentDealerPatronymic,
parentDealer.BIN AS PlaceParentDealerBin
FROM Ticket AS t
INNER JOIN [Order] AS o ON o.Id = t.OrderId AND o.OrderCreateDate BETWEEN #PeriodFrom AND #PeriodTo
INNER JOIN [Terminal] AS ter ON t.[TerminalId] = ter.[Id]
LEFT JOIN [TerminalData] AS td ON ter.[Id] = td.[Id]
INNER JOIN [SalePoint] AS sp ON td.[SalePointId] = sp.[Id]
INNER JOIN FinAccStation AS fas ON fas.Id = sp.FinAccStationId
INNER JOIN Guo AS g ON g.Id = fas.GuoId
INNER JOIN Department AS dep ON dep.Id = g.DepartmentId
INNER JOIN Dealer AS d ON d.Id = ter.DealerId
INNER JOIN [User] AS uDealer ON uDealer.Id = d.Id
INNER JOIN SalesChannel AS sc ON sc.Id = d.SalesChannelId AND (EXISTS(SELECT * FROM #SaleChannels) AND (d.SalesChannelId IN (SELECT * FROM #saleChannels)) OR NOT EXISTS(SELECT * FROM #saleChannels))
INNER JOIN Branch AS b ON b.Id = dep.BranchId AND (EXISTS(SELECT * FROM #Branches) AND (b.Id IN (SELECT * FROM #Branches)))
INNER JOIN ParentDealer AS parentDealer ON parentDealer.childId = d.Id AND (parentDealer.parentId IN (SELECT Id FROM #Dealers) OR NOT EXISTS(SELECT * FROM #Dealers))
INNER JOIN [User] AS uParentDealer ON uParentDealer.Id = parentDealer.parentId
WHERE t.TicketStatusId IN (3, 6) AND
((EXISTS(SELECT TOP 1 * FROM #Carriers) AND (o.CarrierName IN (SELECT CarrierName FROM CarrierNames))) OR NOT EXISTS(SELECT TOP 1 * FROM #Carriers))
UNION ALL
SELECT t.[ExpressId] AS TicketExpressId,
c.OperationDate AS OperationDate,
-1 AS TicketCount,
(-1)*ct.RetTariff AS Tariff,
3 AS OperationTypeId,
sc.Name AS SalesChannelName,
b.ShortName AS BranchName,
o.CarrierName,
c.PaymentType AS PaymentType,
--financial dealers
uDealer.Surname AS DealerSurname,
uDealer.Name AS DealerName,
uDealer.Middlename AS DealerPatronymic,
d.BIN AS DealerBin,
uparentDealer.Surname AS ParentDealerSurname,
uparentDealer.Name AS ParentDealerName,
uparentDealer.Middlename AS ParentDealerPatronymic,
parentDealer.BIN AS ParentDealerBin,
--place dealers
uDealer1.Surname AS PlaceDealerSurname,
uDealer1.Name AS PlaceDealerName,
uDealer1.Middlename AS PlaceDealerPatronymic,
d1.BIN AS PlaceDealerBin,
uparentDealer1.Surname AS PlaceParentDealerSurname,
uparentDealer1.Name AS PlaceParentDealerName,
uparentDealer1.Middlename AS PlaceParentDealerPatronymic,
parentDealer1.BIN AS PlaceParentDealerBin
FROM Cancelation AS c
INNER JOIN CancelationTicket AS ct ON ct.CancelationId = c.Id
INNER JOIN Ticket AS t ON t.Id = ct.TicketId
INNER JOIN [Order] AS o ON o.Id = c.OrderId
INNER JOIN Terminal AS ter ON ter.Id = IIF(o.PaymentType = 1, c.TerminalId, t.TerminalId)
INNER JOIN Terminal AS ter1 ON ter1.Id = c.TerminalId
LEFT JOIN [TerminalData] AS td ON td.[Id] = ter.Id
INNER JOIN [SalePoint] AS sp ON td.[SalePointId] = sp.[Id]
INNER JOIN FinAccStation AS fas ON fas.Id = sp.FinAccStationId
INNER JOIN Guo AS g ON g.Id = fas.GuoId
INNER JOIN Department AS dep ON dep.Id = g.DepartmentId
INNER JOIN Dealer AS d ON d.Id = ter.DealerId
INNER JOIN Dealer AS d1 ON d1.Id = ter1.DealerId
INNER JOIN [User] AS uDealer ON uDealer.Id = d.Id
INNER JOIN [User] AS uDealer1 ON uDealer1.Id = d1.Id
INNER JOIN SalesChannel AS sc ON sc.Id = d.SalesChannelId AND (EXISTS(SELECT * FROM #SaleChannels) AND (d.SalesChannelId IN (SELECT * FROM #saleChannels)) OR NOT EXISTS(SELECT * FROM #saleChannels))
INNER JOIN Branch AS b ON b.Id = dep.BranchId AND (EXISTS(SELECT * FROM #Branches) AND (b.Id IN (SELECT * FROM #Branches)))
INNER JOIN ParentDealer AS parentDealer ON parentDealer.childId = d.Id AND (parentDealer.parentId IN (SELECT Id FROM #Dealers) OR NOT EXISTS(SELECT * FROM #Dealers))
INNER JOIN [User] AS uParentDealer ON uParentDealer.Id = parentDealer.parentId
INNER JOIN ParentDealer AS parentDealer1 ON parentDealer1.childId = d1.Id
INNER JOIN [User] AS uParentDealer1 ON uParentDealer1.Id = parentDealer1.parentId
WHERE c.OperationDate BETWEEN #PeriodFrom AND #PeriodTo AND
((EXISTS(SELECT TOP 1 * FROM #Carriers) AND (o.CarrierName IN (SELECT CarrierName FROM CarrierNames))) OR NOT EXISTS(SELECT TOP 1 * FROM #Carriers)) AND
c.ResponseXml.value('(/GtETicket_Response/#Type)[1]','nvarchar(max)') != 'ExpressStatus'
)T
)
SELECT *
from Result
END
UPDATED: Code on C# side:
public IEnumerable<RegisterTicketsByDealerReportItem> GetRegisterTicketsByDealerReport(DateTime periodFrom, DateTime periodTo, int[] dealerIds, int[] salesChannelIds, int[] branchIds, int[] carrierIds)
{
var pars = new DynamicParameters();
var identityFailureValue = new { Id = 0 }.ToEmptyTable().AsTableValuedParameter("Identities");
pars.AddDynamicParams(
new
{
PeriodFrom = periodFrom,
PeriodTo = periodTo,
Dealers = dealerIds.Return(ds => ds.Select(d => new { Id = d }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue),
Branches = branchIds.Return(br => br.Select(b => new { Id = b }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue),
SaleChannels = salesChannelIds.Return(scs => scs.Select(sc => new { Id = sc }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue),
Carriers = carrierIds.Return(scs => scs.Select(sc => new { Id = sc }).ToDataTable().AsTableValuedParameter("Identities"), identityFailureValue)
});
var result = Connection.Query<RegisterTicketsByDealerReportItem>("TicketSaleByAggregator", pars,
commandType: CommandType.StoredProcedure,
commandTimeout: dbConfiguration.SqlLargeTimeoutSeconds);
Connection.CloseIfNoTransaction();
return result;
}
Sql connection parametrs:
<add key="SqlLargeTimeoutSeconds" value="00:02:00" />
<add name="Readonly" providerName="System.Data.SqlClient" connectionString="Data Source=.;Initial Catalog=db_Readonly;Integrated Security=True;" />
1- Try to use with(nolock) if it is non sensitive transnational data
2- Stop mirroring and check the speed. mirroring may cause this problem

How to include where clause in a set query

I have the query below and it works exactly as I want EXCEPT I need to be able to include a where clause with the declared variable of startDate and endDate. I keep getting an error on the variables.
DROP PROCEDURE IF EXISTS `reportNameTest`//
-- Creates new procedure
CREATE PROCEDURE reportNameTest (
IN logId varchar (50),
IN fromDate varchar (50),
IN toDate varchar (50)
)
BEGIN
DECLARE logInS varchar (50);
DECLARE startDate varchar (50);
DECLARE endDate varchar (50);
SET startDate = FROM_UNIXTIME(fromDate/1000);
SET endDate = FROM_UNIXTIME(toDate/1000);
SET #tbl = CONCAT('log',logId);
SET #s = CONCAT(
'SELECT g.groupId,g.name AS groupName,l.logId,l.name AS logName,
lr.userId,completed,
g1.parentId AS parentId1, g1.name AS group1Name,g2.parentId AS parentId2, g2.name AS group2Name,
g3.parentId AS parentId3, g3.name AS group3Name,u.name,u.userId,lr.*
FROM logs l
INNER JOIN activities a ON l.logid = a.logid
INNER JOIN groups g ON g.groupId = l.groupId
LEFT JOIN groups g1 ON g.parentId = g1.groupId
LEFT JOIN groups g2 ON g1.parentId = g2.groupId
LEFT JOIN groups g3 ON g2.parentId = g3.groupId
INNER JOIN ' ,#tbl);
SET #V = CONCAT (#s,' lr ON lr.activityID = a.activityID
INNER JOIN users u ON u.userID = lr.userID' );
SET #W = CONCAT (#V,'WHERE l.completed
BETWEEN startDate
AND endDate');
PREPARE stmt FROM #V;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
I am open to any suggestions!
Thank you
First of all, as #neutrino points out, you're missing a space between lr.userID and WHERE. To see this you could return the query with select #W instead of the prepare and execute. Then try to run that query in a normal mysql commander.
Or you can check the query/general log for the query that fails and find the missing space.
Second, you don't need to build you query in several steps like that, it's probably easier to read if you just do one long change of concat.
There are several problems with your code:
You are producing unnecessary variables when building a query string. #S -> #V -> #W. But then you prepare your statement from #V which doesn't contain the complete query string.
Instead of concatenating values of variables startDate and endDate you put their names in a string literal.
Values of startDate and endDate should be quoted.
You don't use logInS variable even though you declared it.
In your case you need only one variable (unless you do something meaningful with them like validating for example) that will hold a query string.
That being said try it this way
DELIMITER //
CREATE PROCEDURE reportNameTest(
IN logId VARCHAR(50),
IN fromDate VARCHAR(50),
IN toDate VARCHAR(50))
BEGIN
SET #sql = CONCAT(
'SELECT g.groupId, g.name AS groupName, l.logId,l.name AS logName,
lr.userId,completed,
g1.parentId AS parentId1, g1.name AS group1Name,g2.parentId AS parentId2, g2.name AS group2Name,
g3.parentId AS parentId3, g3.name AS group3Name,u.name,u.userId,lr.*
FROM logs l
INNER JOIN activities a ON l.logid = a.logid
INNER JOIN groups g ON g.groupId = l.groupId
LEFT JOIN groups g1 ON g.parentId = g1.groupId
LEFT JOIN groups g2 ON g1.parentId = g2.groupId
LEFT JOIN groups g3 ON g2.parentId = g3.groupId
INNER JOIN log', logId, ' lr ON lr.activityID = a.activityID
INNER JOIN users u ON u.userID = lr.userID
WHERE l.completed BETWEEN \'', FROM_UNIXTIME(fromDate / 1000),
'\' AND \'', FROM_UNIXTIME(toDate / 1000), '\'');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
That should work just fine assuming that you resulting query itself is correct.
Here is SQLFiddle demo that outputs the resulting query string instead of executing it.