MySql relational division inner join syntax over 3 tables - mysql

I have a problem similar to that answered in:
SQL: Get Products from a category but also must be in another set of categories
but I need to include 3 tables (that deals only with 2)
I have three tables: Image, Category and CategoryImage.
Image:
id name
1 Fred
2 Joan
CategoryImage
imageId categoryId
1 10
1 20
1 30
2 15
2 20
2 30
3 10
Category
id title
10 Hiking
15 Walking
20 Family
30 Older
The only value being passed into the query is the category title. I'm stuck with this situation since the data is coming via an existing website app.
I want to return the image id for images which are in ALL the categories I'm interested in - i.e., if the user selected 'Hiking', 'Family' and 'Older' then I want to see only image 1. If the user selected 'Walking' and 'Older' I'd see only image 2.
The sql from the linked question works if I manually plug in the category ID.
select t0.id, t0.name
from image t0
inner join CategoryImage t1
on (t0.Id = t1.imageId AND t1.categoryId = 10)
inner join CategoryImage t2
on (t0.Id = t2.imageId AND t2.categoryID = 20)
inner join CategoryImage t3
on (t0.Id = t3.imageId AND t3.categoryID = 30)
How do I expand this correctly to add in the fact that actually all I know is the Category table title value.
Thanks for any help.
liz

simply
select t0.*
from
image t0
join CategoryImage t1 on t0.id = t1.imageId
join Category t2 on t1. categoryId = t2.id
where
t2.id in ( $list_of_id )
which
$list_of_id = implode(",", $ids);
or
$list_of_id = '10,20,30';

image is a datatype. plz,change the table name image and try this query...
select * from table1 inner join table2 on table1.id=table2.id inner join table3 on table2.id=table3.id where (condition)

This can be possible if you have the count of your category names you are using in query like for 'Hiking', 'Family','Older' count is 3 so you can use below query, SUM with the IN() expression will give you the count for each image group and in HAVING clause you can filter over the results with your condition
SELECT t0.id, t0.name ,
SUM(t2.title IN('Hiking', 'Family','Older')) `image_exist`
FROM image t0
INNER JOIN CategoryImage t1
ON (t0.Id = t1.imageId)
INNER JOIN Category t2
ON (t2.id = t1.categoryId)
GROUP BY t0.id
HAVING image_exist >= 3 ;
Fiddle Demo
Same for the second scenario 'Walking' and 'Older' count is 2 you can do so
SELECT t0.id, t0.name ,
SUM(t2.title IN('Walking','Older')) `image_exist`
FROM image t0
INNER JOIN CategoryImage t1
ON (t0.Id = t1.imageId)
INNER JOIN Category t2
ON (t2.id = t1.categoryId)
GROUP BY t0.id
HAVING image_exist >= 2 ;

Solution is
select t0.* from images t0 inner join categoryImage t1
on t0.id=t1.ImageID
where t1.CategoryID in (select id from Category where name in ('Hiking','Family','Older'))
group by t0.id,t0.name
having count(categoryid)=(select count(id) from Category where name in ('Hiking','Family','Older'))
select t0.* from images t0 inner join categoryImage t1
on t0.id=t1.ImageID
where t1.CategoryID in (select id from Category where name in ('Walking','Older'))
group by t0.id,t0.name
having count(categoryid)=(select count(id) from Category where name in ('Walking','Older'))

Related

Select from 1 table sum from 2 but 1 table has a AND condition

