mysql multi join from same table give alias - mysql

currently i have the following query
SELECT * FROM tabs
JOIN users d ON tabs.`debit` = d.id
JOIN users c ON tabs.`credit` = c.id
as the table contains two user objects the names that get returned are the same like so:
id | amount | type | id | username | avatar | id | username | avatar
i need it to return as the following
id | amount | type | debit.id | debit.username | debit.avatar | credit.id | credit.username | credit.avatar
or something simmilar as long as the column names from the users are prefixed.

I think this is what you are looking for. Give it a try. (Assuming that id | amount | type belongs to the tabs table)
SELECT t.id,
t.amount,
t.type,
d.id as 'debit.id',
d.username as 'debit.username',
d.avatar as 'debit.avatar',
c.id as 'credit.id',
c.username as 'credit.username',
c.avatar as 'credit.avatar',
FROM tabs t
JOIN users d ON t.`debit` = d.id
JOIN users c ON t.`credit` = c.id

Related

Can I be selective on what rows I join on in MySQL

Suppose I have two tables, people and emails. emails has a person_id, an address, and an is_primary:
people:
id
emails:
person_id
address
is_primary
To get all email addresses per person, I can do a simple join:
select * from people join emails on people.id = emails.person_id
What if I only want (at most) one row from the right table for each row in the left table? And, if a particular person has multiple emails and one is marked as is_primary, is there a way to prefer which row to use when joining?
So, if I have
people: emails:
------ -----------------------------------------
| id | | id | person_id | address | is_primary |
------ -----------------------------------------
| 1 | | 1 | 1 | a#b.c | true |
| 2 | | 2 | 1 | b#b.c | false |
| 3 | | 3 | 2 | c#b.c | true |
| 4 | | 4 | 4 | d#b.c | false |
------ -----------------------------------------
is there a way to get this result:
------------------------------------------------
| people.id | emails.id | address | is_primary |
------------------------------------------------
| 1 | 1 | a#b.c | true |
| 2 | 3 | c#b.c | true | // chosen over b#b.c because it's primary
| 3 | null | null | null | // no email for person 3
| 4 | 4 | d#b.c | false | // no primary email for person 4
------------------------------------------------
You got it a bit wrong, how left/right joins work.
This join
select * from people join emails on people.id = emails.person_id
will get you every column from both tables for all records that match your ON condition.
The left join
select * from people left join emails on people.id = emails.person_id
will give you every record from people, regardless if there's a corresponding record in emails or not. When there's not, the columns from the emails table will just be NULL.
If a person has multiple emails, multiple records will be in the result for this person. Beginners often wonder then, why the data has duplicated.
If you want to restrict the data to the rows where is_primary has the value 1, you can do so in the WHERE clause when you're doing an inner join (your first query, although you ommitted the inner keyword).
When you have a left/right join query, you have to put this filter in the ON clause. If you would put it in the WHERE clause, you would turn the left/right join into an inner join implicitly, because the WHERE clause would filter the NULL rows that I mentioned above. Or you could write the query like this:
select * from people left join emails on people.id = emails.person_id
where (emails.is_primary = 1 or emails.is_primary is null)
EDIT after clarification:
Paul Spiegel's answer is good, therefore my upvote, but I'm not sure if it performs well, since it has a dependent subquery. So I created this query. It may depend on your data though. Try both answers.
select
p.*,
coalesce(e1.address, e2.address) AS address
from people p
left join emails e1 on p.id = e1.person_id and e1.is_primary = 1
left join (
select person_id, address
from emails e
where id = (select min(id) from emails where emails.is_primary = 0 and emails.person_id = e.person_id)
) e2 on p.id = e2.person_id
Use a correlated subquery with LIMIT 1 in the ON clause of the LEFT JOIN:
select *
from people p
left join emails e
on e.person_id = p.id
and e.id = (
select e1.id
from emails e1
where e1.person_id = e.person_id
order by e1.is_primary desc, -- true first
e1.id -- If e1.is_primary is ambiguous
limit 1
)
order by p.id
sqlfiddle

How to count the number of people who choose a particular location?

