Limiting Access by Permission - sql

thanks for viewing this. I have a db that has users, roles & user_roles.
What I am trying to achieve is a login that will select users who have Admin or Associate permissions. The login then uses name and password to permit access.
My SQL syntax thus far is -
SELECT * FROM users
LEFT JOIN ON user_roles
ON user.id=user_roles.userid AND roleid IN (Administrator, Associate)
WHERE username = '$username' AND password = '$password'";
I am not sure where I am going wrong.
Thanks in advance for your help.

Try replacing "LEFT JOIN" by "INNER JOIN"

Here's how I'd write the query:
$stmt = $pdo->prepare("
SELECT (u.password = :password) AS password_is_correct,
(r.roleid IS NOT NULL) AS role_is_authorized
FROM users u
LEFT JOIN ON user_roles r
ON u.id=r.userid AND r.roleid IN (Administrator, Associate)
WHERE u.username = :username");
$stmt->execute(array(":password"=>$password, ":username"=>$username));
This allows you to distinguish between the three conditions: (1) username does not exist, (2) password is wrong, or (3) role is not authorized.
PS: Should "Administrator" and "Associate" be quoted or something? The way you're using them, they look like identifiers rather than values.

Related

Postgres sql to retrieve data based on aggregation and bool_or()

I have User to Role table with Many to Many relation. I need to retrieve all the roles which are not privileged(false) to any VIP users or it should be Privileged only to VIP users.
I came up with a query using aggregation and bool_or() but my result set has opt4 role. opt4 role should be ignored since its Privileged to a non- vip user (user2 - line item 6)
select
r.rolename
from
pam."role" r
join pam.user_role ur on
r.id = ur.role_id
join pam.user u on
ur.user_id = u.id
group by
r.rolename,
u.vip_flag
having
(not bool_or(ur.privileged)) or u.vip_flag=true;
Any help is much appreciated
Sounds like you simply have to add it to the HAVING clause:
HAVING ((not bool_or(ur.privileged)) OR u.vip_flag=true)
AND rolename <> 'opt4'

SQL - Select ids that appear at least once in other table

I'm trying to get a list of Users that appear at least once in OtherTable. The following is my very inefficient HQL query using Grails. In general, there will only be at most a few hundred users that will be run in the query but potentially a million references to those users in OtherTable.
List<User> users = User.executeQuery("select user " +
"from User as user where user.id = any(" +
"select otherTable.user.id from OtherTable as otherTable)")
How can I make this query more efficient?
This SQL might be more effcient,
select distinct u.id from user as u
inner join other_table ot
on u.id = ot.id
Here is an HQL,
select distinct user
from User as user
inner join user.otherTable as ot
Using Criteria API
User.createCriteria().listDistinct {
createAlias("otherTable","ot")
eq('id','ot.id')
}
Both the above would require proper mapping of your domain classes. In case, you don't have that, OtherTable, mapped in User. Try this,
select distinct user from User user, OtherTable ot
where user.id = ot.user_id
You may have noticed that we're avoiding full table scans here, completely; and it's a single query -- unlike the one you posted, which uses a subquery. Joining both entities/tables with id should be more efficient -- assuming id columns are indexed.
Try the following query:
List<User> users = User.executeQuery("select user " +
"from User as user where" +
"user.id in (select distinct otherTable.user.id from OtherTable as otherTable)")
Hope it will help!

Select a user by their username and then select data from another table using their UID

Sorry if that title is a bit convoluted... I'm spoiled by an ORM usually and my raw SQL skills are really poor, apparently.
I'm writing an application that links to a vBulletin forum. Users authenticate with their forum username, and the query for that is simple (selecting by username from the users table). The next half of it is more complex. There's also a subscriptions table that has a timestamp in it, but the primary key for these is a user id, not a username.
This is what I've worked out so far:
SELECT
forum.user.userid,
forum.user.usergroupid,
forum.user.password,
forum.user.salt,
forum.user.pmunread,
forum.subscriptionlog.expirydate
FROM
forum.user
JOIN forum.subscriptionlog
WHERE
forum.user.username LIKE 'SomeUSER'
Unfortunately this returns the entirety of the subscriptionlog table, which makes sense because there's no username field in it. Is it possible to grab the subscriptionlog row using the userid I get from forum.user.userid, or does this need to be split into two queries?
Thanks!
The issue is that you are blindly joining the two tables. You need to specify what column they are related by.
I think you want something like:
SELECT * FROM user u
INNER JOIN subscriptionlog sl ON u.id = sl.userid
WHERE u.username LIKE 'SomeUSER'
select * from user u JOIN subscriptions s ON u.id = s.id where u.username = 'someuser'
The bit in bold is what you want to add, it combines the 2 tables into one that you return results from.
try this
SELECT
forum.user.userid,
forum.user.usergroupid,
forum.user.password,
forum.user.salt,
forum.user.pmunread,
forum.subscriptionlog.expirydate
FROM
forum.user
INNER JOIN forum.subscriptionlog
ON forum.subscriptionlog.userid = forum.user.userid
WHERE
forum.user.username LIKE 'SomeUSER'

Problems with joining two tables in SQL

I have two tables. user(user_id, username, password, age) and comment(comment_id, comment, user_id(foreign key)).
I'm trying to get username from user, using the user_id provided in comment.
My query looks like this:
$sql = "SELECT username FROM user WHERE user_id = (SELECT user_id FROM comments)";
I'm getting null. Is my brain working poorly or is it something else I messed up?
I just want to display all comments after each other, with the username before it.
Use IN instead of "=" .
SELECT username FROM user WHERE user_id IN (SELECT user_id FROM comments);
OR you can use a proper join, something like:
SELECT username FROM user,comments WHERE user.user_id = comments.user_id
That's not a join - a join would be:
$sql = "SELECT username FROM user u JOIN comments c ON u.user_id = c.user_id";
When you use a subquery with =, the subquery must return one value. To show all related records in a related table, use JOIN instead.

MySql If statements

I have a simple table that logs simple events an administrator does. Nothing complicated.
One of the columns is userid, so I can reference the user's name from the users table:
SELECT u.username FROM `users` u, `history` h WHERE u.userid = h.userid
My issue is that the internal system also logs events (just like a user), but there is no userid related to the internal system. It is simply logged as zero, in the record.
Is there a way to modify the query to reflect this? I've tried a LEFT JOIN, but that doesn't let me specify "system" as the username. The other thing i can do is enter a new user into the user's table, and call it "Internal System". But I really don't want to do that.
Is it possible to do this from the query level?
Use:
SELECT COALESCE(u.username, 'SYSTEM') AS username,
FROM HISTORY h
LEFT JOIN USERS u ON u.userid = h.userid
COALESCE will return the first non-NULL value, so if you LEFT JOIN onto USERS and username is NULL--then "system" or whatever you prefer will appear.