two right joins selects in one query mysql - php

I need to join two tables, and each must have a common relationship.
One table is for "purchases" and another for "payments", both are directly related to the "customers" table.
I tried that, but it is not working.
SELECT c.id AS idclient, c.name AS nameclient, p.id AS idpayment, cp.id AS idpurchases
FROM clients AS c
RIGHT JOIN payments AS p ON c.id = p.client
RIGHT JOIN purchases AS cp ON c.id = cp.client
The tables have different structures and other fields that are not currently needed. The fields are basically the ones that are in the select.
Expected outcome:
When a customer is NOT listed in the "purchases" or "payments" tables, it should not be listed, with the exception of a Boolean clause in the "purchases" table (company business rule).
idclient | nameclient | idpurchases | idpayment
109 | John | 3 | NULL
27 | Code | 1 | 1
302 | Woen | 4 | NULL
NULL | NULL | 2 | NULL

You want to join the three tables, but only show clients that have an entry in at least one of the tables payments and purchases. So outer join these tables and use a where clause to ensure at least one of them has a match.
SELECT c.id AS idclient, c.name AS nameclient, p.id AS idpayment, cp.id AS idpurchases
FROM clients AS c
LEFT JOIN payments AS p ON p.client = c.id
LEFT JOIN purchases AS cp ON cp.client = c.id
WHERE (p.client IS NOT NULL OR cp.client IS NOT NULL);
This is a strange query, however, because the table design suggests there can be multiple payments and multiple purchases per client, but your query combines each payment with each purchase a client made. Aren't they somehow related? Would a client make a payment without having purchased anything? What I am saying is, while you asked for this query, you may really want a completely different one.

As far as i see you need LEFT JOIN.
Meaning you have clients with no purchases and no payments.
Or the client is doing the purchase but still didn't pay
There are no purchase and no payments with out an client !
SELECT c.id AS idclient, c.name AS nameclient,
p.id AS idpayment,
cp.id AS idpurchases
FROM clients AS c
LEFT JOIN payments AS p ON c.id = p.client
LEFT JOIN purchases AS cp ON c.id = cp.client
Possible output
[idclient,name, idpay,idPur]
[1,A,2,3] - ok
[2,B,null,4] - no payment :ok
[3,C,null,null] - no purchase and no payment : ok
or
use JOIN(inner) to get without null [1,A,2,3]
SELECT c.id AS idclient, c.name AS nameclient,
p.id AS idpayment,
cp.id AS idpurchases
FROM purchases AS cp
//left if wanted all record
//inner : now only all columns populated
JOIN payments AS p ON cp.client = p.client
JOIN clients AS c ON c.id = cp.client

Related

Show two or more rows in a single row

I have these four tables:
table offers
id
id_company
description
table companies
id
name
table company_customer
id_company
id_customer
table customers
id
name
I need to get the offers, the company that has the offer and also the customers which have a relation with those companies. It's quite simple.
The query I'm typing is the following:
SELECT c.name, c.description, cu.name cu_name
FROM companies c
INNER JOIN offers o ON o.id_company = c.id
INNER JOIN company_customer cc ON cc.id_company = c.id
INNER JOIN customers cu ON cu.id = cc.id_customer
WHERE o.id_company = 1
ORDER BY o.id_company;
The "problem" is that sometimes an offer of a company is available for diferent customers.
Let me to show you the problem with a real example:
'Ebay' | 'offer number 1' | 'customer 1'
'Ebay' | 'offer number 1' | 'customer 2'
But I need concatenate or show both rows on a single row (just in the cases that company and the offer is the same but the customers are different). In other words, I need the following result:
'Ebay' | 'offer number 1' | 'customer 1, customer 2'
I work with PHP and MySQL. I know this may be done with PHP but I'm wondering if it could be possible to do it just with MySQL.
Any ideas??
Any help would be really appreciated. My apologize for my english level. I know it's not my best.
Thanks in advance for your time and attention.
You need to group by both company and offer, so you want this query:
SELECT
c.`name` AS companyName,
o.description AS offerName,
GROUP_CONCAT(cs.`name` ORDER BY cs.id) AS customerNames
FROM
companies c
INNER JOIN offers o ON o.id_company = c.id
INNER JOIN company_customer cc ON cc.id_company = c.id
INNER JOIN customers cs ON cs.id = cc.id_customer
WHERE
c.id = 1
GROUP BY
c.`name`,
o.description
Amyway there is no relation between offers and customers in your database, so you might consider to add such. Otherwhise all company's customers will appear in each offer of this company:
+-------------+-----------+----------------------------------+
| companyName | offerName | customerNames |
+-------------+-----------+----------------------------------+
| Ebay | Offer 1 | Customer 1,Customer 2,Customer 3 |
| Ebay | Offer 2 | Customer 1,Customer 2,Customer 3 |
+-------------+-----------+----------------------------------+
2 rows in set
But if you want exacly that, everything is OK then.
You can use a the aggregated GROUP_CONCAT Function
SELECT c.name, c.description, GROUP_CONCAT(string SEPARATOR ',')
FROM <<table And Joins...>>
GROUP BY c.name, c.description;
See hier http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
There is no way to represent this in your current table design, because an offer can reference (at most) one company. To do what you wish, you will need to add an offer_company table with id_company and id_offer, and remove the id_company field from the offer table. Then you will add an additional join column to your query, and a group by clause to group the rows with the same offer together.
Once you have the rows grouped together, you can merge them into a single row, concatenating the customer information, in your php code.

