All Tables cant' perform INSERT OR UPDATE - mysql

I used a stored procedure that uses a cursor to loop through and process an attendance data table on Mariadb 10.1 database after calling the procedure the first time all the tables on the database lost the ability to perform INSERT INTO or UPDATE statements unless the targeted table is truncated first, can any one tell me what went wrong and how to fix it
the procedure that caused the problem:
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `settle_attendance`()
MODIFIES SQL DATA
BEGIN
DECLARE trans_done BOOLEAN DEFAULT FALSE;
DECLARE punchid BIGINT(20);
DECLARE timein DATETIME;
DECLARE utctimein DATETIME;
DECLARE timeout DATETIME;
DECLARE utctimeout DATETIME;
DECLARE inday DATE;
DECLARE outday DATE;
DECLARE todaysdate DATE;
DECLARE attendcur CURSOR FOR
SELECT id, punch_in_utc_time, punch_in_user_time,
punch_out_utc_time, punch_out_user_time
FROM ohrm_attendance_record
ORDER BY id ASC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET trans_done = TRUE;
OPEN attendcur;
edit_loop: LOOP
SET todaysdate = CURRENT_DATE();
FETCH attendcur INTO punchid, utctimein, timein, utctimeout, timeout;
IF trans_done THEN
CLOSE attendcur;
LEAVE edit_loop;
END IF;
SET inday = DATE(timein);
SET outday = DATE(timeout);
SET todaysdate = CURRENT_DATE();
IF (inday < todaysdate) OR (outday < todaysdate) THEN
CASE
WHEN (timein IS NULL OR timein = '')
OR (utctimein IS NULL OR utctimein = '') THEN
UPDATE ohrm_attendance_record
SET punch_in_utc_time = utctimeout,
punch_in_user_time = timeout,
state = 'PUNCHED OUT'
WHERE punchid = id;
ELSE BEGIN END;
END CASE;
CASE
WHEN (timeout IS NULL OR timeout = '')
OR (utctimeout IS NULL OR utctimeout = '') THEN
UPDATE ohrm_attendance_record
SET punch_out_utc_time = utctimein,
punch_out_user_time = timein,
state = 'PUNCHED OUT'
WHERE punchid = id;
ELSE BEGIN END;
END CASE;
END IF;
END LOOP edit_loop;
END $$
DELIMITER ;

I choose to avoid the question you asked. Instead, let's try to do the query 10 times as fast by getting rid of the pesky CURSOR. The entire Stored Procedure can be done in 2 UPDATEs, no loop:
UPDATE ohrm_attendance_record
SET punch_in_utc_time = utctimeout,
punch_in_user_time = timeout,
state = 'PUNCHED OUT'
WHERE ( timein < CURDATE() OR timeout < CURDATE() )
AND ( ( timein IS NULL OR timein = '' )
OR ( utctimein IS NULL OR utctimein = '' )
);
UPDATE ohrm_attendance_record
SET punch_out_utc_time = utctimein,
punch_out_user_time = timein,
state = 'PUNCHED OUT'
WHERE ( timein < CURDATE() OR timeout < CURDATE() )
AND ( ( timeout IS NULL OR timeout = '' )
OR ( utctimeout IS NULL OR utctimeout = '' )
);
I am, however, suspicious of your tests against timein and timeout.
The queries would be easier to read if you settled on either NULL or '' for missing times.
If you store only UTC values in a TIMESTAMP, you can let the user's timezone take care of coverting to local time -- this would eliminate quite a few columns and simplify the UPDATEs.
I'll make a stab at the question... Do SHOW CREATE PROCEDURE settle_attendance;, you may find that the CHARACTER SET or COLLATION is inconsistent with what you think it should be.

Related

Mysql function used within a VIEW does not return the correct result.