Thanks for assisting with the previous query (SQL Query that selects a column in table 1 and uses that to select sum in table 2) of SUM from 2 tables, I now have a additional Condition for 1 of the tables. I would like to add WHERE Group1 = 1 AND IN/OUT = 'OUT'
I have 3 tables,
Names ,Groups
Names ,Payments
Names ,Payments and IN/OUT
I want to only SUM the OUT Payments in Table 3, I am getting total payments only So FAR is have:
SELECT t1.name1, SUM(t2.sale2),SUM(t3.sale3)
FROM table1 t1 JOIN table2 t2 ON t1.name1 = t2.name2
JOIN table3 t3 ON t1.name1 = t3.name3
WHERE group1 = 1
GROUP BY t1.name1
i would also like to add a zero if there is no data to sum instead of removing the whole record, Currently if a name has no payments in Table 3 but has payments in table 2 it deletes the record.
Please check the query below =>
To Get OutPayment group by Name
SELECT t1.Names,SUM(t3.Payments) As OutPayment
FROM TABLE3 as t3
INNER JOIN TABLE1 as t1 ON t1.Names = t3.Names
INNER JOIN TABLE2 as t2 ON t1.Names = t2.Names
WHERE t1.GroupID = 1 AND t3.INOROUT=2 --INOROUT =2 is OUT and 1 is IN
GROUP BY t1.Names;
To Get TotalOutPayment
SELECT SUM(t3.Payments) As TotalOutPayment
FROM TABLE3 as t3
INNER JOIN TABLE1 as t1 ON t1.Names = t3.Names
INNER JOIN TABLE2 as t2 ON t1.Names = t2.Names
WHERE t1.GroupID = 1 AND t3.INOROUT=2; --INOROUT =2 is OUT and 1 is IN
Note: Code is in DBFiddle too Check the Demo Query Link

SQL JOIN and count without counting an ID twice

I am trying to join a table and get a count but I cannot count an ID twice in the table for the count.
Table 1:
ID animal
-- ------
1 dog
2 dog
3 cat
4 cat
5 dog
Table 2:
ID
--
2
2
3
5
5
I need to get a count of how many of each type of animal are in table 2. I can get it to join and change the ID to the type of animal and then get a count of each.
The issue is that each ID can only get counted once. So the expected output would be.
dog:2
cat:1
Where my output is
dog:4
cat:1
Try like below
select t1.animal, count( distinct t2.ID)
from table1 t1 join table2 t2 on t1.ID=t2.ID
group by t1.animal
You can try below using count distinct id
select b.animal,count(distinct a.id) from table2 a
inner join table1 b on a.id=b.id
group by b.animal
Try this:
SELECT t1.animal AS "Animal", COUNT(DISTINCT t1.ID) AS "No. of Animals"
FROM TABLE2 t2, TABLE1 t1
WHERE t2.ID = t1.ID
GROUP BY t1.animal
You can Try Nested Selects here.
SELECT
t.animal,
COUNT(t.ID) AS Count
FROM
(SELECT DISTINCT a.animal, b.ID FROM table1 a INNER JOIN table2 b ON a.ID = b.ID)t
GROUP BY t.animal
this is tested image

MySQL syntax help needed [duplicate]