how to filter results from mysql inner join query

I have got a problem with my many to many relationship.
Client table columns:
clientID, name, address etc.
User table columns:
userID, name, address etc.
Users_clients columns:
userID, clientID.
Each client can have multible users attached and users can have multible clients.
Right now my users_clients table contains this:
userID | clientID<br>
1 | 2
1 | 3
2 | 2
2 | 3
3 | 3
3 | 2
4 | 1
On my php page I want a list of users which is not already attached to the client.
Ex. if I click on the client profile which has clientID = 3
It should show me a list of users not attached to this client.
SELECT u.name, u.email, u.userID FROM users u
INNER JOIN users_clients uc
ON u.userID = uc.userID
WHERE uc.clientID !=3
This works fine, but how do I create my MySQL query so that if a user have both clientID 3 and client 2 it doesn't show.
This query shows
1|2
2|2
3|2
4|1
and what I'm seeking is:
3|2
4|1
Hope this makes sense to you. Feel free to ask :)
You could process differently.
First make a request to seek every user with a clientId = 3;
select u.id from users u
INNER JOIN users_clients uc
ON u.userID = uc.userID
WHERE uc.clientID =3;
And then you could use this request to fetch all the users except those who have a clientId = 3.
Final request looks like this :
select u.id from users u where u.id NOT IN (select u.id from users u
INNER JOIN users_clients uc
ON u.userID = uc.userID
WHERE uc.clientID =3);
hope this'll help;
Have you tried a DISTINCT instruction ?
select distinct u.id from users u
INNER JOIN users_clients uc
ON u.userID = uc.userID
WHERE uc.clientID =3;

Mysql: Many to Many query based on Array

I have a database with 4 tables:
users following
------------- --------------------------------
| id | etc.. | | user_id (FK) | follow_id (FK) |
articles article_relations
------------- --------------------------------
| id | etc.. | | user_id(FK) | article_id (FK) |
Users can follow other users so they can see what articles they saved.
So based on the current user id it needs to check which users he/she follows in the table "following". The users that are followed will be known now.
Based on those follower ids it needs to check in article_relations which article id's are linked in article_relations to the followers. Now it should now which articles are saved by which users.
So now in the table articles the article_ids needs to be queried keeping the information which user the article saved.
Is the database design logical?
It seems to me that querying the "stream" to see which articles the users you follow saved is very redundant.
Can someone tell me if the DB Design is OK and help me with the query to get the articles from
the users you follow including the user info?
I tried till my pants fell off and searched whole stackoverflow!
try this query, it'll get you user's information, and the people the current user is following's information and the articles that are saved by the people the current user is following.
SELECT u.*,
fu.*,
a.*
FROM following f
INNER JOIN users u ON u.id = f.user_id
INNER JOIN users fu ON fu.id = f.follow_id
INNER JOIN article_relations ar ON ar.user_id = f.follow_id
INNER JOIN articles a ON a.id = ar.article_id
WHERE f.user_id = <currentUserId>
just change the .* to fields you need from each table.
Structure looks fine to me. As for the query, try this.
Join the following table (a) to the article_relations table (b)
by way of the follow_id then joining that to the article table (c) by article_id all based on the current user id.
I'm including the fictional fields article_name and article_field just as an example of what you might be pulling from the article table.
select c.id,
c.article_name,
c.article_field
from (following a
join article_relations b on a.follow_id = b.user_id)
join articles c on b.article_id = c.id
where a.user_id = current_user_id;
Just need to add the users table (d) into the mix for that.
select c.id,
c.article_name,
c.article_field,
d.id
from ((following a
join article_relations b on a.follow_id = b.user_id)
join articles c on b.article_id = c.id)
join users d on a.user_id = d.id
where a.user_id = current_user_id;