i need help in select sql statement.
in my mysql database:
location table
serialID(AI)|locations | telephone | address
---------------------------------------------
1 | A
2 | B
3 | C
4 | D
users table
userID | location chosen
-------------------------
1 | A
2 | B
3 | B
I want to count the number of people who choose a particular location and display in the table. So if this particular location have more users choosen as their favourite location, it will move up to the first row. May I know how can I do this?
something like this when it populate into dynamic table ->
location | address | telephone | user's favourable
B | - | - | 2
A | - | - | 1
C | - | - | 0
D | - | - | 0
You could just do a query like this:
SELECT l.locations, l.telephone, l.address, COUNT (u.userID) as `location_count`
FROM location AS l
LEFT OUTER JOIN users AS u on l.locations = u.location_chosen
GROUP BY l.locations
ORDER BY `location_count` DESC
Try something like this:
SELECT l.location, l.address, l.telephone, COUNT(u.userID) AS [users favourable]
FROM location l
LEFT JOIN
users u
ON l.location = u.locationchosen
GROUP BY l.location, l.address, l.telephone
SELECT loc.*, countResult.usersFavourable
FROM location loc
LEFT JOIN
(
SELECT locationChoosen, COUNT(*) `usersFavourable`
FROM users
GROUP BY locationChoosen
) countResult ON loc.locations = countResult.locationChoosen
ORDER BY countResult.usersFavourable DESC, loc.locations
use this:
select count(userId) count,locations,address,telephone
from Table1 Left join Table2
on Table1.locations = Table2.location
group by locations order by count desc ;
see here.. link
SELECT LocationChosen, Count(*) FROM usersTable GROUP BY LocationChosen

MySQL - Join 2 tables

I have 2 tables: users & balance.
I want to join the tables with all of the details from the user table (all fields of all tuples) with the most recent entry from the balance table (1 field linked by a user id).
Here is the structure of the tables:
balance:
+---------+
| Field |
+---------+
| dbid |
| userId |
| date |
| balance |
+---------+
users:
+-------------+
| Field |
+-------------+
| dbid |
| id |
| fName |
| sName |
| schedName |
| flexiLeave |
| clockStatus |
+-------------+
I have been trying for hours to do this and the closest I can get is to return a row for a single user:
SELECT u.*, b.balance, b.date
FROM users u, balance b
WHERE
u.id = b.userId AND
b.date = (SELECT MAX(date) FROM balance WHERE userId = 'A8126982');
Or I can select all users but not the most recent entry in the balance table:
SELECT u.*, b.balance, b.date
FROM users u, balance b
WHERE u.id = b.userId GROUP BY u.id;
I have tried many different queries and seem to be getting closer but I just can't get to where I want to be.
Any help would be appreciated.
You can use the first SQL you wrote but for all users:
SELECT u.*, b.balance, b.date
FROM users u JOIN balance b ON u.id = b.userId
WHERE b.date = (SELECT MAX(date) FROM balance WHERE userId = u.id);
This may not be the fastest way to get the result, but it'll give you what you need. I use similar queries in quite a few places in my app.

joining 4 tables

