I want to run an Update where the WHERE statement consists of 2 SELECTS, is this at all close to how you do that?
UPDATE Requests SET Response=1 WHERE
sender=SELECT userID FROM Users WHERE Username=?) and
Reciever = SELECT userID FROM Users WHERE Username=?
Thank!
You're missing parentheses, that's all.
UPDATE Requests SET Response=1 WHERE
sender = (SELECT userID FROM Users WHERE Username=?) and
receiver = (SELECT userID FROM Users WHERE Username=?);
Related
I've created a web app that lets you send money to other people (like paypal) for an University project.
For the send money webpage there's a form where an user can choose the money receiver's ID and the amount to send.
The system works with these queries:
SET #moneytosend= ? ; //amount to send
START TRANSACTION;
UPDATE users SET balance= balance- #moneytosend WHERE id = ?; //sender's ID
UPDATE users SET balance= balance+ #moneytosend WHERE id = ?; //receiver's ID
COMMIT WORK;
The problem is when the user inserts a non existing ID and the query is still executed, effectively removing money from the sender.
I'm sorry if my english is not perfect, and sorry again if there are any formatting errors.
One method is to check that the users exist in the update queries:
UPDATE users JOIN
(SELECT ? as sender_id, ? as receiver_id
) uu
ON u.id IN (uu.sender_id, uu.receiver_id)
SET balance = balance + (CASE WHEN u.id = uu.receiver_id THEN #moneytosend ELSE - #moneytosend)
WHERE EXISTS (SELECT 1 FROM users u2 WHERE u2.id = uu.sender_id) AND
EXISTS (SELECT 1 FROM users u2 WHERE u2.id = uu.receiver_id);
This logic combines the queries into a single query and still allows you to input only two parameters.
The problem is caused in the 1st update statement and it can be solved by adding EXISTS as a condition:
update users
set balance = balance - #moneytosend
where
balance >= #moneytosend
and
id = ? <-- sender id
and
exists (
select 1 from (select * from users where id = ? <-- receiver id
) t);
See the demo
As suggested by Raymond Nijland, do an extra check so that balance does not get a negative value.
I'm wondering if it's possible to delete columns using some aggregate functions (found here: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html)
For example say I wanted to delete the last user from my database, it'd be easy if I could just run:
delete from user where id = MAX(id);
But running this will give me the following error:
ERROR 1111 (HY000): Invalid use of group function
Is this possible with mysql or not?
You have to use a query like this:
delete from user where id = (select id
from (select MAX(id) as id
from user) as t)
Try with another select as follows:
delete from user where id = (SELECT MAX(id) FROM user);
you could try something like:
delete from user where id = (select max(id) from user);
As another option, is to use temporary variable:
set #id = (select max(id) from user);
delete from user where id = #id;
update accounts set password=(select password from accounts where name='joongsu')
where id=(select accountid from characters where name='Nobless')
it doesn't work with error message "You can't specify target table 'accounts' for update in FROM clause"
Why doesn't it work? select queries in above only return 1 row.
Perhaps you should try this one:
UPDATE accounts
SET accounts.password =
(
SELECT something.password
FROM (SELECT * FROM accounts) AS something
WHERE something.name='joongsu'
)
WHERE accounts.id=(SELECT accountid FROM characters WHERE name='Nobless');
It's a hack, but I tested it and it works on my test data. For some reason MySQL doesn't allow using the same table in inner queries as the one being updated.
UPDATE
accounts AS account_to_be_updated
JOIN
characters
ON characters.accountid = account_to_be_updated.id
AND characters.name = 'Nobless'
CROSS JOIN
( SELECT password
FROM accounts
WHERE name = 'joongsu'
) AS existing_account
SET
account_to_be_updated.password = existing_account.password ;
Is this what you looking out for?
;with CTE as
(
select password from accounts where name='joongsu' limit 1
)
update accounts set password= CTE.password
where id in
(select accountid from characters where name='Nobless')
I have a database table called private_message. I run the following query on it to get a result of all the user id's that one user (47762) sent a private message to:
SELECT `to_id` FROM `private_message` WHERE `from_id` = 47762
I now want to use this query or some other way on another table called users to get the email address of all the users who received the email address from 47762.
I tried the following:
SELECT * FROM `users` WHERE `sid` = (SELECT `to_id` FROM `private_message` WHERE `from_id` = 47762)
In the above query, users.sid is the same as private_messages.to_id
I got the error #1242 - Subquery returns more than 1 row.
What I want is to get the email addresses of users that were sent a private message from user 47762 but the users table.
I'm a novice with MYSQL so would appreciate some help here.
Thanks.
You should use IN instead od = since you can't compate (=) sid to multiple values.
SELECT * FROM `users` WHERE `sid` IN (SELECT `to_id` FROM `private_message` WHERE `from_id` = 47762)
Anyway you can do a JOIN here instead:
SELECT u.* FROM `users` AS u
JOIN `private_message` AS pm ON u.`sid` = pm.`to_id`
WHERE pm.`from_id` = 47762
It will be more efficient in most cases.
I have a table that stores users. Every user has an ID, a Name and an Access Level. The three possible Access Levels are Administrator, Manager and Simple User.
What I want is to conditionally select from this table based on the Access Level value. I demonstrate the logic bellow:
If user is Administrator, then select all users (Administrators, Managers, Simple Users)
Else if user is Manager select all Managers and all Simple Users
Else if user is Simple User select only himself
Is that possible?
Providing Access Level is an integer that increases with the actual access level:
Administrator = 3
Manager = 2
User = 1
Then
SELECT * FROM USERS
WHERE ACCESS_LEVEL <= (SELECT ACCESS_LEVEL FROM USERS WHERE ID = #ID)
And just switch the less than sign to greater than if it is opposite.
Applies to SQL-server
EDIT: To get what you want you can use something like this:
SELECT id,name FROM users where ID = #id
UNION DISTINCT
SELECT id, name from users where access_level <=
(select case when access_level = 1 then 0 else access_level end
from users where id = #id)
With a query like this you will select all users at your current access_level or lower.
Only exception if your access_level is 1 (e.g. normal user), then only your own user is selected.
In Oracle the concept is known as Row Level Security. See articles such as this or this to get you started.
You can use following code
If(access_level=='administrator'){ str query = 'select * from users';}else if(access_level=='manager'){ str query = 'select * from users where access_level!="administrator"'; }else{ str query = 'select * from users where access_level="users"'; }
Might be a little overkill, but the following stored procedure can be used to achieve what you want:
DROP procedure IF EXISTS `listAccessibleUsers`;
DELIMITER $$
CREATE PROCEDURE `listAccessibleUsers`(IN user_id INT)
BEGIN
DECLARE u_access_level INT;
-- Select the user access level
SELECT access_level
FROM users
WHERE users.id = user_id
INTO u_access_level;
-- Result for simple users
IF u_access_level = 1 THEN
SELECT id, name, access_level
FROM users
WHERE users.id = user_id;
-- Result for admistrators and managers
ELSE
SELECT id, name, access_level
FROM users
WHERE access_level <= u_access_level;
END IF;
END$$
DELIMITER ;
Example calling code:
CALL listAccessibleUsers(200);