MySQL join through relational table

Hi I can't seem to find the right way to write this query. I have two entities websites and clients, and a table that relates them through their id fields.
This is a many to many relationship. i.e. a website can have multiple clients and a client can have multiple websites.
I am trying to write a query that returns all the websites with the clients that belong to them. I want to return all the websites even if they have no clients associated with them. Here is the query that I am working with at the moment:
the three tables are ost_sites = websites, ost_site_auth = relational table, ost_clients = clients
SELECT
ost_sites.site_id,
ost_sites.name,
ost_sites.site_url,
ost_site_auth.site_id,
ost_site_auth.client_id
ost_clients.client_id,
CONCAT_WS(" ", ost_clients.lastname, ost_clients.firstname) as name,
FROM ost_sites
LEFT JOIN (ost_site_auth, ost_clients)
ON (ost_sites.site_id=ost_site_auth.site_id
AND ost_site_auth.client_id=ost_clients.client_id)
GROUP BY ost_sites.name
I get a result set but it doesn't return all the sites, and all of the rows don't have clients associated with them.
Thanks so much for any help!
Edit:
Here are the columns for the tables:
ost_site
site_id | name | site_url
1 facebook facebook.com
2 twitter twitter.com
3 tubmblr tumblr.com
4 google google.com
ost_site_auth
(notice no site_id = 3 in auth list)
id | site_id | client_id
1 1 1
2 1 2
3 2 1
4 2 2
5 4 1
6 4 4
ost_client
client_id | firstname | lastname
1 wilma flintstone
2 bam bam
3 fred flintstone
4 barney rubble
expected output:
site_id | name | site_url | client_name |
1 facebook facebook.com wilma flintstone
1 facebook facebook.com bam bam
2 twitter twitter.com wilma flintstone
2 twitter twitter.com bam bam
4 google google.com wilma flintstone
4 google google.com barney rubble
3 tumblr tumlr.com NULL
Your join looks a bit off... try this
SELECT
ost_sites.site_id,
ost_sites.name,
ost_sites.site_url,
ost_site_auth.site_id,
ost_site_auth.client_id
ost_clients.client_id,
CONCAT_WS(" ", ost_clients.lastname, ost_clients.firstname) as name
FROM ost_sites
LEFT OUTER JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
LEFT OUTER JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
ORDER BY ost_sites.name
Let me try to explain this a little for you...
We start with the ost_sites table and we want all the results from that regardless of if anything matches in the other tables.
Then, we do a left outer join to the table ost_site_auth. That means that if something from ost_site_auth does not match something in ost_sites, it will not be returned. However, something in ost_sites that doesn't match something in ost_site_auth will be returned because of the left outer part.
Next, we repeat the left outer join for the ost_clients.
Not sure what you want... Let's pretend we have this data represented in the tables:
Site #1 has no clients
Site #2 has one client: A
Site #3 has two clients: B, C
Site #4 has three clients: D, E, F
Site #5 has no clients
Clients G and H have no associated site
Query One
SELECT
ost_sites.site_id as SITE,
ost_clients.client_id as CLIENT
FROM ost_sites
LEFT OUTER JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
LEFT OUTER JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
ORDER BY ost_sites.site_id, ost_clients.client_id
That would return (basically)
SITE CLIENT
1 NULL
2 A
3 B
3 C
4 D
4 E
4 F
5 NULL
Query Two
SELECT
ost_sites.site_id as SITE,
ost_clients.client_id as CLIENT
FROM ost_sites
JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
ORDER BY ost_sites.site_id, ost_clients.client_id
That would return (basically)
SITE CLIENT
2 A
3 B
3 C
4 D
4 E
4 F
Query three
SELECT
ost_sites.site_id as SITE,
ost_clients.client_id as CLIENT
FROM ost_sites
FULL OUTER JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
FULL OUTER JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
ORDER BY ost_sites.site_id, ost_clients.client_id
That would return (basically)
SITE CLIENT
1 NULL
2 A
3 B
3 C
4 D
4 E
4 F
5 NULL
NULL G
NULL H
Query four
SELECT DISTINCT ost_sites.site_id as SITE
FROM ost_sites
LEFT OUTER JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
LEFT OUTER JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
ORDER BY ost_sites.site_id
ORDER BY ost_sites.site_id
That would return (basically)
SITE
2
3
4
Query five
SELECT
ost_sites.site_id as SITE,
count(ost_clients.client_id) as CLIENT_COUNT
FROM ost_sites
JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
GROUP BY ost_sites.site_id
ORDER BY ost_sites.site_id
That would return (basically)
SITE CLIENT_COUNT
2 1
3 2
4 3
Query five
SELECT
ost_sites.site_id as SITE,
count(ost_clients.client_id) as CLIENT_COUNT
FROM ost_sites
LEFT OUTER JOIN ost_site_auth
ON ost_sites.site_id=ost_site_auth.site_id
LEFT OUTER JOIN ost_clients
ON ost_site_auth.client_id=ost_clients.client_id
GROUP BY ost_sites.site_id
ORDER BY ost_sites.site_id
That would return (basically)
SITE CLIENT_COUNT
1 0
2 1
3 2
4 3
5 0
Check out
Full Outer Join in MySQL
I think all you really need to do is do the same query as a right outer join as well and union them.

