How to use mysql event scheduler in codeigniter model - mysql

SOLVED
I have this block of codes which will insert data to all unique email_address available on emp_leave_balance table. The problem is it doesn't work even though it didnt catch error. I tried this code in cmd and it works perfectly. I'm not sure if codeigniter accept this kind of query or not.
MODEL
public function insert_credit_points_data($email){
try{
$sql = "DELIMITER $$
CREATE EVENT ecp
ON SCHEDULE EVERY 1 MINUTE STARTS NOW() DO
BEGIN
INSERT INTO emp_leave_balance (balance, date_from, date_to, leave_type, earned, date_filed, action_taken,email_address)
SELECT (1.25+balance), NOW(), DATE_ADD(NOW(),INTERVAL 1 MINUTE), 'Vacation', 1.25, NOW(), 'CREDITED',".$email." FROM emp_leave_balance where email_address = ".$email." ORDER BY balance DESC LIMIT 1;
END$$
DELIMITER ;";
$this->db->query($sql);
}catch(Exception $e){
throw $e;
}
}
SQL ERROR
NEW PROBLEM
I'm trying to loop the insert query based on the number of distinct email address available in my table. The problem is my loop doesn't work.
$sql = "CREATE EVENT ecp ON SCHEDULE EVERY 1 MINUTE STARTS NOW() DO
BEGIN
DECLARE x INT DEFAULT 0;
DECLARE counter INT DEFAULT (SELECT COUNT(DISTINCT(email_address)) FROM emp_leave_balance);
simple_loop: LOOP
INSERT INTO emp_leave_balance (balance, date_from, date_to, leave_type, earned, date_filed, action_taken,email_address)
SELECT (1.25+balance), NOW(), DATE_ADD(NOW(),INTERVAL 1 MINUTE), 'Vacation', 1.25, NOW(), 'CREDITED','".$email."' FROM emp_leave_balance where email_address = '".$email."' ORDER BY balance DESC LIMIT 1;
SET x = x + 1;
IF x<counter THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END";

Very few (if any) functions in CI throw exceptions, if they do it is usually due to a native php function. In your case query() will return boolean depending on whether or not it succeeded so the try catch block is superfluous.
With that being said, all the query() function does is execute a query so I don't see if having a problem handling anything phpmyadmin can't. I would suggest going into the database.php file and changing db_debug to true. This should help you find the exact cause of the error.

Related

SQL nested if inside of a function with exist and checking timestamp

I need to check that VIP exist in DB and his time not expired. Everything would be fine if not this problem: how to create Boolean function that will store this functionality?
CREATE DEFINER=`root`#`localhost` FUNCTION `IsVip`(steamId VARCHAR(17)) RETURNS tinyint(1)
BEGIN
RETURN EXISTS (SELECT SteamId, Expired FROM Vips WHERE SteamId=steamId AND Expired >= NOW());
END
This is my solution, but is this coed efficient well - I mean SELECT statement?
CREATE DEFINER=`root`#`localhost` FUNCTION `IsVip`(steamId VARCHAR(17)) RETURNS tinyint(1)
BEGIN
IF (SELECT VipId FROM Vips WHERE SteamId = steamId AND Expired >= NOW())
THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END
Assuming that there is only one line per SteamID in the Vips table, I would just do :
SELECT 1 FROM Vips WHERE SteamId = ? AND Expired >= NOW();
This will return a single row with a value of 1 when the user is valid (ie exists and is not expired), and an empty recordset if it does not.
Another option :
SELECT COUNT(*) FROM Vips WHERE SteamId = ? AND Expired >= NOW()
Will always return a resultset, with a single record containing either 1 if the user is valid, or 0 if not.

what's wrong with this if/then stored proc?

