How to join three table to see all the rows - mysql

I have three tables:
(domains)
+----+-----+
| id |title|
+----+-----+
| 1 | com |
+----+-----+
| 2 | net |
+----+-----+
(slabs)
+----+-----+
| id |title|
+----+-----+
| 1 |str1 |
+----+-----+
| 2 |str2 |
+----+-----+
(prices)
+----+------+--------+
| id |slabid|domainId|
+----+------+--------+
empty
here is my query:
SELECT
prices.*,
FROM
prices
RIGHT JOIN domains ON domains.id=prices.domainId
JOIN slabs ON slabs.id=prices.slabId
how should I get query to list by domains & slabs rows...
and the result should be like this:
+----+------+--------+
| id |slabid|domainId|
+----+------+--------+
| 1 |1 |1 |
+----+------+--------+
| 2 |2 |1 |
+----+------+--------+
| 3 |1 |2 |
+----+------+--------+
| 4 |2 |2 |
+----+------+--------+
but it didn't.

An INNER JOIN will suffice your needs. If one of the fields on table prices is nullable and you want to display all records on the table whether it has a matching row on the other table or not, use LEFT JOIN.
The INNER JOIN will only display the record if it has atleast one match on each table. While LEFT JOIN, on the other hand, will display all row on the left hand side whether it has a match or nonmatch on the other tables.
SELECT a.*,
b.title domainTitle,
c.title slabsTitle
FROM prices a
INNER JOIN domain b
ON a.domainID = b.id
INNER JOIN slab c
ON a.slabID = c.ID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
UPDATE 1
You need to use CROSS JOIN for this because you need the product of the two tables, assuming that you want to insert it on table prices and ID is Identity or AUTO_INCREMENTed column,
INSERT INTO prices (slabid, domainid)
SELECT b.ID as slabID, a.ID as domanID
FROM domains a
CROSS JOIN slabs b
If the column ID on table prices is not auto_incremented and you are using mysql, use a variable to hold an increment the value,
SELECT #ID:=#ID+1 ID,
b.ID as slabID,
a.ID as domanID
FROM domains a
CROSS JOIN slabs b
CROSS JOIN (SELECT #ID:=0) s

Just cross join DOMAINS with SLABS table. Not sure why PRICES table plays a role here, since you just want to permutate the rows in DOMAINS table with the rows in SLABS table.

Related

Sql query with 2 join and count numbers and group by

I want to use an join to list the car colors count, car type, and users name.
I have 3 table
Table 1 Useres
id|username|fullname
1 | test0 | xy xy
2 | test1 | yx yx
Table 2 Car Type
id|car_type|user_id
1 | Ford | 1
2 | BMW | 2
3 | Ford | 1
4 | Skoda | 1
5 | BMW | 2
Table 3 Car Color
id| Color |user_id|car_id
1 | Red | 1 |1
2 | Blue | 2 |2
3 | Red | 2 |5
4 | Red | 1 |3
5 | Red | 1 |4
6 | Green | 1 |4
One car has 2 color
The result should be:
countType | CountColor | UserName
3 | 4 | test0
2 | 2 | test1
I tryed this:
SELECT
test as BlogsPost,
test2 as CommenstPost,
u.name
FROM users u
LEFT JOIN (
select COUNT(blogs.user_id) as test FROM blogs GROUP by blogs.user_id) blogs
on blogs.user_id=u.id
LEFT JOIN (
select COUNT(comments.user_id) as test2 FROM comments GROUP by comments.user_id) comments
on comments.user_id=u.id
GROUP by users.id
If I understand your question correctly with reference to your actual code section what you want is a list of users with how many blogs they have and how many comments they have. Now if you were wanting to count one matching table you could just do this:
SELECT
U.NAME
,COUNT(1) AS BLOG_COUNT
FROM USERS U
LEFT JOIN BLOGS B
ON B.USER_ID = U.ID
GROUP BY U.NAME
But since you are wanting to count two tables you have to do it slightly differently. There's a few ways of doing it but the way I like is like this:
SELECT
U.NAME
,B.BB_COUNT AS BLOG_COUNT
,C.CC_COUNT AS COMMENT_COUNT
FROM USERS U
LEFT JOIN
(
SELECT
BB.USER_ID
,COUNT(1) AS BB_COUNT
FROM BLOGS BB
GROUP BY BB.USER_ID
) B
ON B.USER_ID = U.ID
LEFT JOIN
(
SELECT
CC.USER_ID
,COUNT(1) AS CC_COUNT
FROM COMMENTS CC
GROUP BY CC.USER_ID
) C
ON C.USER_ID = U.ID
That may or may not be the most efficient way but in my experience it works pretty well and it's simple to understand. It all depends a lot on the number of rows in the tables and indexes etc. Usually the idea is to narrow down rows returned as fast as possible. In this case you'll have two sub queries but they'll end up with only as many rows as you have users basically.
Another thing to note, this will return all users, period. That may not be what you want. You might want only a subset of users. If so this inner select may not be the most efficient because you're doing calculations on users that may not be in the final result, wasting time. However I may be getting off topic.
I agree with the comment that states the table design is not really well constructed yet for you to achieve the counts you want you will need to do subqueries like this:
SELECT
(SELECT count(1) from CarType where user_id=username) as countType,
(SELECT count(1) from CarColor where user_id=username) as countColor,
username from (
SELECT username from Users
) a
As a suggestion for design:
Table Users
Table Cars
Table Colors
Then you have a Relationship table where you have user_id, car_id, color_id
This would be the proper table design for this structure

SQL left join: how to return the newest from tableB and grouped by another field

I've been trying for two days, without luck.
I have the following simplified tables in my database:
customers:
| id | name |
| 1 | andrea |
| 2 | marco |
| 3 | giovanni |
access:
| id | name_id | date |
| 1 | 1 | 5000 |
| 2 | 1 | 4000 |
| 3 | 2 | 1500 |
| 4 | 2 | 3000 |
| 5 | 2 | 1000 |
| 6 | 3 | 6000 |
| 7 | 3 | 2000 |
I want to return all the names with their last access date.
At first I tried simply with
SELECT * FROM customers LEFT JOIN access ON customers.id =
access.name_id
But I got 7 rows instead of 3 as expected. So I understood I need to use GROUP BY statemet as the following:
SELECT * FROM customers LEFT JOIN access ON customers.id =
access.name_id GROUP BY customers.id
As far I know, GROUP BY combines using a random row. In fact I got unordered access dates with several tests.
Instead I need to group every customer id with its corresponding latest access! How this can be done?
You have to get the latest date from the access table with a group by on the the name_id, then join this result with the customer table. Here is the query:
select c.id, c.name, a.last_access_date from customers c left join
(select id, name_id, max(access_date) last_access_date from access group by name_id) a
on c.id=a.name_id;
Here is a DEMO on sqlfiddle.
I think this is what you'd like to achieve:
SELECT c.id, c.name, max(a.date) last_access
FROM customers c
LEFT JOIN access a ON c.id = a.name_id
GROUP BY c.id, c.name
The LEFT join will return all entries in table customers regardless if the join criteria (c.id = a.name_id) is satisfied. This means that you might get some NULL entries.
Example:
Simply add a new row in the customers table (id: 4, name: manuela). The output will have 4 rows and the newest row will be (id: 4, last_access: null)
I would do this using a correlated subquery in the ON clause:
SELECT a.*, c.*
FROM customers c LEFT JOIN
access a
ON c.id = a.name_id AND
a.DATE = (SELECT MAX(a2.date) FROM access a2 WHERE a2.name_id = a.name_id);
If this statement is true:
I need to group every customer id with its corresponding latest access! How this can be done?
Then you can simply do:
select a.name_id, max(a2.date)
from access a
group by a.name_id;
You do not need the customers table because:
All customers are in access, so the left join is not necessary.
You need no columns from customers.

MySQL Error to selecting data

I have two column one column associated with another...
Table:base_data
id |---name----|-----des
1 | some name1 | The description1
2 | some name2 | The description2
Table: photos
id |---p_id----|-----photo
1 | 1 | img1s.jpg
2 | 1 | img1w.jpg
3 | 2 | img2.jpg
4 | 2 | img14.jpg
5 | 2 | img15.jpg
I want to select all data from table 1(base_data) and one row from associated row from photos: table how can I do that ????
I don't want to select by greatest n per group I want to select all data from the first table and only one row of the second table which matches with the first table row id, just first match not other.
The Result I want...
id |---name----|---des----|---p_id----|---photo----|
1 | some name |the des..1| 1 | img1s.jpg|
2 | some name |the des..2| 2 | img2.jpg|
I suppose you want to associate base_data with the first photo taken, which should be the one with the lowest photos.id. In MySQL, you could write this as follows: Create an intermediate query which gives - for any p_id - the corresponding record with the lowest id. Then, left join base_data with this intermediate query result. Hope there are not to many typos in it :-) :
select b.id, p2.photo
from base_data b left join
(select p.photo, p.p_id, min(id) from photos p group by p.p_id) p2 on b.id = p2.p_id
If you want the alphanumerically lowest photo name, in MySQL you can do this:
select
t1.*,
t2.photo
from
base_data as t1
left join (
select
p_id,
min(photo) as photo
from
photos
group by
p_id
) as t2 on t2.p_id = t1.id;