I am new to this kind of relational type of database design. I just designed the database in this manner. However, I am quite confused on this JOIN of MySQL. What should be my query to join all this table. If you can see the table users is the reference of all the tables.
users
+----------+----------------+-----------------+
| users_id | users_level_id | users_status_id |
+----------+----------------+-----------------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
+----------+----------------+-----------------+
users_credentials
+----------+---------------------------+-----------------------------+----------------------------+
| users_id | users_credential_username | users_credential_email | users_credential_password |
+----------+---------------------------+-----------------------------+----------------------------+
| 1 | super | super#gmail.com | $5$e94e9e$vptscyHjm8rdX0j6 |
| 2 | admin | admin#gmail.com | $5$fVuOmySyC0PttbiMn8in0k7 |
+----------+---------------------------+-----------------------------+----------------------------+
users_level
+----------------+-------------------------+
| users_level_id | users_level_description |
+----------------+-------------------------+
| 1 | Super Administrator |
| 2 | Administrator |
+----------------+-------------------------+
users_status
+-----------------+--------------------------+
| users_status_id | users_status_description |
+-----------------+--------------------------+
| 0 | Disabled |
| 1 | Enabled |
+-----------------+--------------------------+
Try this
SELECT u.*, uc.*, ul.*, us.*
FROM users u
INNER JOIN users_credentials uc
ON u.users_id = uc.users_id
INNER JOIN users_level ul
ON u.users_level_id = ul.users_level_id
INNER JOIN users_status us
ON u.users_status_id = us.users_status_id
Note the use INNER JOIN: this means that if a user does not have corresponing record on joined table it won't be shown; if you need to return every user even without matching record on related tables, change INNER JOIN with LEFT JOIN.
EDITED after user comment:
If you want to return just some column, define it as this example
SELECT uc.users_credential_username AS username,
uc.users_credential_email AS email,
uc.users_credential_password AS pwd,
ul.users_level_description AS level,
us.users_status_description AS status
This is a simple query that will join all of them
select *
from users
left join users_credentials
on users_credentials.users_id = users.users_id
left join users_level
on users_level.users_level_id = users.users_level_id
left join users_status
on users_status.users_status_id = users.users_status_id
EDIT
if you want to fetch data from different tables
user this
select users.* , users_credentials.* , users_level.* , users_status.*
from users
left join users_credentials
on users_credentials.users_id = users.users_id
left join users_level
on users_level.users_level_id = users.users_level_id
left join users_status
on users_status.users_status_id = users.users_status_id
I think this look like this :
SELECT * FROM users
LEFT JOIN user_credentials ON users.user_id = user_credential.user_id
LEFT JOIN user_level ON users.users_level_id = users_level.users_level_id
and so on..
Use this type of query....
SELECT c.*, l.*, s.*
FROM users AS u
INNER JOIN users_credentials AS c ON (u.users_id = C.users_id)
INNER JOIN users_level AS l ON (u.users_level_id= l.users_level_id)
INNER JOIN users_status AS s ON (u.users_status_id= s.users_status_id)
Where you can specify the field what you want in .* ...
Join is used to fetch data from normalized tables which have foreign key relation with the reference table.
For the above table with join you can fetch data among two tables with the help of reference table.
For example
Select * from users a JOIN users_credentials b
ON a.user_id=b.user_id JOIN users_level c
ON c.users_level_id=a.users_level_id
where users_credential_username='super';
The result of this query will give you the detail like users_level_description for the user with users_credential_username=super.

How would I accomplish this using SQL?

I have 2 tables in my database that look like so:
clients
+-------------+
| id | sms |
|------+------|
| 1 | 0 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
+------+------+
clients_lists_relationships
+----------------------+
| listid | clientid |
|----------+-----------|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
+----------+-----------+
Now what I'm trying to do is get a list of clients who are in a bunch of lists. I do that like so:
SELECT c.id,
l.*
FROM clients AS c,
clients_lists_relationships AS l
WHERE c.id = l.clientid
AND c.sms = '1'
AND ( l.listid = '1'
OR l.listid = '2' );
This does give me a list of the clients that I need. But because a client can be in more than one list I get the same client more than once. How would I limit this to only one row for each client no matter how many lists they are in?
If you just need any client that is in a list, you can just query the relationship table:
SELECT DSITINCT(clientid) FROM clients_lists_relationships
You can also use that distinct on your combined query, but be aware that the "listid" you'll get is just one.
Use GROUP BY:
SELECT c.id,
l.listid
FROM clients c
INNER JOIN clients_lists_relationships l
ON c.id = l.clientid
WHERE c.sms = 1
AND l.listid IN (1,2)
GROUP BY c.id
Note that by doing this you lose information on which lists the client was a member of. This means that you should probably not select anything from client_lists_relationships as this information is either redundant (clientid) or incomplete (listid).
First of all take a look at MySQL:: JOIN It's much better than the WHERE statements you use now.
I think you are looking for GROUP BY.
In total, the query look like:
SELECT
c.id,
l.*
FROM
clients AS c
INNER JOIN
clients_lists_relationships AS l
ON
l.clientid = c.id
AND
c.sms = '1'
AND
( l.listid = '1'
OR l.listid = '2' );
GROUP BY
c.id
To return just the clients participating in more than 1 list you may want to consider using the HAVING clause:
SELECT c.id
FROM Clients c
INNER JOIN Client_Lists_Relationships l
ON l.clientid = c.id
WHERE c.sms = 1
HAVING COUNT(L.listid) > 1
GROUP BY c.id