MySQL syntax help needed [duplicate] - mysql

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')

Related

Create View by Left join on multiple columns with OR

I am trying to create a view from two tables by left joining on two columns: t1.recipient_email = t2.username or t1.created_by = t2.id. As shown in pseudocode below, I want the first t2.name to be the recipient_name and second t2.name to be sender_name. I can't think of the correct way to achieve this.
CREATE VIEW emailsent_log_view
(id_email_que_log, date_sent, recipent_email, recipient_name, send_status, sender_name)
AS
SELECT
t1.id,
t1.date_send,
t1.recipient_email,
t2.name, --recipient_name: corresponds with t1.recipient_email = t2.username
t1.send_status,
t2.name --sender_name: correspond with t1.created_by = t2.id
FROM email_que_log AS t1
LEFT JOIN user_account as t2
ON t1.recipient_email = t2.username
OR t1.created_by = t2.id
As you guessed, you can't pick and choose which row joins to which row with an or condition like that. The way to solve such issues is to join the table twice, once for each need:
CREATE VIEW emailsent_log_view
(id_email_que_log, date_sent, recipent_email, recipient_name, send_status, sender_name)
AS
SELECT
eql.id,
eql.date_send,
eql.recipient_email,
res.name AS reciever, -- From the first join
eql.send_status,
snd.name AS sender -- From the second join
FROM
email_que_log AS eql
LEFT JOIN
user_account AS res ON eql.recipient_email = res.username
LEFT JOIN
user_account AS snd ON eql.created_by = snd.id

MySQL - Joining table on itself based on criteria from other table

Here’s the problem I am trying to solve:
Table1 has Product ID’s, dates, and prices for those dates, Table2 has Product attributes.
I want to be able to compare prices for a client for different products on the same date based on a set of attributes. I’m easily able to get a list of products/dates/prices for a ‘simple’ product, as well as an ‘advanced’ product (see below).
I want to be able to join these two tables such that the output looks like:
[CLIENT] [PRODUCT] [DATE] [SIM_PROD] [SIM_PRICE] [ADV_PROD] [ADV_PRICE]
Here is as far as I've made it
SELECT b.NAME AS ‘CLIENT’, a.NAME AS ‘SIMPLE_PRODUCT’, t1.DATE AS ‘DATE’, t1.PIVOT_PRICE AS ‘SIMPLE_PRICE’
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = TRUE;
SELECT b.NAME AS ‘CLIENT’, a.NAME AS ‘ADV_PRODUCT’, t2.DATE AS ‘DATE’, t2.PIVOT_PRICE AS ‘ADV_PRICE’
FROM TABLE1 t2
LEFT JOIN PRODUCT a
ON t2.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = FALSE;
I've been able to build similar tables where I pull in price from TABLE1 labeling it as t1 then pull in price again from TABLE1 and labeling it as t2, but only when using criteria in TABLE1, not criteria in a table that needs to be joined.
Is it possible to 'set' a table (EG simple) then 'set' a second one (EG advanced) and then join them on PARTNER_ID and DATE?
You can join the two subqueries:
SELECT t1.client, t1.date, t1.simple_product, t1.simple_price, t2.adv_product, t2.adv_price
FROM (
SELECT b.NAME AS CLIENT, a.NAME AS SIMPLE_PRODUCT, t1.DATE, t1.PIVOT_PRICE AS SIMPLE_PRICE
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = TRUE
) AS t1
JOIN (
SELECT b.NAME AS CLIENT, a.NAME AS SIMPLE_PRODUCT, t1.DATE, t1.PIVOT_PRICE AS SIMPLE_PRICE
FROM TABLE1 t1
LEFT JOIN PRODUCT a
ON t1.PRODUCT_ID = a_PRODUCT_ID
LEFT JOIN CLIENTS b
ON a.PARTNER_ID = b.PARTNER_ID
WHERE a.CRITERIA = FALSE
) AS t2
ON t1.client = t2.client AND t1.date = t2.date
You'll probably need to select additional criteria and add them to the ON condition. Otherwise this will produce a full cross product between all the products that have the same client and date.
Your desired output has an additional PRODUCT column, but I couldn't see where that comes from.

MySql relational division inner join syntax over 3 tables

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'))

select from 2 tables with for statement in sql

i have 2 table and want to select data from them
table 1 :
id
name
table 2
id
name
table1.id
and i want a query to make this resualt:
table1.id
table1.name
count(table2.id)
this is simple and solved by this way :
SELECT
c.id as corridor_id,
c.name as corridor_name,
(SELECT COUNT( r.id ) FROM rooms AS r WHERE r.corridorid = c.id ) as room_count
FROM corridors AS c
now if i add another table like this :
table3
id
name
table2.id
and want a query like this :
table1.id
table1.name
count(table2.id)
count(table3.id)
idk how can i do such as this query, but if there is a way i'll be happy to find it, many tnx
You'll want to join them all together, and then Group them along these lines:
SELECT
t1.Id,
t1.Name,
Count(t2.Id) AS T2Count,
Count(t3.Id) AS T3Count
FROM table1 t1
JOIN table2 t2
ON t1.Id = t2.table1_id
JOIN table3 t3
ON t2.id = t3.table2_id
GROUP BY t1.Id, t1.Name
You don't need nested SELECT statement here. You can do it by grouping and to avoid double-counting you would want DISTINCT keyword:
SELECT
c.id as corridor_id,
c.name as corridor_name,
COUNT(DISTINCT r1.id),
COUNT(DISTINCT r2.id)
FROM
corridors c
JOIN rooms r ON r.corridorid = c.id
JOIN rooms2 r2 ON r2.corridorid = c.id
GROUP BY c.id
If you want to properly treat missing values (0 counts) you can also do this:
SELECT
c.id as corridor_id,
c.name as corridor_name,
IFNULL(COUNT(DISTINCT r1.id), 0),
IFNULL(COUNT(DISTINCT r2.id), 0)
FROM
corridors c
LEFT JOIN rooms r ON r.corridorid = c.id
LEFT JOIN rooms2 r2 ON r2.corridorid = c.id
GROUP BY c.id

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)