MySQL If Else Statement Error - mysql

For the life of me I cannot work out why this MySQL code doesn't work.
The aim is to check the credentials and if they exist, return the ID and if they don't then insert them and return the ID;
SET #Found = 0;
SELECT Id INTO #Found FROM Users WHERE Users.Username = "testAccount" AND Users.Email = "test#email.com";
IF #Found > 0 THEN
SELECT #Found;
ELSE
INSERT INTO Users VALUES (DEFAULT, "testAccount", "test#email.com");
SELECT LAST_INSERT_ID();
END IF;
Thank you for the help.

The MySQL if statement only works in stored programs -- stored procedures, functions, and triggers.
That is what the first line of the documentation means:
The IF statement for stored programs implements a basic conditional construct.
So, your statement is syntactically invalid.
In addition, you have a syntax error in your select:
SELECT Id INFO #Found
FROM Users
WHERE Users.Username = "testAccount" AND Users.Email = "test#email.com";
What is being selected? Should you have commas? Or do you mean:
SELECT #Found := id
. . .

Related

if condition inside a sql query

following is a part of my stored proceedure im using it to extract data from my db.
query
BEGIN
SET #sqlstring = CONCAT("SELECT b.ID, c.name, c.accountID,, b.total_logs, a.time_start, a.time_end ,COUNT(a.id) AS number_of_users
FROM ",logtable," a INNER JOIN users b on a.ID = b.ID INNER JOIN accounts c on b.accountID = c.accountID
GROUP BY ID;");
PREPARE stmt FROM #sqlstring;
EXECUTE stmt;
END
At times in the db, the logtable(table is passed in a variable like logtable_1, logtable_2 .... ) can be non existent, currently when the perticuler table is missing it crashes and throws an error because a.time_start, a.time_end cannot have values without the log table.
but what i want is just to assign NULL on values a.time_start, a.time_end without throwing an error,
So can any body tell is there a way i could modify this code like
BEGIN
if logtable exists
\\ the query
else
\\ the query
END
Find existence of the table by querying information_schema.tables. If it returns a count equals to 1 then you can proceed executing your query on the table. Otherwise go with your Else block.
Sample:
declare table_exists int default 0;
select count(1) into table_exists
from information_schema.tables
where table_schema='your_table_schema_name'
and table_name = 'your_table_name';
if table_exists then
-- do something
else
-- do something else
end if;

mysql return results from update