I'm fuzzy on when I need you use # to reference vars in mySQL. I'm coming from MS SQL where you always use it, but apparently that's not correct in mySQL.
So the below stored procedure is always executing the first IF block, even if the session value is expired - in that it's always executing the update statement. Apparently the only debug tool I could find for mySQL stored procs runs on Windows and Linux. I'm on a Mac. Wamp wamp wamp.
So yeah. Can anyone see what's wrong here? Thanks!
DELIMITER $$
CREATE DEFINER=`xxx`#`localhost` PROCEDURE `validate_session`(uid INT, token VARCHAR(256))
BEGIN
DECLARE sessId INT DEFAULT NULL;
SELECT sessId = id FROM UserSessions
WHERE userId = uid
AND sessionToken = token
AND expires > INTERVAL 2 MINUTE + NOW() ORDER BY expires DESC LIMIT 1;
IF sessId IS NOT NULL THEN
UPDATE UserSessions
SET expires = INTERVAL 2 HOUR + NOW()
WHERE id = sessId;
ELSE
DELETE FROM UserSessions
WHERE userId = uid
AND sessionToken = token;
SET #sessId = 0;
END IF;
SELECT sessId;
END
For the record what it's supposed to do in pseudo code:
if we have a session for this user, with a matching token which has not expired {
update the expiration time to 2 hours from now
return the session id;
}
else {
delete the (now stale) session
return 0;
}
Thanks in advance.
You're not setting the value of sessId... you're making a comparisson in your query.
I think what you need is something like this:
CREATE DEFINER=`xxx`#`localhost` PROCEDURE `validate_session`(uid INT, token VARCHAR(256))
BEGIN
DECLARE sessId INT DEFAULT NULL;
SELECT id
INTO sessId -- Here is the assignment
FROM UserSessions
WHERE userId = uid
AND sessionToken = token
AND expires > INTERVAL 2 MINUTE + NOW()
ORDER BY expires DESC
LIMIT 1;
IF sessId IS NOT NULL THEN
UPDATE UserSessions
SET expires = INTERVAL 2 HOUR + NOW()
WHERE id = sessId;
ELSE
DELETE FROM UserSessions
WHERE userId = uid
AND sessionToken = token;
SET sessId = 0;
END IF;
SELECT sessId;
END
Reference:
MySQL Reference: SELECT ... INTO syntax
MySQL Reference: Local variable scope and resolution

MySQL query seems to be ignoring part of WHERE statement within stored function

I am having quite a frustrating problem with a stored function in MySQL.
I have a database full of session data from users connecting to a wireless hotspot. I am trying to select individual user download statistics from within a selected month. My problem is that the subquery within the function seems to ignore the mac field in the WHERE statement. Here is my code:
CREATE FUNCTION get_month_download(mo varchar(45), box int(11), mac varchar(45)) RETURNS DOUBLE
BEGIN
DECLARE dwnld double;
IF mo IS NULL THEN
SET mo := CONCAT(CONCAT(YEAR(NOW()), '-', MONTH(NOW())),'-','01');
END IF;
SET dwnld := (
SELECT SUM(`tx_bytes`)
FROM `session`
WHERE `assoc_time` > UNIX_TIMESTAMP(mo)
AND `disassoc_time` < UNIX_TIMESTAMP(DATE_ADD(mo, INTERVAL 1 MONTH))
AND `mac` = mac
AND `controller_id` = box
);
return dwnld;
END
Running this:
SELECT get_month_download('2012-09-01', '2', '00:21:5c:56:be:a3');
Returns download data for the entire table, though it is using the controller_id to filter the data.
If I run the subquery outside of the function using the same parameters, it works fine. What gives?
To be more clear, running this query:
SELECT SUM(`tx_bytes`)
FROM `session`
WHERE `assoc_time` > UNIX_TIMESTAMP('2012-09-01')
AND `disassoc_time` < UNIX_TIMESTAMP(DATE_ADD('2012-09-01', INTERVAL 1 MONTH))
AND `mac` = '00:21:5c:56:be:a3'
AND `controller_id` = '2';
returns the correct download statistic for that user. Where the function returns the statistic for all users of that controller.
Are you sure there is more than one controller_id present?
SELECT DISTINCT controller_id FROM session
How many records does this query fetch you?
If this fetches you only one record, and that corresponds to box = 2, there is no issue.
If there are multiple controller ids, run this query,
SELECT COUNT(1), controller_id
FROM session
WHERE assoc_time > '2012-01-01'
AND disassoc_time < '2012-01-31'
AND mac = '00:21:5c:56:be:a3'
GROUP BY controller_id
How many rows does this return? If it returns just one record for controller_id 2, there isn't any isssue.
I should really reflect back to what my teachers taught me in college more often. The issue was that the variable mac, in the scope of the select statement, was seen as a field from the table, and not as my parameter from the function. So, changing the parameter name fixed the issue:
CREATE FUNCTION get_month_download(mo varchar(45), box int(11), inmac varchar(60)) RETURNS DOUBLE
BEGIN
DECLARE dwnld double;
IF mo IS NULL THEN
SET mo := CONCAT(CONCAT(YEAR(NOW()), '-', MONTH(NOW())),'-','01');
END IF;
SET dwnld := (
SELECT SUM(`tx_bytes`)
FROM `session`
WHERE `assoc_time` > UNIX_TIMESTAMP(mo)
AND `disassoc_time` < UNIX_TIMESTAMP(DATE_ADD(mo, INTERVAL 1 MONTH))
AND `controller_id` = box
AND `mac` = inmac
);
return dwnld;
END
This has been a 'smack in the face' moment. Thank you all for your help.

Whats wrong with this short procedure (MySQL)

