Using CASE for multiple conditions in MySQL query - mysql

Here's a MySQL query which I am using to get the roles for a user along with the comments.
But there are some cases where a user can be admin for multiple cases, in which case this query doesn't work.
This only shows up the first role of the user as an admin.
What would be the right way to use case for this situation?
select u.fullname, c.comment,
case when u.n_admin = 1 then 'n_admin'
when u.c_admin = 1 then 'c_admin'
when u.t_admin = 1 then 't_admin'
when u.i_admin = 1 then 'i admin'
end as role
from comments c
left join users u on u.id = c.user_id
where c.id= 34

As stated by #Matt-Spinks, your query is wrapping all the roles into one column.
Since, based on your query, user can have multiple independent admin roles (u.n_admin, u.c_admin etc), then you should report each column separately.
Since each only can be true or false, I would do it with IF() instead of CASE():
SELECT u.fullname, c.comment,
IF(u.n_admin = 1,'Yes','No') AS 'has n_admin role',
IF(u.c_admin = 1,'Yes','No') AS 'has c_admin role',
IF(u.t_admin = 1,'Yes','No') AS 'has t_admin role',
IF(u.i_admin = 1,'Yes','No') AS 'has i_admin role'
FROM comments c
LEFT JOIN users u on u.id = c.user_id
WHERE c.id= 34

Related

mySql query - web file sharing program

Here is my code. It is supposed to select the name of the person "to_whom" I'm sharing a particular file,
and the whole thing needs to return back the user_id (u_c.to_whom) and the user_name,
so I can populate my friends list with a checkboxe next to each other, that once clicked,
will share (save into a DB table) that particular file to a specific person.
This is from a web-app where users share files among each other.
SELECT u_c.to_whom, u.user_name
FROM files f
LEFT JOIN users_connections u_c
ON (u_c.who = :user_id OR u_c.to_whom = :user_id) AND u_c.friends = "Y"
LEFT JOIN users u
ON u.user_id = u_c.to_whom
WHERE f.file_id = 90
In the table files we have
file_id, file_name, file_desc, etc...
In the table users connections
id, who, to_whom, friends
1 1 4 Y
meaning that user 1 had initiated a friendship to user 4 and "Y" means the friendship is TRUE (N = still pending)
And in users we have
user_id, user_name
1 Jack
I cannot seem to get this working for some reason.
Can any advanced user help me out?
Thanks a bunch!!
I found the answer to this code. It is an essential code if you want to build a sharing file system.
$query_list_count = "SELECT COUNT(user_id)
FROM users_connections u_c
LEFT JOIN users u
ON u.user_id = u_c.who OR u.user_id = u_c.to_whom
LEFT JOIN files f
ON f.file_id = :file_id
WHERE (u_c.who = :user_id OR u_c.to_whom = :user_id AND friends = :friends)
GROUP BY u.user_id
";
$result_list_count = $db->prepare($query_list_count);
$result_list_count->bindValue(':user_id', $_SESSION['user_id'], PDO::PARAM_INT);
$result_list_count->bindValue(':friends', "Y", PDO::PARAM_STR);
$result_list_count->bindValue(':file_id', $file_id, PDO::PARAM_INT);
$count_ = $result_list_count->fetchColumn();

How to use IF statement before FROM Clause

I have three tables:
Users and companies can add feeds. The flag columns means
0 = user
1 = company
How can I perform this SQL query correctly? Thanks in advance for your help!
SELECT
feeds.feeds_id,
feeds.title
IF feeds.flag = 0
FROM user
INNER JOIN
feeds.user_or_company = user.user_id
ELSEif feeds.flag = 1
INNER JOIN
feeds.user_or_company = company.company_id
One way to solve this is to LEFT JOIN to both user and company tables and then select the appropriate name value based on feeds.flag:
SELECT f.feeds_id, f.title,
CASE f.flag WHEN 0 THEN u.name ELSE c.name END AS name
FROM feeds f
LEFT JOIN user u ON u.user_id = f.user_or_company
LEFT JOIN company c ON c.company_id = f.user_or_company
Output (for your sample data)
feeds_id title name
2 This title added twice by user User-1
3 This title added by company Company-2
1 This title added by user User-3
Demo on dbfiddle

Laravel newbie and external (Moodle) database