I am facing a weird issue (i tried to look for previous answers but i could not find anything).
I created this function:
CREATE DEFINER=`root`#`localhost` FUNCTION `CALCULATEDATE`(caller VARCHAR(4)) RETURNS date
BEGIN
DECLARE cur_day INT(2);
DECLARE cur_time INT(2);
DECLARE calculated_date DATE;
IF caller = 'HOME' THEN
SELECT DAY(CONVERT_TZ(NOW(),##system_time_zone,'US/Pacific')) INTO cur_day;
SELECT HOUR(CONVERT_TZ(NOW(),##system_time_zone,'US/Pacific')) INTO cur_time;
/*Case homepage */
IF cur_day = DAY(NOW()) THEN
IF cur_time < 7 THEN
/*return yesterdays date */
SET calculated_date = DATE_SUB(CURDATE(), INTERVAL 1 DAY);
ELSE
/*return todays date */
SET calculated_date = CURDATE();
END IF;
ELSE
SET calculated_date = DATE(CONVERT_TZ(NOW(),##system_time_zone,'US/Pacific'));
END IF;
ELSE
/*Case newsletter */
/*return todays date */
SET calculated_date = CURDATE();
END IF;
RETURN calculated_date;
END
Which returns a date (based on PST time comparison).
I am calling this function from a view:
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`#`localhost`
SQL SECURITY DEFINER
VIEW `dd_vwfeatured` AS
(SELECT
`doms`.`id` AS `id`,
`doms`.`name` AS `name`
FROM
`myelements` `doms`
WHERE
`doms`.`id` IN (SELECT
`d`.`domainid`
FROM
(`daily_featured_picks` `d`
LEFT JOIN `daily_featured` `f` ON ((`d`.`featuredid` = `f`.`id`)))
WHERE
(`f`.`date` = CALCULATEDATE('NEWS')))
ORDER BY `doms`.`name`)
The function works perfectly if called from the mysql query, but within a view i get all records in return always.
Can you guys help?
Thanks,
DT
I finally solved it (not sure why it does not worn in the view).
I changed approach and used a stored procedure.
CREATE DEFINER=`root`#`localhost` PROCEDURE `new_procedure`(IN p VARCHAR(4))
BEGIN
DECLARE p_tipo DATE;
SELECT CALCULATEDATE(p)
INTO p_tipo;
SELECT
`doms`.`id` AS `id`,
`doms`.`name` AS `name`,
`doms`.`description` AS `description`,
`doms`.`price` AS `price`
FROM
`myelements` `doms`
WHERE
`doms`.`id` IN (SELECT
`d`.`domainid`
FROM
(`daily_featured_picks` `d`
LEFT JOIN `daily_featured` `f` ON ((`d`.`featuredid` = `f`.`id`)))
WHERE
(`f`.`date` = p_tipo))
ORDER BY `doms`.`name`;
END

VB.Net Daily Time Record MySQL

Good day, I have a problem regarding MySQL queries. I want to create a daily time record output but my problem is on making queries. What I want is that when a record have the same id and date it must be updated otherwise it will insert a new record. These are some of screenshots of table properties
CREATE PROCEDURE dbo.EditGrade
#Id int
,#TimeIn datetime
,#TimeOut datetime
,#Existing bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CurrentTimeIn as datetime
DECLARE #CurrentId as int
SELECT #CurrentId = Id
FROM tblAttendance
WHERE TimeIn = #TimeIn
IF (#CurrentId <> #Id)
BEGIN
IF (SELECT COUNT(ISNULL(Id,0))
FROM tblAttendance
WHERE TimeIn = #TimeIn
SET #Existing = 0
ELSE
SET #Existing = 1
END
ELSE
BEGIN
SET #Existing = 0
END
IF #Name = ''
SET #Name = null
IF (#Existing = 0)
UPDATE tblAttendance
SET TimeIn = #TimeIn
--other column values here
WHERE Id = #Id
ELSE
--INSERT FROM tblAttendance query here
END
GO
this is from stored procedure of ms sql, you can just convert it into mysql version.
take note, datetime types also checks the seconds, so don't include the seconds as much as possible or it will render as NOT THE SAME (e.g time in = 10:00:01 and time out is 10:00:02 will be rendered as NOT THE SAME)

declaring variable inside mysql stored procedure

we are trying to declare a variable inside mysql stored procedure that has transaction implemented in it. but it seems to be giving a syntax error :
following is the syntax of the stored procedure:
CREATE PROCEDURE `sp_MarkAppointmentRefferal`(
p_AppId bigint,
p_NewLocation bigint,
p_userId bigint,
p_ReferralReason varchar(500),
p_NewLocationName varchar(100)
)
begin
declare v_OldLocation int default 0;
set v_OldLocation = (select LocationId FROM appointments where iAppID = p_AppId limit 1 );
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
select -1;
END;
START TRANSACTION;
update table
set is_referred = 1,
referred_timestamp = now(),
referral_reason = p_ReferralReason
where iAppID = p_AppId
limit 1;
-- create a new appointment for the new referred location..
insert into appointments
(vAppName, vAppType, dAppDate, vCell, iPatID, iAppStatus, iuserid, iActive,
dInsertDate, iHSID, daily_ticket_no, LocationId, visit_id, encounter_id, ReferredFrom,ReferredOPDName, opd_name )
select vAppName, vAppType, now(), vCell, iPatID, iAppStatus, p_userId,
1, now(), iHSID, fn_GenerateNextAppointmentTicket(now(),p_NewLocation) , p_NewLocation, visit_id, encounter_id+1,
(select LocationId FROM appointments where iAppID = p_AppId limit 1),
(select OPD_Name FROM appointments where iAppID = p_AppId limit 1), p_NewLocationName
FROM appointments
where iAppID = p_AppId limit 1;
select LAST_INSERT_ID();
COMMIT;
end;
the syntax checker is saying that declare command is not valid here.
have also tried to place this inside the transaction clause and similar error shows up ..
any help is appreciated..
All declare statements should be at the top of the stored procedure body. Moving DECLARE EXIT HANDLER before the SET statement should fix the problem.

how to declare variables in trigger with mysql?

CREATE OR REPLACE TRIGGER ATTENDANCE_NOTIFY AFTER INSERT OR UPDATE ON ATTENDANCE
FOR EACH ROW
DECLARE
V_STUDENT_ID STUDENT.STUDENT_ID%TYPE := NULL;
V_HOD_ID HEAD_OF_DEPARTMENT.HOD_ID%TYPE := NULL;
V_SUBCODE STUDENT.SUBCODE%TYPE := NULL;
V_ATTENDANCE ATTENDENCE%TYPE := NULL;
BEGIN
SELECT SUB_CODE, SUB_NAME INTO V_SUB_CODE, FROM SUBJECT WHERE STUDENT_ID = :NEW.STUDENT_ID;
SELECT STUDENT_ID INTO V_STUDENT_ID FROM STUDENT WHERE SUBJECT_CODE = :NEW.SUBJECT_CODE;
SELECT HOD_ID INTO V_HOD_ID FROM STUDENT_HOD WHERE STUDENT_ID = :NEW.STUDENT_ID;
SELECT ATTENDENCE INTO V_ATTENDENCE FROM ATTENDENCE WHERE STUDENT_ID=:NEW_STUDENT_ID
IF (V_ATTENDENCE IS NOT NULL AND V_SUB_CODE IS NOT NULL AND V_STUDENT_ID IS NOT NULL AND V_HOD_ID IS NOT NULL) THEN
IF (:NEW.ATTENDENCE < (V_ATTENDENCE * 0.85)) THEN
INSERT INTO NOTIFY VALUES(V_HOD_ID, V_STUDENT_ID || ' (ID:- ' || :NEW.STUDENT_ID ||') HAS LESS THAN 85% ATTENDENCE IN SUBJECT ' || V_SUB_CODE);
END IF;
END IF;
EXCEPTION
WHEN OTHERS
THEN NULL;
END;
i am getting a syntax error in declare
There is no way to refer datatype of column in MySQL. DECLARE must statically declare a variable's type and size.
Something like
DECLARE myvar VARCHAR( 8 ) -- This is valid in Mysql
Not
DECLARE myvar mytable.myfield%TYPE --This is invalid in Mysql
Hope this helps.

1172 - Result consisted of more than one row in mysql

How can I solve this problem (Result consisted of more than one row in mysql)
DROP PROCEDURE IF EXISTS `doMarksApplication`;
CREATE PROCEDURE `doMarksApplication`(
in kuser varchar(20),
out idpro int(11))
SP:BEGIN
declare no_more_rows int default FALSE;
declare total_marks decimal(10,2) default 0;
declare idfor int(11) default 0;
declare sskod int(5) default getCurSession();
declare bdata int(5) default 0;
declare nopmh varchar(20);
# Data PB [Permohonan Baru] DM [Proses Pemarkahan]
declare cur1 cursor for
select ind_nopmh from pinduk
left join pprses on pro_nopmh = ind_nopmh
where ind_sskod = sskod and
concat(pro_stats,pro_statp) in ('PB','DM') and
not exists (select mar_idnum from pmrkah where mar_nopmh = ind_nopmh)
order by ind_nopmh;
declare continue handler for not found set no_more_rows = TRUE;
begin
select count(ind_nopmh) into bdata
from pinduk
left join pprses on pro_nopmh = ind_nopmh
where ind_sskod = sskod and
concat(pro_stats,pro_statp) in ('PB','DM') and
not exists (select mar_idnum from pmrkah where mar_nopmh = ind_nopmh);
end;
begin
select count(for_idnum) into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
end;
if idfor = 1 and sskod <> 0 then
begin
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
end;
begin
insert into pprmar
(pma_tkmla,pma_msmla,pma_puser,pma_sskod,pma_idfor,pma_bdata)
values
(curdate(),curtime(),kuser,sskod,idfor,bdata);
end;
begin
select last_insert_id() into idpro;
end;
open cur1;
LOOP1:loop
fetch cur1 into nopmh;
if no_more_rows then
close cur1;
leave LOOP1;
end if;
begin
call getMarksAnakPerak(nopmh,#total_perak);
call getMarksAkademik(nopmh,#total_akdmk);
call getMarksSosioekonomi(nopmh,#total_sosio);
end;
set total_marks = #total_perak + #total_akdmk + #total_sosio;
begin
insert into pmrkah
(mar_idpro,mar_nopmh,mar_idfor,mar_perak,mar_akdmk,mar_sosio,mar_total)
values
(idpro,nopmh,idfor,#total_perak,#total_akdmk,#total_sosio,total_marks);
end;
begin
update pprses
set pro_stats = 'D',
pro_statp = 'M',
pro_tkmsk = curdate(),
pro_msmsk = curtime(),
pro_kuser = kuser
where pro_nopmh = nopmh;
end;
end loop;
begin
update pprmar
set pma_tktmt = curdate(),
pma_mstmt = curtime()
where pma_idnum = idpro;
end;
end if;
END;
i have been programming in mysql for 15 years and this is easily the most confusing stored procedure i have ever seen.
None the less, one possible place for your issue is here
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
I know it does not seem to be the reason but without knowing the content of the other three stored procedures you are calling this is the only candidate. You should add a limit 1 to it, and to every select into statement that reads from a table (i.e. not a sum() or a count() etc...) as that would always have the potential to cause the error you are seeing.
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg limit 1;
In addition, you should comment out the three stored procedure calls and see if the error goes away. My guess is that the issue is one of those stored procedures due to a select into similar to above has more than one row in the result set but does not use limit 1 and does not filter properly.