SQL Join query using three tables and some null values

I have three tables in a mySQL database that I am querying with PHP:
players
player_id | player_name
-----------------------
1 Tom
2 Dick
3 Harry
games
game_id | game_name
-------------------
1 Tennis
2 Cricket
3 Rugby
gamePlayerRel
game_id | player_id
-------------------
1 2
1 3
2 3
3 2
3 3
I want a query that will return the players id and name as well as the games that they play. If they play no games - as in the case of Tom (1) - then I want the id and name and a null or 0 value.
Desired Result
player_id | player_name | game_id | game_name
---------------------------------------------
1 Tom null null
2 Dick 1 Tennis
2 Dick 3 Rugby
3 Harry 1 Tennis
3 Harry 2 Cricket
3 Harry 3 Rugby
The closest I can get is with the following query:
SELECT players.player_id, players.player_name, gamePlayerRel.game_id, games.game_name
FROM players
INNER JOIN gamePlayerRel
INNER JOIN games
ON players.player_id = gamePlayerRel.player_id
AND gamePlayerRel.game_id=games.game_id
This gets close except that it does not return data for players with games assigned to them. In the above examples the result is as I want except that Tom (1) with his null values is left out.
I'm a super noob at this so if I'm coming at it from the wrong angle please say so and if you can suggest a query that will do what I'm after you would make my day.
Thanks in advance for any help and advice.
To return the result set as you've shown you need to actually do two outer joins
SELECT players.player_id, players.player_name, gamePlayerRel.game_id, games.game_name
FROM players
LEFT OUTER JOIN gamePlayerRel ON players.player_id = gamePlayerRel.player_id
LEFT OUTER JOIN games ON gamePlayerRel.game_id=games.game_id
In your case this should work just fine, however, what I really think you're trying to do is an inner join between games and gamePlayerRel and then a Left Outer Join between that virtual table and the players table. You can accomplish that via something like this:
SELECT players.player_id, players.player_name, playerGames.game_id, playerGames.game_name
FROM players
LEFT OUTER JOIN (Select gameplayerRel.player_id, games.game_id, games.game_name from games inner join gamePlayerRel on games.game_id = gamePlayerRel.game_id) playerGames
on players.player_id = playerGames.player_id
In your case you'd never need this alternative syntax, but there are some times when things can get messed up because the two left outer joins way is not exactly logically equivalent.
Here is a SQL Fiddle showing the results of the queries
I know you're using mysql, but this article does a good job of explaining the nuances of the joins, but it is written for MSSQL, although it should apply to you just the same. http://weblogs.sqlteam.com/jeffs/archive/2007/10/11/mixing-inner-outer-joins-sql.aspx
This should do the trick
SELECT players.player_id, players.player_name, gamePlayerRel.game_id, games.game_name
FROM players
INNER JOIN gamePlayerRel ON players.player_id = gamePlayerRel.player_id
LEFT OUTER JOIN games ON gamePlayerRel.game_id=games.game_id
You need to join each table individually and also need to use a LEFT OUTER JOIN for your games table. This will pull in at least one record for every match in the players/gamePlayerRel tables. If there isn't a match you'll be returned a NULL value.
After being nudged in the right direction by the helpful folk of SO I have got a query that does what I am after though I am still not 100% sure why it works.
SELECT players.player_id, players.player_name, gamePlayerRel.game_id, games.game_name
FROM players
INNER JOIN gamePlayerRel ON players.player_id = gamePlayerRel.player_id
LEFT OUTER JOIN games ON gamePlayerRel.game_id=games.game_id
Thanks to those who commented. Once again this site proves one of the most useful I have ever found :)

Categories