I want to select a bunch of rows from a mysql database and update the viewed attribute of those once selected (this is a kind of 'I have read these' flag).
Initially I did something like this:
update (
select a, b, c
from mytable
where viewed = '0'
)
set viewed = '1';
This selects the rows nicely and updates their viewed attribute as required. But it does not return the selected rows from the subquery.
Is there a clause I can add, or perhaps I need to store the subquery, etc...? I did consider a transaction but I ended up with the same problem. I have not tried a stored procedure...
Please can someone advise / point me in the right direction on how to do what I do above but in addition return the selected tables from the subquery?
Thanks in advance.
Update:
As pointed out by #Barmar, #a_horse_with_no_name, #fancyPants and #George Garchagudashvil...
In MySQL you have to use two statements to select and update, and not a nested statement as in my initial post, if you want to return the selected rows.
e.g.
begin;
select a, b, c
from mytable
where viewed = '0';
update mytable
set viewed = '1'
where viewed = '0';
commit;
thanks guys.
I would create a simple function:
DELIMITER $$
DROP FUNCTION IF EXISTS `mydb`.`updateMytable`$$
CREATE
/*[DEFINER = { user | CURRENT_USER }]*/
FUNCTION `mydb`.`updateMytable`() RETURNS TEXT
BEGIN
SET #updated := '';
UPDATE mytable
SET viewed = 1
WHERE viewed = 0
AND (
SELECT #updated := CONCAT_WS(',', #updated, id)
) != ''
;
RETURN TRIM(LEADING ',' FROM #updated);
END$$
DELIMITER ;
which updates tables and returns concatenated ids.
From php you call this:
SELECT mydb.updateMytable()
and you get ids in a stirng: 1,2,7,54,132 etc...
Update:
my function is returning string containing comma separated ids:
'1,5,7,52,...' these ids are only which would have been updated during the function call,
better php-mysql example would be (you may and would use PDO):
$query = "SELECT mydb.updateMytable()";
$res = mysql_query($query);
$arr = mysql_fetch_array($res);
$ids = explode(',', $arr[0]);
// now you can do whatever you want to do with ids
foreach ($ids as $id)
{
echo "Hoorah: updated $id\n";
}
also remember to change mydb and mytable according to your database names
Final
because you need more complex functionality, simply run two query:
First run:
SELECT a, b, c
FROM mytable
WHERE viewed = 0
Next run:
UPDATE mytable
SET viewed = 1
WHERE viewed = 0

mysql update column then select updated value

I have a table like this
tbl_user
id
user_id
amount
first i want to update a row based on id
$amount = 123; // dyanamic value
$sql = "UPDATE tbl_user SET amount=amount-'$amount' WHERE id='$id' LIMIT 1 ";
now i want to get updated value of amount column i have applied this sql
$sql = "SELECT amount FROM tbl_user WHERE id='$id' LIMIT 1 ";
my question is can i combine both of above sql or any single query to achieve above task?
The best you could imitate is to use two lines of queries, probably using a variable like:
UPDATE tbl_user SET
amount = #amount := amount-'$amount'
WHERE id='$id' LIMIT 1;
SELECT #amount;
The best you could do then is to create a Stored Procedure like:
DELIMITER //
CREATE PROCEDURE `return_amount` ()
BEGIN
UPDATE tbl_user SET
amount = #amount := amount-'$amount'
WHERE id='$id' LIMIT 1;
SELECT #amount;
END //
And then call Stored Procedure in your PHP.
Note: PostgreSQL has this kind of option using RETURNING statement that would look like this:
UPDATE tbl_user SET amount=amount-'$amount'
WHERE id='$id' LIMIT 1
RETURNING amount
See here
A function can do this easily. It sounds like you want to limit how many times your code connects to the database. With a stored function or procedure, you are only making one connection. Yes, the stored function has two queries inside it (update then select), but these are executed on the server side without stopping to do round trips to the client.
http://sqlfiddle.com/#!2/0e6a09/1/0
Here's my skeleton of your table:
CREATE TABLE tbl_user (
id VARCHAR(100) PRIMARY KEY,
user_id VARCHAR(100),
amount DECIMAL(17,4) );
INSERT INTO tbl_user VALUES ('1', 'John', '100.00');
And the proposed function:
CREATE FUNCTION incrementAmount
(p_id VARCHAR(100), p_amount DECIMAL(17,4))
RETURNS DECIMAL(17,4)
BEGIN
UPDATE tbl_user
SET amount = amount + p_amount
WHERE id = p_id;
RETURN (SELECT amount FROM tbl_user WHERE id = p_id);
END
//
Then you just run one query, a SELECT on the function you just created:
SELECT incrementAmount('1', 5.00)
The query result is:
105
It is not possible with a single query, but you can combine multiple commands into a script and execute them with a single request to the database server.
Run this script:
"UPDATE tbl_user SET amount=amount-'$amount' WHERE id='".$id."';SELECT amount FROM tbl_user WHERE id='".$id."'; "
Also, you might want to check whether $id is a number, as I do not see a protection against SQL injection inside your code. SQL injection is a serious threat, you would do better to prepare and protect yourself against it.
We can also use:
UPDATE tbl_user SET id = LAST_INSERT_ID(id), amount = 2.4,user_id=4 WHERE id = 123;
// SELECT
$id =SELECT LAST_INSERT_ID();
SELECT amount,user_id FROM tbl_user WHERE id = $id LIMIT 1
Here would be the procedure
CREATE PROCEDURE UpdateAndSelect
(
#amount MONEY,
#id INT
)
AS
BEGIN
UPDATE tbl_user
SET amount = #amount
WHERE id = #id
LIMIT 1
SELECT amount
FROM tbl_user
WHERE id = #id
LIMIT 1
END
GO
You would call this stored procedure by setting your variables (#amoutn and #id) and then calling:
exec UpdateAndSelect
Hope this helps solve your problem

mysql trigger with select from database and update a column

I have this trigger. If the incoming log agrees with input filter, than is not saved into database. But, I want to keep number of "hits" of each Primitive_filter. I have a column named hit_rate, which is int(30). Is there some way how to do that? Maybe specific error? Or sth else? Thx for help.
UPDATE Primitive_filters SET hit_rate = hit_rate + 1 where Primitive_filters.id = ???;
trigger
delimiter //
CREATE TRIGGER inputFilter
before insert
on Logs
for each row
begin
declare msg varchar(255);
IF (SELECT COUNT(*) FROM Primitive_filters, Primitive_in_filter, Filters WHERE
Filters.name = "input" AND Filters.id = Primitive_in_filter.id_filter AND Primitive_in_filter.id_primitive = Primitive_filters.id AND
(Primitive_filters.id_host LIKE CONCAT('%',(SELECT host FROM Hosts WHERE id = new.id_host),'%') OR Primitive_filters.id_host IS NULL) AND
(Primitive_filters.facility LIKE CONCAT('%',new.facility,'%') OR Primitive_filters.facility IS NULL) AND
(Primitive_filters.priority LIKE CONCAT('%',new.priority,'%') OR Primitive_filters.priority IS NULL) AND
(Primitive_filters.program LIKE CONCAT('%',new.program,'%') OR Primitive_filters.program IS NULL) AND
(new.msg REGEXP Primitive_filters.msg OR Primitive_filters.msg IS NULL)) > 0 THEN CALL raise_error; END IF;
END //
delimiter ;
This is NOT the answer to your question.
It's only a hint how to fix a potentially serious performance problem in your code.
Don't use this:
IF (SELECT COUNT(*) FROM ... giant query ...) > 0
THEN CALL raise_error;
END IF;
Use this instead:
IF EXISTS (SELECT 1 FROM ... giant query ...)
THEN CALL raise_error;
END IF;
The former condition calculates a count ... it must read all rows returned by the query
If the query returns billion rows, it must reads them all --> because you asked give me a count of rows.
Then, after the query return the count, there is a check: if the query returns at least one row, then do something.
The latter condition stops executing the query when the query returns first row, saving time and resources.

MySQL 5.5 Query Based on IF statement

I've been battling with this for too long so I'm here to ask for help...
I have a MySQL stored procedure that I want to do the following:
given an 'id' and a 'username' for a given record
if id does not exist in table then create record
else if id exists and username is not the same as what exists then update record
else do nothing
I've tried the following:
BEGIN
DECLARE doCreate INT;
DECLARE doUpdate INT;
SELECT COUNT(*) INTO doCreate FROM app_user WHERE id=1;
IF (doCreate > 0) THEN
SELECT COUNT(*) INTO doUpdate FROM app_user WHERE id=1 AND username='other';
END IF
IF(doCreate = 0) THEN ---SYNTAX ERROR ON THIS LINE---
SELECT 'CREATE';
ELSE IF(doUpdate = 0) THEN
SELECT 'UPDATE';
ELSE
SELECT 'NOTHING';
END IF
END
I've also tried replacing the if-elseif-else block with a case statement but get the same result...
CASE ---ERROR ON THIS LINE---
WHEN doCreate = 0 THEN
SELECT 'CREATE';
WHEN doUpdate = 0 THEN
SELECT 'UPDATE';
ELSE
SELECT 'NOTHING';
END
I seem to get a syntax error on anything that comes after the first END IF, so that's the first problem that occurs...
Any help would be appreciated - I'm sure there's a better way to do this.
I believe you'll need to terminate the END IFs with ;, and internally ELSEIF should be one word. Otherwise, another END IF is needed, but not found.
IF (doCreate > 0) THEN
SELECT COUNT(*) INTO doUpdate FROM app_user WHERE id=1 AND username='other';
END IF; /* terminate with ; */
IF(doCreate = 0) THEN
SELECT 'CREATE';
ELSEIF(doUpdate = 0) THEN
SELECT 'UPDATE';
ELSE
SELECT 'NOTHING';
END IF; /* terminate with ; */
Look over the MySQL IF/ELSE syntax reference for various usage examples.