Im trying to make a procedure, which will be checking if user is already logged (he got a session, and im checking if his last action was over 15 minutes ago). My procedure looks like this:
CREATE PROCEDURE `isLogged`(in p_sessid VARCHAR(32), out res INT(1))
BEGIN
DECLARE v_customer_id INT(9);
DECLARE v_date DATE;
SELECT customer_id INTO v_customer_id FROM Sessions WHERE sessid=p_sessid;
SELECT expiry_date INTO v_date FROM Sessions WHERE sessid=p_sessid;
SET res=3;
IF v_customer_id > 0 THEN
IF UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(v_date) THEN
DELETE FROM Sessions WHERE sessid=p_sessid;
SET res=1;
ELSE
UPDATE Sessions SET expiry_date=DATE_ADD(NOW(), INTERVAL 15 MINUTE) WHERE customer_id=v_customer_id;
SET res=0;
END IF;
END IF;
END
Can anyone tell, why it always return 1, what means that user is not logged anymore? I were checking manually expression UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(v_date), and it gives me 0 in response, so? Whats going on?
Thanks in advance,
Marcin
The first IF statement should read like this:
UNIX_TIMESTAMP(NOW()) > UNIX_TIMESTAMP(DATE_ADD(v_date, INTERVAL 15 MINUTE))
or else NOW will always be greater than the last login date.
You may rewrite/optimize your procedure to function. For example -
CREATE FUNCTION `isLogged`(IN p_sessid VARCHAR(32))
RETURNS INT
BEGIN
DELETE FROM Sessions WHERE sessid = p_sessid AND v_date <= NOW() - INTERVAL 15 MINUTE;
IF ROW_COUNT() > 0 THEN -- check how many rows were deleted
RETURN 1;
ELSE
UPDATE Sessions SET expiry_date = NOW() + INTERVAL 15 MINUTE WHERE customer_id = v_customer_id;
IF ROW_COUNT() > 0 THEN -- check how many rows were updated
RETURN 0;
END IF;
END IF;
RETURN 3;
END
Also, you can try to debug your code to understand the error.
Omg, that was very stupid.
There was a type mismatch. v_date type was a DATE, and this is just a day! Like 2011-12-14.
Solution:
change DATE -> DATETIME.
And now everything works good.
Anyway, thank you for answers.

MYSQL Procedures run, but return 0 rows affected

I call a procedure, it runs, and the console says "0 rows affected". Is this normal behavior for a MySQL procedure ?
The procedures are clearly doing what they should. One procedure has 2 insert statements, another has an insert and update statement, and I've seen the results with my own eyes. There are indeed rows being affected.
I'm not sure that I would use that result later on, but it seems like I'd want to get an accurate response from my DB whether or not anything was updated, especially when its expected.
Thoughts ?
MySQL 5.5 if it matters, and the procedures use transactions over auto-committed statements.
CREATE DEFINER=`root`#`localhost` PROCEDURE `create_issue`(user_id SMALLINT, title varchar(255), body LONGTEXT)
BEGIN
DECLARE MYUSERID SMALLINT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
START TRANSACTION;
INSERT INTO tracker.issue (user_id, title, body, creation_date, last_mod_date) values (user_id, title, body, CURDATE(), CURDATE());
UPDATE user_activity SET last_new_issue = CURDATE(), post_count = post_count + 1 WHERE user_activity.user_id = user_id;
COMMIT;
END
Edited to show the actual query. Also I've been searching and as best as I can tell this is a known issue over a year and a half old. So I suppose this one can be closed.
the "0 rows affected" response is for the last statement executed in the stored procedure.
usually i track the number of rows effected by manually counting them into session variables
DELIMITER $$
CREATE PROCEDURE `create_issue`(user_id SMALLINT, title varchar(255), body LONGTEXT)
BEGIN
DECLARE MYUSERID SMALLINT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
SET #inserted_rows = 0;
SET #updated_rows = 0;
START TRANSACTION;
INSERT INTO tracker.issue (user_id, title, body, creation_date, last_mod_date) values (user_id, title, body, CURDATE(), CURDATE());
SET #inserted_rows = ROW_COUNT() + #inserted_rows;
UPDATE user_activity SET last_new_issue = CURDATE(), post_count = post_count + 1 WHERE user_activity.user_id = user_id;
SET #updated_rows = ROW_COUNT() + #updated_rows;
COMMIT;
END
$$
the session variables can then be read after the SP was executed.
i am not sure if it is possible to override the response from the ROW_COUNT() function by setting a value to a variable,
I guess this is a reported bug. May be a good question for MySQL mailing list/forum. http://bugs.mysql.com/bug.php?id=44854
Something definitely isn't right. A sproc should still return the number of rows affected if there are multiple inserts occurring. I'm using the same version of MySQL and this works fine for me.
Are you sure you're not doing something like that
...SET col1='value1' AND col2='value2'...
instead of
...SET COL1='value1', col2='value2'...
Could you post your stored procedure?