MySQL Stored Procedure with IF/THEN/ELSE - mysql

I have a MySQL stored procedure and in it, the following WHILE statement.
I have confirmed that #RowCnt is 1, and #MaxRows is 6090, however after further debugging, I realized that the WHILE statement is going through a single iteration and not continuing; so I'm hoping to have some light shed on what could possibly be causing this.
Full disclosure: I ported this from SQL Server to a MySQL stored procedure, something I have never taken on before. (meaning SQL Server, porting OR stored procedures..)
WHILE #RowCnt <= #MaxRows DO
SELECT #currentReadSeq:=ReadSeq, #currentReadStrength:=ReadStrength, #currentReadDateTime:=ReadDateTime, #currentReaderID:=ReaderID FROM tblTempRead WHERE rownum = #RowCnt;
IF ( ((#lastReadSeq + 10) > #currentReadSeq) AND (#lastReaderId = #currentReaderId) ) THEN
SET #lastReadSeq = #currentReadSeq, #lastReadStrength = #currentReadStrength, #lastReadDateTime = #currentReadDateTime, #lastReaderID = #currentReaderID;
ELSE
INSERT INTO tblreaddataresults (SiteID, ReadDateTimeStart, ReadDateTimeEnd, ReadSeqStart, ReadSeqEnd, ReaderID, DirectSeconds) VALUES ('1002', #saveReadDateTime, #lastReadDateTime, #saveReadSeq, #lastReadSeq, #lastReaderID, timestampdiff(SECOND,#saveReadDateTime,#lastReadDateTime));
SET #saveReadSeq = #currentReadSeq, #saveReadStrength = #currentReadStrength, #saveReadDateTime = #currentReadDateTime, #saveReaderID = #currentReaderID;
SET #lastReadSeq = #saveReadSeq, #lastReadStrength = #saveReadStrength, #lastReadDateTime = #saveReadDateTime, #lastReaderID = #saveReaderID;
END IF;
SET #RowCnt = #RowCnt+1;
END WHILE;

Try This Construct
WHILE (#RowCnt <= #MaxRows)
BEGIN
SELECT #currentReadSeq:=ReadSeq, #currentReadStrength:=ReadStrength, #currentReadDateTime:=ReadDateTime, #currentReaderID:=ReaderID FROM tblTempRead WHERE rownum = #RowCnt;
IF (((#lastReadSeq + 10) > #currentReadSeq) AND (#lastReaderId = #currentReaderId))
BEGIN
SET #lastReadSeq = #currentReadSeq, #lastReadStrength = #currentReadStrength, #lastReadDateTime = #currentReadDateTime, #lastReaderID = #currentReaderID;
END
ELSE
BEGIN
INSERT INTO tblreaddataresults (SiteID, ReadDateTimeStart, ReadDateTimeEnd,ReadSeqStart, ReadSeqEnd, ReaderID, DirectSeconds) VALUES ('1002',#saveReadDateTime, #lastReadDateTime, #saveReadSeq, #lastReadSeq, #lastReaderID,timestampdiff(SECOND,#saveReadDateTime,#lastReadDateTime));
SET #saveReadSeq = #currentReadSeq, #saveReadStrength = #currentReadStrength, #saveReadDateTime = #currentReadDateTime, #saveReaderID = #currentReaderID;
SET #lastReadSeq = #saveReadSeq, #lastReadStrength = #saveReadStrength,#lastReadDateTime = #saveReadDateTime, #lastReaderID = #saveReaderID;
END
SET #RowCnt = #RowCnt+1;
END

Related

Stored Function Variables in MySQL

I am trying to create a stored function in MySQL but when I try to run the function it does't see the variable 'InterimAPI'
Code is as follows:
DELIMITER $$
Create function
InterimAPI_Math(test_subject char(100), grade
int(2), GradeTableValue decimal(5,2))
Returns decimal(6,2) Not Deterministic
Begin
Declare IterimAPI decimal(10,2);
if test_subject = 'Math' AND Grade = 3 THEN
SET ##InterimAPI = (10.9*(GradeTableValue - 253.9)) + 1000;
elseif test_subject = 'MATH' AND GRADE = 4 THEN
SET ##InterimAPI = (10.8*(GradeTableValue -253.4)) + 1000;
elseif test_subject = 'MATH' AND GRDE = 5 THEN
SET ##InterimAPI = (10.1*(GradeTableValue - 250.3)) + 1000;
elseif test_subject = 'MATH' AND GRADE = 6 THEN
SET ##InterimAPI = (9.4*(GradeTableValue - 246.3)) + 1000;
elseif test_subject = 'MATH' AND GRADE = 7 THEN
SET ##InterimAPI = (8.4*(GradeTableValue - 240.2)) + 1000;
elseif test_subject = 'MATH' AND GRADE = 8 THEN
SET ##InterimAPI = (8.4*(GradeTableValue - 239.8)) + 1000;
elseif test_subject = 'Algebra I' AND GRADE = 'EOI' THEN
SET InterimAPI = (17.4*(GradeTableValue - 71.2)) + 1000;
END IF;
Return (InterimAPI);
END
Also slightly confused as to what belongs in the parameters. Is it the information from the table that you want input into the function or something else?

SQLTransaction2 : Operation cannot be performed on an active transaction FreePascal - Code Typhon

I would like some help solving this error message.
I am using Code Typhon32 V4.9 on Windows 7 Pro.
I had a project connecting to a firebird database,
Single form which works fine- No problems.
I added a 2nd form to be my data entry form linked to another Database in
Firebird - I need both databases in one project.
Since adding the 2nd form I am getting the following error when I close code typhon and when I close Form1 while using the debugger: "SQLTransaction2 : Operation cannot be performed on an active transaction"
I have tried numerous of solution found on the internet but can not solve it.
I have a button that open the 2nd from as Follows:
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
frmContributions := TfrmContributions.Create(nil);
try
frmContributions.ShowModal;
finally
frmContributions.Free;
end;
end;
Here is my 2nd form Code:
unit uFirebirdDemo1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, sqldb, IBConnection, pqconnection, db, FileUtil, Forms,
Controls, Graphics, Dialogs, StdCtrls, DBGrids, DbCtrls;
type
TfrmContributions = class(TForm)
btnUpdate: TButton;
btnDeleteProgrammer: TButton;
dsProgrammer: TDatasource;
dbgrdProgrammer: TDBGrid;
dbnavProgrammer: TDBNavigator;
IBConnection2: TIBConnection;
sqlqProgrammer: TSQLQuery;
SQLScript1: TSQLScript;
SQLTransaction2: TSQLTransaction;
procedure btnDeleteProgramClick(Sender: TObject);
procedure btnUpdateClick(Sender: TObject);
procedure btnUpdateProgramsClick(Sender: TObject);
procedure btnDeleteProgrammerClick(Sender: TObject);
procedure dbgrdCombinedTitleClick(Column: TColumn);
procedure dbgrdProgrammerTitleClick(Column: TColumn);
procedure dbgrdProgramsTitleClick(Column: TColumn);
procedure edtSearchChange(Sender: TObject);
procedure Savechanges;
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
end;
var
frmContributions: TfrmContributions;
implementation
{$R *.lfm}
procedure TfrmContributions.btnUpdateClick(Sender: TObject);
begin
sqlqProgrammer.Edit;
sqlqProgrammer.Post;
sqlqProgrammer.ApplyUpdates(1);
SQLTransaction2.CommitRetaining;
end;
procedure TfrmContributions.btnDeleteProgrammerClick(Sender: TObject);
begin
SQLScript1.Script.Text:= 'Delete from Programmer WHERE ID = ' + dbgrdProgrammer.Columns[0].Field.AsString + ';';
SQLScript1.Execute;
SQLTransaction2.CommitRetaining;
sqlqProgrammer.Refresh;
end;
procedure TfrmContributions.dbgrdProgrammerTitleClick(Column: TColumn);
begin
sqlqProgrammer.Close;
SQLTransaction2.Active := TRUE;
sqlqProgrammer.SQL.Text := 'Select * from Programmer ORDER BY ID DESC';
sqlqProgrammer.Open;
end;
procedure TfrmContributions.Savechanges;
// Saves edits done by user, if any.
begin
try
if SQLTransaction2.Active then
// Only if we are within a started transaction
// otherwise you get "Operation cannot be performed on an inactive dataset"
begin
sqlqProgrammer.ApplyUpdates; //Pass user-generated changes back to database...
SQLTransaction2.Commit; //... and commit them using the transaction.
//SQLTransaction2.Active now is false
end;
except
on E: EDatabaseError do
begin
MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
E.Message, mtError, [mbOK], 0);
end;
end;
end;
procedure TfrmContributions.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
SaveChanges;
sqlqProgrammer.Close;
SQLTransaction2.Commit;
SQLTransaction2.RollBack;
SQLTransaction2.Active := False;
IBConnection2.Connected := False;
end;
end.
I tried adding a formclose to my first form as follows in order to solved the problem
but it does not seem to be doing anything:
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
frmContributions.SaveChanges;
frmContributions.SQLTransaction2.RollBack;
frmContributions.SQLTransaction2.Active := False;
frmContributions.IBConnection2.Connected := False;
end;
I have tried different solutions found on the internet but I am still getting:
"SQLTransaction2 : Operation cannot be performed on an active transaction" when i
close my project using the debugger, and also I get the same error when closing down
code typhon.
Here is the lfm file:
object frmContributions: TfrmContributions
Left = 816
Height = 415
Top = 172
Width = 774
Caption = 'Data Entry for Promo'
ClientHeight = 415
ClientWidth = 774
Color = clHighlight
OnClose = FormClose
LCLVersion = '1.3'
object btnUpdate: TButton
Left = 536
Height = 25
Top = 376
Width = 168
Caption = 'Update programmers'
OnClick = btnUpdateClick
TabOrder = 0
end
object dbgrdProgrammer: TDBGrid
Left = 16
Height = 360
Top = 0
Width = 744
Color = clWindow
Columns = <
item
Title.Caption = 'ID'
Width = 60
FieldName = 'ID'
end
item
Title.Caption = 'DATESENT'
FieldName = 'DATESENT'
end
item
Title.Caption = 'COURSE'
Width = 140
FieldName = 'COURSE'
end
item
Title.Caption = 'PROMOTYPE'
Width = 140
FieldName = 'PROMOTYPE'
end
item
Title.Caption = 'LINK'
Width = 100
FieldName = 'LINK'
end
item
Title.Caption = 'VALUE'
Width = 50
FieldName = 'VALUECHART'
end
item
Title.Caption = 'TOTALSENT'
FieldName = 'TOTALSENT'
end
item
Title.Caption = 'NOTES'
FieldName = 'NOTES'
end>
DataSource = dsProgrammer
TabOrder = 1
OnTitleClick = dbgrdProgrammerTitleClick
end
object dbnavProgrammer: TDBNavigator
Left = 280
Height = 25
Top = 376
Width = 241
BevelOuter = bvNone
ChildSizing.EnlargeHorizontal = crsScaleChilds
ChildSizing.EnlargeVertical = crsScaleChilds
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 100
ClientHeight = 25
ClientWidth = 241
DataSource = dsProgrammer
Options = []
TabOrder = 2
VisibleButtons = [nbFirst, nbPrior, nbNext, nbLast, nbInsert, nbRefresh]
end
object btnDeleteProgrammer: TButton
Left = 64
Height = 25
Top = 376
Width = 201
Caption = 'Delete Selected Programmer'
OnClick = btnDeleteProgrammerClick
TabOrder = 3
end
object dsProgrammer: TDataSource
DataSet = sqlqProgrammer
left = 696
top = 168
end
object IBConnection2: TIBConnection
Connected = True
LoginPrompt = False
DatabaseName = '.......CONTRIBUTIONS.FDB'
KeepConnection = False
Password = 'password'
Transaction = SQLTransaction2
UserName = 'username'
HostName = 'hostname'
left = 696
top = 8
end
object SQLTransaction2: TSQLTransaction
Active = True
Action = caCommitRetaining
Database = IBConnection2
left = 696
top = 56
end
object sqlqProgrammer: TSQLQuery
IndexName = 'DEFAULT_ORDER'
FieldDefs = <
item
Name = 'ID'
DataType = ftInteger
Precision = -1
Size = 0
end
item
Name = 'DATESENT'
DataType = ftDate
Precision = -1
Size = 0
end
item
Name = 'PROMOTYPE'
DataType = ftString
Precision = -1
Size = 25
end
item
Name = 'COURSE'
DataType = ftString
Precision = -1
Size = 25
end
item
Name = 'LINK'
DataType = ftString
Precision = -1
Size = 450
end
item
Name = 'VALUECHART'
DataType = ftInteger
Precision = -1
Size = 0
end>
Active = True
Database = IBConnection2
Transaction = SQLTransaction2
SQL.Strings = (
'select * from Programmer order by ID DESC'
)
UpdateSQL.Strings = (
''
)
InsertSQL.Strings = (
''
)
DeleteSQL.Strings = (
''
)
Params = <>
UpdateMode = upWhereChanged
UsePrimaryKeyAsKey = False
left = 696
top = 224
end
object SQLScript1: TSQLScript
DataBase = IBConnection2
Transaction = SQLTransaction2
Directives.Strings = (
'SET TERM'
'COMMIT'
'#IFDEF'
'#IFNDEF'
'#ELSE'
'#ENDIF'
'#DEFINE'
'#UNDEF'
'#UNDEFINE'
)
Script.Strings = (
''
)
Terminator = ';'
CommentsinSQL = True
UseSetTerm = True
UseCommit = True
UseDefines = True
left = 696
top = 112
end
end
Thank you.
Actually I don't know exactly what should be next, but
(0) I'd move the database code into standalone TDataModule (outside the UI code) to make the code more straightforward to read and maintain. During this refactoring you may spot a hidden problem..
(1) this http://forum.lazarus.freepascal.org/index.php?topic=14301.0 seems to solve similar problem
(2) book Lazarus, the complete guide seems to have a chapter about TDataModule
(3) Martin Fowler wrote a book about refactoring and runs a site about the same at http://refactoring.com/
(4) some components don't behave well if they are active in the design mode. As it is actually different and more complicated scenario (lots of ifs with csDesigning in ComponentState, sequence diagram of events is different, nearly random and everything should be foolproof and re-entrant..). So safe side for production is to turn component's active state off in the design mode and activate them in code in a well defined order anticipated by the component authors
(5) If you experience the error only when in the debugger and it does not appear in production code I think that you can ignore the problem as the debugging environment is <see="(4)">

How to make function execute faster in SQL?

I am using function to update to one column , like
DetailedStatus = dbo.fn_GetProcessStageWiseStatus(PR.ProcessID, PR.ProcessRunID, getdate())
Here 500,000 records are continuously UPDATED in this line. Its like like a loop
So using this function for few records its executing fast but when its 500,000 records executing it becomes very slow...
What can I do to make this execute faster using many records?
Any measures to be taken or any split to be used?
Function:
CREATE FUNCTION [dbo].[fn_GetProcessStageWiseStatus]
(
#ProcessID INT
,#ProcessRunID INT
,#SearchDate SMALLDATETIME
)
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE
#iLoopCount SMALLINT
,#iRowCount SMALLINT
,#StepProgress VARCHAR(100)
,#StepCount SMALLINT
IF EXISTS(
SELECT TOP 1 1
FROM dbo.Step S WITH(NOLOCK)
JOIN dbo.vw_FileGroup FG
ON S.FileConfigGroupID = FG.FileConfigGroupID
WHERE S.ProcessID = #ProcessID
AND S.Active = 1
AND FG.FileConfigGroupActive = 1
AND FG.Direction = 'Inbound'
)
BEGIN
SET #StepProgress = 'Not Received'
END
ELSE
BEGIN
SET #StepProgress = 'Not Started'
END
DECLARE #StepRunDetailsTable TABLE
(
KeyNo INT IDENTITY(1,1)
,StepID INT
,StepStartTime SMALLDATETIME
,StepEndTime SMALLDATETIME
,SourceEnv VARCHAR(100)
,DestEnv VARCHAR(100)
)
INSERT INTO #StepRunDetailsTable
SELECT
S.StepID
,MAX(isnull(SR.StepStartTime, '06/06/2079'))
,MAX(isnull(SR.StepEndTime, '06/06/2079'))
,isnull(SENV.EnvironmentName, '')
,isnull(DENV.EnvironmentName, '')
FROM dbo.ProcessRun PR WITH(NOLOCK)
JOIN dbo.StepRun SR WITH(NOLOCK)
ON SR.ProcessRunID = PR.ProcessRunID
JOIN dbo.vw_StepHierarchy SH
ON SR.StepID = SH.StepID
AND SH.Active = 1
JOIN dbo.Step S WITH(NOLOCK)
ON SH.StepID = S.StepID
JOIN dbo.WorkFlow WF WITH(NOLOCK)
ON S.WorkFlowID = WF.WorkFlowID
AND WF.Active = 1
JOIN dbo.Environment SENV WITH(NOLOCK)
ON SENV.EnvironmentID = WF.SourceEnvironmentID
AND SENV.Active = 1
JOIN dbo.Environment DENV WITH(NOLOCK)
ON DENV.EnvironmentID = WF.DestinationEnvironmentID
AND DENV.Active = 1
WHERE PR.ProcessRunID = #ProcessRunID
GROUP BY S.StepID, SENV.EnvironmentName, DENV.EnvironmentName, SH.StepOrder
ORDER BY SH.StepOrder ASC
SELECT #StepCount = COUNT(*)
FROM dbo.ProcessRun PR WITH(NOLOCK)
JOIN dbo.Step S WITH(NOLOCK)
ON PR.ProcessID = S.ProcessID
AND PR.ProcessRunID = #ProcessRunID
AND S.Active = 1
SELECT #iRowCount = COUNT(DISTINCT StepID) FROM #StepRunDetailsTable
SET #iLoopCount = 0
WHILE (#iRowCount > #iLoopCount)
BEGIN
SET #iLoopCount = #iLoopCount + 1
SELECT
#StepProgress =
CASE
--WHEN #SearchDate BETWEEN StepStartTime AND StepEndTime
WHEN #SearchDate >= StepStartTime AND #SearchDate <= StepEndTime
THEN DestEnv + ' Load in Progress'
WHEN #SearchDate > StepEndTime AND #iLoopCount < #StepCount
THEN 'Waiting on next step - Loaded to ' + DestEnv
WHEN #SearchDate > StepEndTime AND #iLoopCount = #StepCount
THEN 'Completed'
WHEN #SearchDate < StepStartTime AND #iLoopCount = 1
THEN 'Load Not Started'
ELSE #StepProgress
END
FROM #StepRunDetailsTable
WHERE KeyNo = #iLoopCount
END
RETURN #StepProgress
END
Thanks in advance.
Seems like you have a change in execution plan when you try to update 500k rows.
You can try and set forceseek hint on the from clause to force using seeks instead of scans.
Also, WHILE (#iRowCount > #iLoopCount) should be replaced with if exists, because you basically check for certain conditions on the results table and you need to return as early as possible.
I see that you use nolock hint everywhere to allow dirty reads, you can set isolation level read uncommitted in the calling stored procedure and remove all of those; or consider to change the database to set read_committed_snapshot on to avoid locks.
By the way, scalar function calls in SQL Server are very expensive, so if you have some massive updates/selects happening in a loop where you call a function you have to avoid using functions as much as possible.

error message not displaying on mysql stored procedure

I am trying to validate something but It always returns a success result. I wonder what's wrong with my codes.
INSERT INTO playlist_details (playlist_id,filename,image_id,transition,timeframe,userid,update_date)
VALUES (i_playlistid,i_filename,i_imageid, i_transition, i_time, i_userid,i_date);
SELECT booking_id INTO v_booking_id FROM staging_table WHERE playlist_id = i_playlistid LIMIT 1;
SELECT num_of_spots INTO v_spots FROM booking_sum WHERE booking_id = v_booking_id;
SET v_allowed_time = v_spots * 30;
IF ((SELECT SUM(timeframe) FROM playlist_details WHERE playlist_id = i_playlistid) > v_allowed_time) THEN
SET o_success = FALSE;
SET o_message = 'You exceeded the time allowed with your booking';
SELECT playlist_id,filename,image_id,transition,timeframe,userid FROM playlist_details
WHERE userid = i_userid;
ELSE
SELECT playlist_id,filename,image_id,transition,timeframe,userid FROM playlist_details
WHERE userid = i_userid;
SET o_success = TRUE;
SET o_message = 'Success';
END IF;

MySQL DECLARE Syntax (Converting from MSSQL)

MySQL Gurus,
I'm converting some reports from a MSSQL database for usage on a MySQL Database, and don't seem to understand how the DECLARE works in MySQL. Below is the SQL code for the report, as works in MSSQL. I read that DECLARE can only be use in a nested function, I belive, but that just does not sound right to me.
Current Report SQL: (I parse & replace the values of Current & Pending from my app code)
DECLARE #Current int;
DECLARE #Pending int;
SET #Current = [1];
SET #Pending = [3];
Select Ticket.TIcketID,
ISNULL((Select LocationName from Location where LocationID = Ticket.SiteCurrentLocation), 'Invalid Location') as [Current Location],
ISNULL((Select LocationName from Location where LocationID = Ticket.SitePendingLocation), 'Invalid Location') as [Pending Location]
from Ticket
where
(SitePendingLocation > 0 AND SitePendingLocation <> SiteCurrentLocation) AND
(SiteCurrentLocation = #Current OR #Current = 0) AND
(SitePendingLocation = #Pending OR #Current = 0)
Any insight?
Thanks - Andrew
EDIT
Working, converted script - that it may help others:
SET #Current = '1';
SET #Pending = '1';
Select Ticket.TIcketID,
IFNULL((Select LocationName from Location where LocationID = Ticket.SiteCurrentLocation), 'Invalid Location') as `Current Location`,
IFNULL((Select LocationName from Location where LocationID = Ticket.SitePendingLocation), 'Invalid Location') as `Pending Location`
from Ticket
where
(SitePendingLocation > 0 AND SitePendingLocation <> SiteCurrentLocation) AND
(SiteCurrentLocation = #Current OR #Current = 0) AND
(SitePendingLocation = #Pending OR #Current = 0)
You can either use SET by itself (no DECLARE) or replace # with _ or similar (or even no prefix).
I generally prefix mine with _
See What's wrong with this MySQL statement: DECLARE #ID INT for a similar question
As regards your other comment, it's IFNULL in MySql - See http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_ifnull
It's always the little things... :-)