mysql returning duplicates on JOIN

i have two tables in a database.
The table clients looks like this:
----------------------------
|id | name | age | gender |
|---------------------------
|1 | CL1 | 22 | M |
|2 | CL2 | 23 | M |
|3 | CL3 | 24 | M |
|4 | CL4 | 25 | F |
|5 | CL5 | 26 | NA |
----------------------------
Now i have another table which relates to this client table , please note that the "id" in above Table is not AUTO_INCREMENT and is UNIQUE.
The second table is "images" which contain portfolio images of the clients and looks like this :
------------------------------
|id | client_id | url |
|------------------------------
|1 | 1 | img1_1.jpg |
|2 | 1 | img1_2.jpg |
|3 | 1 | img1_3.jpg |
|4 | 2 | img2_1.jpg |
|5 | 2 | img2_2.jpg |
-------------------------------
What i am basically achieving is that i want to pull all results from the client table which include name age gender etc and the first and one result from the images table which means, that if i Query it will have to show me the imag1_1.jpg from images table if i query for CL1 in clients table.
For this i am doing something like this :
SELECT DISTINCT c.* , i.* FROM clients c LEFT JOIN images i ON i.client_id = c.id
This query returns me the results but then the results are more duplicates. I ain't getting or i am either confused for WHAT THE DISTINCT stands for then if it still returns the duplicates, or may be i am missing something.
Any help regarding would be appreciated.
Best,
Ahsan
Here's one way to do it, using a correlated subquery:
SELECT c.*
, ( SELECT i.url
FROM images i
WHERE i.client_id = c.id
ORDER BY i.id
LIMIT 1
) AS url
FROM clients c
You don't really need to pull client_id from the images table, you already know it's value. If you need to return the id value from the images table, you'd need to add another correlated subquery in the select list
, ( SELECT i.id
FROM images i
WHERE i.client_id = c.id
ORDER BY i.id
LIMIT 1
) AS images_id
This approach can get expensive on large sets, but it performs reasonably for a limited number of rows returned from clients.
A more general query is of the form:
SELECT c.*
, i.*
FROM clients c
LEFT
JOIN ( SELECT m.client_id, MIN(m.id) as images_id
FROM images m
GROUP BY m.client_id
) n
LEFT
JOIN images i
ON i.id = n.images_id
The inline view aliased as n will get a single id value from the images table for each client_id, and then we can use that id value to join back to the images table, to retrieve the entire row.
Performance of this form can be better, but with large sets, materializing the inline view aliased as n can take some time. If you have a predicate on the client.id table on the outer query, then for better performance, that predicate can be repeated on m.client_id inside the inline view as well, to limit the number of rows.
Assuming that by "first" you mean the record with the minimal images.id, you are after the groupwise minimum:
SELECT * FROM images NATURAL JOIN (
SELECT client_id, MIN(id) id
FROM images
GROUP BY client_id
) t JOIN clients ON clients.id = images.client_id
SELECT DISTINCT operates on a ROW basis. It checks all values in a row against all other rows. If even one value is different, then the row is not a duplicate and the whole thing will be output. If you want to force a single FIELD to be distinct, then you should GROUP BY that field instead.
Since you're doing a left join, you'll get all records from the clients table, and ANY matching records from the images table.

