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

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.

Related

Mysql function, return more than one row

I have build a little mysq function who should check is the users in my table are still vaid, the have got a row validfrom and validto and my function should check if the validto date is older than now.
CREATE DEFINER=`root`#`localhost` FUNCTION `is_valid_user`(username
VARCHAR(10)) RETURNS tinyint(1)
BEGIN
DECLARE valid_from, valid_to datetime;
SELECT
Gültig_von, Gültig_bis
INTO valid_from , valid_to FROM
Benutzer
WHERE
Benutzername = username;
IF valid_from <= now() and valid_to > now() THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END if;
END
if i want to proceed this function i get the error message: Result consisted of more than one row.
As per your posted error message your query return more than one rows so just add "LIMIT 1" after where clause so you will have only one row at each time if it exists.

MySQL Stored procedure SELECT var wrong value after INSERT

I have a problem on MySQL stored procedure, already did another logic with IF THEN ELSE, but I still have problems which I cant understand...
The procedure consists on two user inputs: user_id and meet_id. The procedure define a variable called 'ue' which stores result of a bunch of validation (if user exists, if event exists, if event date is still valid, etc.).
After that, it does INSERT and UPDATE some data on multiple tables in IF THEN ELSE selector, and SELECT 1 (or 0) AS result depending of validation.
But my problem is: it always return me 0 as 'result', as if my validation variable was 0 when I do INSERT... And there is where things get weird, if I remove the INSERT [...]; line of the code, it returns me the value of validation correctly (1 or 0).
The code of the procedure is this one:
CREATE DEFINER=`nwouserf`#`localhost`
PROCEDURE `join_event`(IN `user_id` BIGINT(64), IN `event_id` INT)
NOT DETERMINISTIC MODIFIES SQL DATA SQL SECURITY DEFINER
begin
DECLARE ue INT;
SET ue = EXISTS(SELECT 1 FROM users WHERE fb_uid=user_id)
AND EXISTS(SELECT 1 FROM meetup WHERE meet_id=event_id)
AND EXISTS(SELECT 1 FROM meetup WHERE date > NOW() AND meet_id = event_id)
AND EXISTS(SELECT 1 FROM meetup WHERE meet_id = event_id AND participants <= max_participants)
AND NOT EXISTS(SELECT 1 FROM meetup_participation WHERE fb_uid = user_id AND meet_id = event_id);
IF ue = 1 THEN
INSERT INTO meetup_participation (fb_uid, meet_id) VALUES (user_id, event_id);
UPDATE users SET events_participated = events_participated + 1 WHERE fb_uid=user_id;
UPDATE meetup SET participants = participants + 1 WHERE meet_id=event_id;
SELECT 1 AS result;
ELSEIF ue = 0 THEN
SELECT 0 AS result;
ELSE
SELECT null AS result;
END IF;
end
Thanks in advance!
I have been stuck on this for a while now, and can not figure out why.
You should define OUT parameter. Add
", OUT result INT"
immediately after the last IN parameter.

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 stored function giving different results than original query (some conditions are not working)

I have a weird problem in mysql stored function. The function is returning different result than if I run the query alone. Here is my function:
DELIMITER $$
CREATE DEFINER=`admin`#`%` FUNCTION `getARetention`
(appID int(10), currentDate DATE)
RETURNS int(11)
READS SQL DATA
DETERMINISTIC
BEGIN
RETURN
(SELECT count(DISTINCT UserId)
FROM
Session
WHERE (Date(Started) = currentDate AND AppId=appID));
END
Here is how I call it:
SELECT getARetention(5,DATE('2013-04-03'));
Here is the alone query:
SELECT count(DISTINCT UserId)
FROM
Session
WHERE (Date(Started) = DATE('2013-04-03') AND AppId=5)
The function is returning 2502 which is wrong. Alone query is returning 5, which is correct. Also, if I delete "AND AppId=5" from alone query then it return 2502, which means in the stored function that condition is not working.
Anyone have any idea why? I haven't used mysql for a while, so I am probably missing something.
MySQL cannot distinguish between the variable name and the column name here.
Name the variable otherwise:
DELIMITER $$
CREATE DEFINER=`admin`#`%` FUNCTION `getARetention`
(
_appID int(10),
_currentDate DATE
)
RETURNS int(11)
READS SQL DATA
DETERMINISTIC
BEGIN
RETURN (
SELECT COUNT(DISTINCT UserId)
FROM Session
WHERE appId = _appId
AND started >= _currentDate
AND started < _currentDate + INTERVAL 1 DAY
);
END
$$

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.