I have tables called comment, admin, user.
comment:
body userType userId
--------------------------------------------
comment1 admin 1
comment2 user 2
admin:
id title
-----------------------
1 amir
2 farhad
user:
id title
-----------------------
1 kazem
2 ali
I want to get the comment and userTypes' title from it's table by one query like:
SELECT u.title, c.body FROM comment c, c.userType u
but it doesn't work!
A couple options come to mind:
using a union:
SELECT title, body FROM comment c JOIN user u on c.userId = u.id and userType = 'user'
UNION
SELECT title, body FROM comment c JOIN admin u on c.userId = u.id and userType = 'admin'
using left joins:
SELECT
COALESCE(u.title, a.title) as title,
c.body
FROM comment c
LEFT JOIN user u on c.userId = u.id and userType = 'user'
LEFT JOIN user a on a.userId = u.id and userType = 'admin'
WHERE COALESCE(u.title, a.title) is not null;
This uses ANSI SQL COALESCE. If you are using T-SQL (MS SQL), you will need to use ISNULL instead.
More generically, this is a case of the "Concrete Table Inheritance" pattern, and the userType column is called a discriminator.
Related
I have 2 tables table name is users and projects.the structure of table is:
user table
id | name | role
1 | samjad | user
2 | saneer | constructor
projects table
id | name | user_id | constructor_id |
1 | school | 1 | 2 |
How can i get all details from both table in a single row based on project table id.
i want to select
projectname username, constroctorname, user_id, constroctor_id
in a single row
You can join the user table twice - Once as users and then as constructors.
select p.name as projectname,
u.name as username,
c.name as contructorname,
p.user_id,
p.contructor_id
from projects p
left join user u on p.user_id = u.id
left join user c on p.contructor_id = c.id
where u.role = 'user' -- check if the said user has role "user"
and c.role = 'constructor'; -- check if the said constructor has role "constructor"
Do the fact you have two relation between project table and user (one for user and one for constroctor) You can use user joined for two time
select p.name, u1.username, u2.username, p.user_id, p.constroctor_id
from projects as p
inner join user as u1 on p.user_id = u1.id
inner join user as u2 on p.constroctor_id = u2.id
You can use concat() function:
SELECT CONCAT(field1, field2, field3);
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat
or CONCAT_WS(separator,str1,str2,...)
Assuming there is a table called Constructor with columns name and constructor_id your query would be
select
p.name as projectname,
u.name as username,
c.name as constructorname,
u.id as userid,
c.id as constructorid
from
projects p
inner join user u on p.user_id=u.id
inner join constructor c on p.constructor_id=c.id
Use a join. You probably want an INNER JOIN:
SELECT * -- actually include only the fields you need
FROM Projects p
INNER JOIN Users u ON u.id = p.user_id
INNER JOIN Users uc ON uc.id = p.constructor_id
You'll want to join the tables on their keys. In this case something like the below:
select p.name as projectname
, u.name as username
, if(u.role='constructor',u.name,null) as constructorname
, p.user_id, p.constructor_id
from users u
join projects p
on p.user_id = u.id;
Below is an example of the schema I am working with.
How can I return the id and name of all users who have a permission, but DO NOT have a matching certification for that permission?
For example, the query would return 0, john in this case, since john has the "delete" permission, but does not have a matching "delete" certification.
(This schema is arbitrary and contrived, I'm just trying to get at the syntax/select logic for this query)
users
=====
id name
--------
0 john
1 joe
user_permissions
================
uid permission
--------------
0 'edit'
0 'delete'
1 'edit
user_certs
==========
uid cid
-------
0 'edit'
1 'edit'
I've tried, this, and I know the last line is wrong.
SELECT DISTINCT id, name FROM users
LEFT JOIN user_permissions users ON users.uid = user_permissions.uid
LEFT JOIN user_certs ON users.id = user_certs.uid
WHERE (user.permission = 'delete')
GROUP BY id, name
HAVING (COUNT(user_certs.cid = 'delete') = 0)
Get all the permissions that doesn't have a matching certificate, then group on the user:
select
u.id,
u.name
from
users u
inner join user_permissions p on p.uid = u.id
left join user_certs c on c.uid = p.uid and c.cid = p.permission
where
c.uid is null
group by
u.id,
u.name
Bud you are right.
The alias user dies not exist.
I have three different tables in MySQL:
given an user id, how can i get a list of role's name of this user?
For example, user_id = 1
I need a list like this (1, deleteuser, modifyuser, viewuser)
How can I construct my SQL command to get such a list?
JOIN the three tables like so:
SELECT
u.id,
r.Name
FROM user u
INNER JOIN user_role ur ON u.id = ur.user_id
INNER JOIN roles r ON ur.Role_id = r.id
WHERE u.id = Someid
However, if you want the list of roles for each user to be concatenated into one string. Use GROUP_CONCAT like so:
SELECT
u.id,
GROUP_CONCAT(r.Name) roles
FROM user u
INNER JOIN user_role ur ON u.id = ur.user_id
INNER JOIN role r ON ur.Role_id = r.id
WHERE u.id = 1
GROUP BY u.id
SQL Fiddle Demo
SELECT User_id, Name
FROM User_role
JOIN Role ON User_role.Role_id = Role.Id
WHERE User_id = '1'
that would create a list like this:
User_id | Name
1 | DeleteUser
1 | ModifyUser
1 | ViewUser
Try this:
SELECT User_id, GROUP_CONCAT(r.Name)
FROM User_Role ur
INNER JOIN Role r ON ur.Role_id = r.Role_id
GROUP BY User_id;
I have 3 tables.
user
id
firstname
lastname
...
user_rel_domain
user_id
domain_id
value
domain
id
name
I would like to make a search that would match the firstname, the lastname and the domain(s) name(s) if the value in user_rel_domain is higher then 0.
How could I do this in a single MySQL query?
EDIT:
Ok, I though that this idea would be easy to integrate from the 3 tables example, but I actually have 6 tables and I don't think that the answers can be used for the structure I really have, so here it is, sorry everyone!:
user
id
firstname
lastname
...
user_rel_domain
user_id
domain_id
value
domain
id
name
user_rel_mandate
user_id
mandate_id
value
mandate
id
cat_id
name
mandate_cat
id
name
Basically I want to search in all the "name" columns and the firstname and lastname of the user table while all the value from the relation tables be higher then 0.
EDIT: Hmm... I made a few assumptions about your new requirements, so let me know if this is in the ballpark:
SELECT
u.firstName,
u.lastName,
d.name AS domainName,
m.name AS mandateName,
mc.name AS mandateCatName
FROM
user u
JOIN user_rel_domain urd ON urd.user_id = u.id AND urd.value > 0
JOIN domain d ON d.id = urd.domain_id
JOIN user_rel_mandate urm ON urm.user_id = u.id AND urm.value > 0
JOIN mandate m ON m.id = urm.mandate_id
JOIN mandate_cat mc ON mc.id = m.cat_id
WHERE
u.firstName = #SearchTerm
OR u.lastName = #SearchTerm
OR d.Name = #SearchTerm
OR m.Name = #SearchTerm
OR mc.Name = #SearchTerm
SELECT u.firstname, u.lastname, d.name
FROM user_rel_domain urd
INNER JOIN user u
ON urd.user_id = u.id
INNER JOIN domain d
ON urd.domain_id = d.id
WHERE urd.value > 0;
SELECT user.firstname, user.lastname FROM user
JOIN user_rel_domain ON user.id=user_rel_domain.user_id
JOIN domain ON domain.id=user_rel_domain.domain_id
WHERE user_rel_domain.value>0
edit: are you looking for an exact match eg name in all of the columns should be equal to string you are looking for? or is it enough if any of the names is equal?
maybe this then:
SELECT user.firstname, user.lastname FROM user
JOIN user_rel_domain ON user.id=user_rel_domain.user_id
JOIN domain ON domain.id=user_rel_domain.domain_id
JOIN user_rel_mandate ON user.id=user_rel_mandate.user_id
JOIN mandate ON user_rel_mandate.mandate_id=mandate.id
JOIN mandate_cat ON mandate.id=mandate_cat.mandate_ID
WHERE
user_rel_domain.value>0 AND
(user.firstname="string" OR user.lastname="string" OR domain.name="string" OR mandate.name="string")
I am working the friend table with mysql. I want to get friend userid and username form current username.
friend
=======
- id
- uid
- fid
Sample Data
===========
id uid fid
1 1 2
2 3 1
user
====
- id
- username
Sample Data
===========
id username
1 saturngod
2 snow
3 John
My current code is
SELECT `user`.id,`user`.username FROM friend
INNER JOIN User
ON user.id = friend.uid
WHERE friend.fid = ( SELECT `id` FROM `User` WHERE `username`='saturngod')
UNION
SELECT `user`.id,`user`.username FROM friend
INNER JOIN User
ON user.id = friend.fid
WHERE friend.uid = ( SELECT `id` FROM `User` WHERE `username`='saturngod')
It's working. I got the friend list. However, I feel , the sql is so long.
Can I reduce this sql and can we write without UNION in sql ?
You have already joined the tables, so the subselect is not needed.
SELECT u.id,u.username
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
WHERE u.username='saturngod'
UNION ALL
SELECT u2.id,u2.username
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
INNER JOIN user u2 ON (u2.id = f.fid)
WHERE u.username='saturngod'
Or you can do:
SELECT
u.id as user_id
,u.username
,u2.id as friend_id
,u2.username as friendname
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
LEFT JOIN user u2 ON (u2.id = f.fid)
WHERE 'saturngod' = u.username
If you want one row per user you can do:
SELECT
u.id as user_id
,u.username
,GROUP_CONCAT(u2.id) AS friend_ids
,GROUP_CONCAT(u2.username) as friendnames
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
LEFT JOIN user u2 ON (u2.id = f.fid)
WHERE 'saturngod' = u.username <<-- optional
GROUP BY u.id
SELECT CASE WHEN user_id="$id" THEN friend_id ELSE user_id END AS friendID
FROM user_friend WHERE user_id="$id" OR friend_id="$id" order by friendID ASC