This question already has an answer here:
SQL: Get Products from a category but also must be in another set of categories
(1 answer)
Closed 8 years ago.
I am completely stuck on this and would appreciate help from someone who is more fluent in sql than me!
Situation: I have Images which can belong to up to 3 Categories. I have to look them up using the category name (e.g. 'School'). I have an Image table, a Category table, and a CategoryImage table as a join table
The essential fields are
Category
Id
categoryname
Image
Id
imagename
description
CategoryImage
categoryId
imageId
If Image '001' belongs to the categories called 'School' and 'Home' it will have 2 entries in CategoryImage.
I need the sql to find all images which are in BOTH the 'School' AND the 'Home' category. I can see that this sql is probably trying to return a single image where the category is 'School AND 'Home' which is clearly impossible. [ Changing the AND to an OR finds images which be log to the 'School' category plus also images which belong to the 'Home' category, which is not what I need.
SELECT
DISTINCT t0.description,
t0.imagename
FROM
Image t0, Category T2, CategoryImage T1
WHERE
(T2.name = "School"
AND T2.name = "Home")
AND T1.categoryId = T2.id
AND t0.id = T1.imageId
Thanks in advance for any suggestions.
this will get you all images which are in both the school and home categories
SELECT
i.description,
i.imagename
FROM
Image i
WHERE EXISTS (SELECT *
FROM Category c
INNER JOIN CategoryImage ci ON ci.categoryid=c.id
WHERE ci.imageid=i.id AND c.name="School")
AND EXISTS (SELECT *
FROM Category c
INNER JOIN CategoryImage ci ON ci.categoryid=c.id
WHERE ci.imageid=i.id AND c.name="Home")
SELECT
t0.description, t0.imagename
FROM
Image t0
INNER JOIN CategoryImage T1 ON (t0.id = T1.imageId)
INNER JOIN Category T2 ON (T1.categoryId = T2.id)
WHERE
T2.name = "School"
UNION
SELECT
t0.description, t0.imagename
FROM
Image t0
INNER JOIN CategoryImage T1 ON (t0.id = T1.imageId)
INNER JOIN Category T2 ON (T1.categoryId = T2.id)
WHERE
T2.name = "Home"
SELECT DISTINCT(i.description), i.imagename
FROM CategoryImage ci
LEFT JOIN Category c
ON ci.categoryId = c.Id
LEFT JOIN Image i
ON ci.imageId = i.Id
WHERE c.categoryname IN ( 'School', 'Home' )
Try something like this :
select distinct t0.description
, t0.imagename
from categoryimage T1
join image t0 on t0.id = T1.imageid
join category T2 on T1.categoryid = T2.id
where T2.name in ( 'School', 'Home')

simple mysql query count fails

SELECT
count(t1.id) AS c1
FROM
table2
LEFT JOIN table1 AS t1 ON (t1.uid = table2.uid)
WHERE
table2.mode = 'ls'
GROUP BY
t1.id
c1 = 6 -> CORRECT!
SELECT
count(t2.id) AS c2
FROM
table2
LEFT JOIN table1 AS t2 ON (t2.pid = table2.id)
WHERE
table2.mode = 'ls'
GROUP BY
t1.id
c2 = 1 -> CORRECT!
SELECT
count(t1.id) AS c1,
count(t2.id) AS c2
FROM
table2
LEFT JOIN table1 AS t1 ON (t1.uid = table2.uid)
LEFT JOIN table1 AS t2 ON (t2.pid = table2.id)
WHERE
table2.mode = 'ls'
GROUP BY
t1.id
c1 = 6 -> CORRECT!
c2 = 6 -> WRONG!
How do I request both counts in one query, without getting wrong results?
I need to count two different requests at the same table (table1).
so, I'm using an alias for both request. (t1). Each alias-request is working fine alone. If I use both in the same query, i got wrong results.
count() will get you the number of records that are returned by your query. Since if you removed the counts and replaced it with * you would have 6 rows both of those counts are giving you 6.
Is there any reason why you cant use two sub selects and return the result of each of those?
So:
SELECT subQ1.c1, subQ2.c2 FROM
(SELECT count(t1.id) AS c1 FROM table2
LEFT JOIN table1 AS t1 ON (t1.uid = table2.uid)
WHERE table2.mode = 'ls') as subQ1,
(SELECT count(t2.id) AS c2 FROM table2
LEFT JOIN table1 AS t2 ON (t2.pid = table2.id)
WHERE table2.mode = 'ls') as SubQ2;
I believe your problem on the full query is your group by function. You are grouping by t.id, thus a1.id will have a different count based on how many rows you have.
What I mean by this is if there are 6 rows in table t, then count is going to return 6 for table t; but also since there looks to be a 1 to 1 relation on table a, there are 6 matching rows in table a to the 6 matching rows in table t. such that
t.id = a.id
1 = 1
2= 2 ...etc.
Thus your count is returning rows versus the count you believe you should have? I believe sum function is what you want to use here.
You could try this...but I'm not really sure what you're trying to do.
SELECT (...)
count(CASE WHEN t1.uid = t3.uid THEN t1.id ELSE NULL END) AS CBanz,
count(CASE WHEN ta1.pid = t3.id THEN a1.id ELSE NULL END) AS CBanz1
FROM
t0
LEFT JOIN (...)
LEFT JOIN t1 ON (t1.uid = t3.uid)
LEFT JOIN t1 AS a1 ON (a1.pid = t3.id)
WHERE (...)