When to use LEFT JOIN and when to use INNER JOIN?

I feel like I was always taught to use LEFT JOINs and I often see them mixed with INNERs to accomplish the same type of query throughout several pieces of code that are supposed to do the same thing on different pages. Here goes:
SELECT ac.reac, pt.pt_name, soc.soc_name, pt.pt_soc_code
FROM
AECounts ac
INNER JOIN 1_low_level_term llt on ac.reac = llt.llt_name
LEFT JOIN 1_pref_term pt ON llt.pt_code = pt.pt_code
LEFT JOIN 1_soc_term soc ON pt.pt_soc_code = soc.soc_code
LIMIT 100,10000
Thats one I am working on:
I see a lot like:
SELECT COUNT(DISTINCT p.`case`) as count
FROM FDA_CaseReports cr
INNER JOIN ae_indi i ON i.isr = cr.isr
LEFT JOIN ae_case_profile p ON cr.isr = p.isr
This seems like the LEFT may as well be INNER is there any catch?
Is there any catch? Yes there is -- left joins are a form of outer join, while inner joins are a form of, well, inner join.
Here's examples that show the difference. We'll start with the base data:
mysql> select * from j1;
+----+------------+
| id | thing |
+----+------------+
| 1 | hi |
| 2 | hello |
| 3 | guten tag |
| 4 | ciao |
| 5 | buongiorno |
+----+------------+
mysql> select * from j2;
+----+-----------+
| id | thing |
+----+-----------+
| 1 | bye |
| 3 | tschau |
| 4 | au revoir |
| 6 | so long |
| 7 | tschuessi |
+----+-----------+
And here we'll see the difference between an inner join and a left join:
mysql> select * from j1 inner join j2 on j1.id = j2.id;
+----+-----------+----+-----------+
| id | thing | id | thing |
+----+-----------+----+-----------+
| 1 | hi | 1 | bye |
| 3 | guten tag | 3 | tschau |
| 4 | ciao | 4 | au revoir |
+----+-----------+----+-----------+
Hmm, 3 rows.
mysql> select * from j1 left join j2 on j1.id = j2.id;
+----+------------+------+-----------+
| id | thing | id | thing |
+----+------------+------+-----------+
| 1 | hi | 1 | bye |
| 2 | hello | NULL | NULL |
| 3 | guten tag | 3 | tschau |
| 4 | ciao | 4 | au revoir |
| 5 | buongiorno | NULL | NULL |
+----+------------+------+-----------+
Wow, 5 rows! What happened?
Outer joins such as left join preserve rows that don't match -- so rows with id 2 and 5 are preserved by the left join query. The remaining columns are filled in with NULL.
In other words, left and inner joins are not interchangeable.
Here's a rough answer, that is sort of how I think about joins. Hoping this will be more helpful than a very precise answer due to the aforementioned math issues... ;-)
Inner joins narrow down the set of rows returns. Outer joins (left or right) don't change number of rows returned, but just "pick up" additional columns if possible.
In your first example, the result will be rows from AECounts that match the conditions specified to the 1_low_level_term table. Then for those rows, it tries to join to 1_pref_term and 1_soc_term. But if there's no match, the rows remain and the joined in columns are null.
An INNER JOIN will only return the rows where there are matching values in both tables, whereas a LEFT JOIN will return ALL the rows from the LEFT table even if there is no matching row in the RIGHT table
A quick example
TableA
ID Value
1 TableA.Value1
2 TableA.Value2
3 TableA.Value3
TableB
ID Value
2 TableB.ValueB
3 TableB.ValueC
An INNER JOIN produces:
SELECT a.ID,a.Value,b.ID,b.Value
FROM TableA a INNER JOIN TableB b ON b.ID = a.ID
a.ID a.Value b.ID b.Value
2 TableA.Value2 2 TableB.ValueB
3 TableA.Value3 3 TableB.ValueC
A LEFT JOIN produces:
SELECT a.ID,a.Value,b.ID,b.Value
FROM TableA a LEFT JOIN TableB b ON b.ID = a.ID
a.ID a.Value b.ID b.Value
1 TableA.Value1 NULL NULL
2 TableA.Value2 2 TableB.ValueB
3 TableA.Value3 3 TableB.ValueC
As you can see, the LEFT JOIN includes the row from TableA where ID = 1 even though there's no matching row in TableB where ID = 1, whereas the INNER JOIN excludes the row specifically because there's no matching row in TableB
HTH
Use an inner join when you want only the results that appear in both tables that matches the Join condition.
Use a left join when you want all the results from Table A, but if Table B has data relevant to some of Table A's records, then you also want to use that data in the same query.
Use a full join when you want all the results from both Tables.
For newbies, because it helped me when I was one: an INNER JOIN is always a subset of a LEFT or RIGHT JOIN, and all of these are always subsets of a FULL JOIN. It helped me understand the basic idea.