I'm trying to read from external Moodle database in Laravel Eloquent, to display all users that are teachers, and put them into a dropdown list inside a form.
I have Teacher model containing:
class Teacher extends Eloquent
{
protected $guarded = ['id'];
protected $connection = 'moodle';
protected $table = 'mooddle_user';
public function Task()
{
return $this->hasMany('Task', 'id');
}
}
I can return all users just simply by using lists method, but the problem is that the info whether the user is indeed a teacher or not is not stored in this table. Instead I have to use a few JOIN commands to retrieve teachers.
I'm wondering how can I execute this command inside the model, to use it simply in the dropdown of the Task view. Task model, accepts teacher_id - foreign key.
SQL:
SELECT DISTINCT u.firstname, u.lastname
FROM moddle_user u
JOIN moddle_user_enrolments ue ON ue.userid = u.id
JOIN moddle_enrol e ON e.id = ue.enrolid
JOIN moddle_role_assignments ra ON ra.userid = u.id
JOIN moddle_role r ON r.id = ra.roleid AND r.shortname = 'editingteacher'
WHERE e.status = 0 AND u.suspended = 0 AND u.deleted = 0
AND (ue.timeend = 0 OR ue.timeend > NOW()) AND ue.status = 0
I tried running it as Raw query through model but no luck, because it locks inside a moddle_user data table and so I am unable to use JOIN with other tables.
I know I could've tried to create 4 additional eloquent models, but since I only need this one query to return all teachers, there could be another way around this.
Any idea and suggestion greatly appreciated =).
So i've found out there is thing called DB::connection that you use before the methods like select, statement etc.
For other newbs like me, I share the solution for top example:
$teachers2 = DB::connection('moodle')->select(DB::raw("SELECT DISTINCT u.firstname, u.lastname
FROM mdl_user u
JOIN mdl_user_enrolments ue ON ue.userid = u.id
JOIN mdl_enrol e ON e.id = ue.enrolid
JOIN mdl_role_assignments ra ON ra.userid = u.id
JOIN mdl_role r ON r.id = ra.roleid AND r.shortname = 'editingteacher'
WHERE e.status = 0 AND u.suspended = 0 AND u.deleted = 0
AND (ue.timeend = 0 OR ue.timeend > NOW()) AND ue.status = 0"));
Now if only was there a way to use the result as a whole model (I only need teachers, never whole users).
Edit:
I've fixed the whole problem elegantly by using global scopes "http://laravel.com/docs/4.2/eloquent#global-scopes". This way my model always works on array of teachers.
Regarding those question marks it just means that there will be a value presented when Laravel runs it.

SQL Query complex tree join

I have a catalog that contains directories that can contain directories. The access of a directory can be granted to everyone or restricted to 0 to n user and/or to 0 to n usergroup. Access right is inherited in the hierarchy of group and from a group to its user. Therefore, a user can access a directory if he is allowed OR (he isn't deny AND (his group is allowed OR (his group isn't deny AND (his supergroup is allowed OR etc....
Their can be 1 to n level of groups, even if most of the time, their are typically no more than 3 levels.
I made a sqlfiddle from the schema : http://sqlfiddle.com/#!2/81b28
What I need is to get the list directories inside a given directory that can be accessible by a given user.
What I have so far is the following: this get the content of directory id '3' accessible to the user id '10', who is in usergroup '3' which is in supergroup '1' :
select l.id, l.accessright, ll.parentlibrarydirectoryid, ulc.*, glc1.*, glc2.*
from librarydirectory l
inner join a_librarydirectory_librarydirectory ll on ll.childlibrarydirectoryid = l.id
left join a_user_librarydirectory_canaccess ulc on ulc.librarydirectoryid = l.id
left join ws_user u on u.id = ulc.userid
left join a_group_librarydirectory_canaccess glc1 on glc1.librarydirectoryid = l.id
left join a_group_librarydirectory_canaccess glc2 on glc2.librarydirectoryid = l.id
where
ll.parentlibrarydirectoryid = 3
and (u.id = 10 or u.id is null)
and (glc1.groupid = 3 or glc1.groupid is null)
and (glc2.groupid = 1 or glc2.groupid is null)
and (l.accessright = "n"
or ((ulc.canaccess = "y")
or (ulc.canaccess is null and (glc1.allowedToAccess = 1
or (glc1.allowedToAccess is null and (glc2.allowedToAccess = 1))))));
It is working but I feel that this is not very elegant because I need to query the database to get the hierarchy of group prior to dynamically build the query in order to add as many a_group_librarydirectory_canaccess join and where clause as there are levels in the group hierarchy.
Is there a smarter way?
Thank you for your time

Assistance with MySQL Query - Omitting, Grouping?

Doing a bit of investigation and writing a query against a logs db.
I've joined a number of tables to bring back the data that I need, but i'd like to clean it up a bit.
The query returns all the users and which features they have enabled on their account.
Here is what i'm trying to do to clean it up:
Their is a column called 'actions' which has two states, 'added' and 'removed'
If a user feature has an action of 'removed' then I want to not show any of the rows for the same feature for that user which are also marked as 'added'
Is this possible?!
Here is what I have so far:
select users.id as site_id, users.company_name, feature_log.featurecode, feature.minimum_account as feature_type, users.account_type as site_type, account_types.name as account, feature_log.action, feature_log.time
from users
inner join
feature_log
on users.id = feature_log.siteid
inner join
feature
on feature_log.featurecode = feature.featurecode
inner join account_types
on users.account_type_INC = account_types.id
where feature.minimum_account != 0
AND feature.minimum_account > users.account_type
AND users.status = 'Y'
ORDER BY feature_log.time DESC
Thanks for any support!
So, in order to "mute" all the features, that have been "removed" at any point in time for a given user, you can add a (left) join on the following subquery:
SELECT DISTINCT users.id as siteid, feature_log.featurecode, TRUE as mute_feature
FROM users
INNER JOIN feature_log ON (users.id = feature_log.siteid)
WHERE action = 'removed'
This will be the list of features that a given user disabled at some point in time. Then in your query's WHERE clause, you'd add a filter like so:
AND NOT IFNULL(mute_feature, FALSE)
Essentially, that'd bring your whole query to be:
select users.id as site_id, users.company_name, feature_log.featurecode, feature.minimum_account as feature_type, users.account_type as site_type, account_types.name as account, feature_log.action, feature_log.time
from users
inner join
feature_log
on users.id = feature_log.siteid
left join (
SELECT DISTINCT users.id as siteid, feature_log.featurecode, TRUE as mute_feature
FROM users
INNER JOIN feature_log ON (users.id = feature_log.siteid)
WHERE action = 'removed'
) as muted_features ON (feature_log.siteid = muted_features.siteid AND feature_log.featurecode = muted_features.featurecode)
inner join
feature
on feature_log.featurecode = feature.featurecode
inner join account_types
on users.account_type_INC = account_types.id
where feature.minimum_account != 0
AND feature.minimum_account > users.account_type
AND users.status = 'Y'
AND NOT IFNULL(mute_feature, FALSE)
ORDER BY feature_log.time DESC