sql query question

I have tables
table 1
id text
1 A
1 B
2 C
table 2
id text
1 x
1 f
2 y
2 z
I want to join them this way
1 A x
1 B f
2 C y
2 z
In other words i want to see all texts from table1 and table2 grouped by id, with no repeats.
Any ideas?
Update: as they say in comments, the logic is not clear, I'll try to explain.
I have current values in table_1 and deleted values in table_2.
Customer wants to see current values and deleted values in one table grouped by some id.
Simple solution to get something close to what you're looking for
SELECT t1.id, t1.text, t2.text
FROM tbl_1 t1
INNER JOIN tbl_2 t2
ON t1.id = t2.id
this will create output
1 A x
1 B x
2 C y
2 C z
Only different is now that the duplicated texts x and C should somehow removed.
Update
precondition: duplicates per id are either in tbl_1 or tbl_2 not both !
Joining a grouped select in addition to above simple solution will allow to create kind of "CASE-Filters" to get your desired output.
SELECT
t1.id,
CASE
WHEN t2.text = txt_i2 THEN t1.text
END AS txt_t1,
CASE
WHEN t1.text = txt_i1 THEN t2.text
END AS txt_t2
FROM (
SELECT
i1.id,
i1.text AS txt_i1,
i2.text AS txt_i2
FROM tbl_1 i1
INNER JOIN tbl_2 i2
ON i1.id = i2.id
GROUP BY id
) i
INNER JOIN tbl_1 t1
ON i.id = t1.id
INNER JOIN tbl_2 t2
ON t1.id = t2.id
You should create a view of the tbl_1-tbl_2-join to get more readable SQL:
CREATE OR REPLACE VIEW V_tbl_1_2 AS (
SELECT
t1.id,
t1.text AS txt_1,
t2.text AS txt_2
FROM tbl_1 t1
INNER JOIN tbl_2 t2
ON t1.id = t2.id
)
;
SELECT
t.id,
CASE
WHEN t.txt_2 = i.txt_2 THEN t.txt_1
END AS txt_t1,
CASE
WHEN t.txt_1 = i.txt_1 THEN t.txt_2
END AS txt_t2
FROM V_tbl_1_2 t
INNER JOIN (
SELECT *
FROM V_tbl_1_2
GROUP BY id
) i ON t.id = i.id
;
USE MYSQL VIEW OR JOIN
This works if you can have no more than two items per id in either table and if neither one has complete duplicates. (And I must also add that this can only work if MySQL is able to swallow this monster and not choke with it.)
SELECT
COALESCE (t1.id, t2.id) AS id,
t1.text AS text1,
t2.text AS text2
FROM (
SELECT
t.id,
t.text,
CASE t.text WHEN m.text THEN 1 ELSE 2 END AS rowid
FROM table_1 t
INNER JOIN (
SELECT id, MIN(text) AS text
FROM table_1
GROUP BY id
) m ON t.id = m.id
) t1
FULL JOIN (
SELECT
t.id,
t.text,
CASE t.text WHEN m.text THEN 1 ELSE 2 END AS rowid
FROM table_2 t
INNER JOIN (
SELECT id, MIN(text) AS text
FROM table_2
GROUP BY id
) m ON t.id = m.id
) t2
ON t1.id = t2.id AND t1.rowid = t2.rowid
ORDER BY COALESCE (t1.id, t2.id), COALESCE (t1.rowid, t2.rowid)