MySQL join with LIMIT 1 from two tables - mysql

I have two tables. One with information about properties. The other stores 3 images for each property. Of these three images - one is marked as being the "main" image.
So I have:
Properties:
p_id name
1 villa a
2 villa b
3 villa c
4 villa d
and
Images
i_id p_id main
1 1 0
2 1 0
3 1 1
4 2 0
5 2 1
6 2 0
I need to produce a query which returns all of the properties with the id of their main image. e.g.
p_id name i_id
1 villa a 3
2 villa b 5
I know this will involve using LIMIT 1 and a join, but not sure where to start, I have already attempted doing this by using a subquery but felt it must be less complicated than what I was doing....
* HOW DO I *
Make it so it orders the query by "main" selecting the top 1 (i.e. so if main is not set it will still select an image) ?

Here's one way:
select *
from properties p
left join images i
on p.p_id = i.p_id
and i.main = 1
The left join will return a NULL image if no main image is found.

Here you go:
SELECT p_id, name, i_id
FROM properties p INNER JOIN images i ON (p.p_id = i.p_id AND i.main = 1)
or
SELECT p_id, name, i_id
FROM properties p INNER JOIN images i ON (p.p_id = i.p_id)
WHERE i.main = 1

SELECT p.p_id, p.name i.i_id FROM properties p JOIN images i USING p_id where p_id = 1;

select p.p_id, p.name, i.i_id
from properties p join images i on p.p_id = i.p_id
where i.main=1

You want to use a query like the following:
SELECT p.p_id, p.name, i.i_id FROM Images i INNER JOIN Properties p ON p.p_id = i.p_id WHERE i.main = 1

Related

How to return rows from left table where condition on right table true on all row without sub query

I have 2 table with this sample data.
Parent
id
title
1
A
2
B
3
C
Childs
id
p_id
number
1
1
1
2
1
2
3
1
3
4
2
4
5
2
5
6
2
6
7
3
2
8
3
7
9
3
8
10
3
9
And I want to get rows from parents join with childs and number > 3.
But I want to receive only parent whose condition is correct on all childs, and even if the condition is not correct on one child, the parent should not be returned
And I want to do without subquery
SELECT * FROM `parent`
LEFT JOIN `childs` on `childs`.`p_id` = `parent`.`id`
WHERE `childs`.`number` > '3'
I want to get only parent B with this condition.
Thanks.
Try this:
SELECT p.id, p.title, GROUP_CONCAT(number ORDER BY number) val
FROM Parent p JOIN Childs c ON p.id=c.p_id
GROUP BY p.id, p.title
HAVING SUBSTRING_INDEX(val,',',1) > 3;
Here's a fiddle demo
Maybe something like this can work
SELECT *
FROM parent p, child c2
WHERE EXISTS ( SELECT *
FROM child c1
WHERE p.id = c1.p_id AND c1.number >3) AND p.id = c2.p_id AND c2.number <=3
And I want to get rows from parents join with childs and number > 3.
But I want to receive only parent whose condition is correct on all childs, and even if the condition is not correct on one child, the parent should not be returned
I would recommend:
SELECT p.id, p.title
FROM Parent p JOIN
Childs c
ON p.id = c.p_id
GROUP BY p.id, p.title
HAVING MIN(number) > 3;
There is no reason at all to use strings for what you want to do. It just confuses the logic.
An even more efficient method would use NOT EXISTS:
select p.*
from p
where not exists (select 1
from childs c
where p.id = c.p_id and c.number <= 3
);

SQL select posts without specific tag

Straight to the point.
I have three tables POSTS, TAGS, POST_TAGS
POSTS { p_id, title }
TAGS { t_id, name }
POST_TAGS { p_id, t_id }
One post can have multiple tags and i want to select all post that don't have a specific tag. for example take this demo data:
TASKS
p_id | title
1 MyPost 1
2 MyPost 2
3 MyPost 3
TAGS
t_id | name
1 red
2 green
POST_TAGS
p_id | t_id
1 1
2 1
2 2
3 2
Now i want to see all POSTS that do not have the TAG 'green'. My current SQL query looks like this:
SELECT DISCTINCT
p.p_id, p.title
FROM
POSTS as p,
POST_TAGS as pt
WHERE
pt.p_id = p.p_id AND pt.t_id != 2
but this is going to return me this
RESULT
p_id | title
1 MyPost 1
2 MyPost 2
because 'MyPost 2' also has the TAG red it is listet.
Desired result is:
RESULT
p_id | title
1 MyPost 1
EDIT:
Thanks to all of you guys, i accepted GarethD answer because NOT EXISTS is more self-explanatory. NOT IN is working but not NULL save (even if i wasn't asking for it - thanks to Nico Haase as well)
GermanC solution also is correct and working, but isn't as self-explanatory as the selected answer. thanks to you too.
You can do this using NOT EXISTS:
SELECT p.p_id, p.title
FROM POSTS AS p
WHERE NOT EXISTS
( SELECT 1
FROM POST_TAGS AS pt
WHERE pt.p_id = p.p_id
AND pt.t_id = 2
);
You can explicitely join looking for the Green tag, and show those posts where the join was not successful:
SELECT
p.p_id, p.title
FROM
POSTS as p
LEFT OUTER JOIN
POST_TAGS as pt on pt.p_id = p.p_id AND pt.t_id = 2
WHERE
pt.p_id is null
This will do the job, as it searches for all postings which are tagged with 2 in an inner query and excludes them in the outer one
SELECT DISTINCT p.p_id WHERE p.p_id NOT IN(
SELECT DISCTINCT
p.p_id
FROM
POSTS as p,
POST_TAGS as pt
WHERE
pt.p_id = p.p_id AND pt.t_id = 2
)

Joing multiple with one master table

I have six tables- Project,Equipment,Fish,Staff and the junction tables - Project_Equipment,Project_Fish and Project_Staff.I want to retrieve Project total cost.
So, I wrote the statement like follows,
SELECT P.ProjectID, (SUM(E.EquipPrice*PE.EQuantity)+SUM(F.FishPrice*PF.FQuantity)+SUM(PS.Salary)) as ProjectCost
FROM Equipment as E INNER JOIN Project_Equipment as PE
ON E.EquipID=PE.EquipID
INNER JOIN Project as P
ON PE.ProjectID=P.ProjectID
INNER JOIN Project_Fish as PF
ON P.ProjectID=PF.ProjectID
INNER JOIN Fish as F
ON PF.FishID=F.FishID
INNER JOIN Project_Staff as PS
ON P.ProjectID=PS.ProjectID
INNER JOIN Staff as S
PS.StaffID=S.StaffID
GROUP BY ProjectID
But, I got the price with twice of correct amount.
Your query will end up with a lot of duplicate results. Consider the following simpler case:
Table: Project
ProjectID EQuantity
1 1
2 1
Table: Equipment
EquipID EPrice
1 1
2 1
Table: Fish
FishID
1
2
Table: Project_Equipment
ProjectID EquipID
1 1
1 2
2 1
2 2
Table: Project_Fish
ProjectID FishID
1 1
1 2
2 1
2 2
Now, let's look at the results of a Project_Equipment query only:
SELECT p.projectid, e.eprice, pe.equantity FROM project p
INNER JOIN project_equipment pe ON pe.projectid=p.projectid
INNER JOIN equipment e ON e.equipid=pe.equipid
ProjectID EPrice EQuantity
1 1 1 // a
1 1 1 // b
2 1 1 // c
2 1 1 // d
That's as expected; a list of the price and quantity of each piece of equipment used by each project. But what do you think will happen when we INNER JOIN that to project_fish? That first result has project 1 in it twice, and project 2 in it twice, so we end up with every combination of that result and project_fish!
SELECT p.projectid, e.eprice, pe.equantity, f.fishid FROM project p
INNER JOIN project_equipment pe ON pe.projectid=p.projectid
INNER JOIN equipment e ON e.equipid=pe.equipid
INNER JOIN project_fish pf ON pf.projectid=p.projectid
ProjectID EPrice EQuantity FishID
1 1 1 1 // from a above
1 1 1 2 // from a above
1 1 1 1 // from b above
1 1 1 2 // from b above
2 1 1 1 // from c above
2 1 1 2 // from c above
2 1 1 1 // from d above
2 1 1 2 // from d above
This duplication will continue with every inner join. The amount your price will be off won't always be 2x, it will actually depend on the number of combinations of all your joins.
So, you can't really do what you are trying to do with this particular query. Instead you'll have to calculate the cost of each relationship separately. Then you sum all those together. You can do this by selecting each one separately and calculating the cost into a ProjectID and ProjectCost column, using UNION to concatenate those altogether, then once again grouping the results by ProjectID and summing the individual ProjectCost subtotals.
I explained that poorly, but think of it as subtotaling equipment, fish, and salary costs, then sticking all those subtotals into one table and summing that. E.g.:
SELECT x.projectid, SUM(x.ProjectCost) FROM
(
SELECT p.projectid, SUM(e.eprice * pe.equantity) ProjectCost FROM project p
INNER JOIN project_equipment pe ON pe.projectid=p.projectid
INNER JOIN equipment e ON e.equipid=pe.equipid
GROUP BY p.projectid
UNION
SELECT p.projectid, SUM(f.fprice * pf.fquantity) ProjectCost FROM project p
INNER JOIN project_fish pf ON pf.projectid=p.projectid
INNER JOIN fish f ON f.fishid=pf.fishid
GROUP BY p.projectid
UNION
SELECT p.projectid, SUM(s.salary) ProjectCost FROM project p
INNER JOIN project_staff ps ON ps.staffid=p.projectid
INNER JOIN staff s ON s.staffid=ps.staffid
GROUP BY p.projectid
) x
GROUP BY x.projectid
Each of the subqueries produces a projectid column and a ProjectCost column. Run the subquery (between the parens) by itself to see the results. The outer query then adds the subtotals for the projects.
Sorry, btw, I renamed your EquipPrice and FishPrice columns to EPrice and FPrice when I was testing.

SQL Query joining two tables

I have 2 tables as below:
1.Products
product_id, name
1 Books A
2 Books B
3 Books C
4 Books D
5 Books E
2.liked_items
user_id, product_id
1 4
1 3
1 1
I want to query (sql) to retrieve result as below.
Can I do in same single query?
product_id, user_id
1 1
2 0
3 1
4 1
5 0
Hi, this first time i'm posting here.
Hope anyone can help me. Thank you
SELECT Products.product_id,liked_items.product_id,liked_items.user_id
FROM Products
LEFT JOIN liked_items
ON Products.product_id=liked_items.product_id
Try this one,
SELECT a.product_ID,
COALESCE(b.user_id,0) `user_id`
FROM products a
LEFT JOIN liked_items b
ON a.product_ID = b.product_ID
Sometimes liked_items.user_id can be possibly NULL so instead of displaying NULL in the result list, it can be changed using COALESCE. COALESCE is a function that can change NULL value into your desired value.
Click For Demonstration
SELECT
Products.product_id AS product_id,
IFNULL(liked_items.user_id,0) AS user_id
FROM Products
LEFT JOIN liked_items ON liked_items.product_id=Products.product_id
If you're using MS SQL Server you can use IsNull like so:
SELECT p.product_id, IsNull(li.user_id, 0)
FROM products p
LEFT JOIN liked_items li
ON (p.product_id = li.product_id);
If not, Joao or John's answer will do just fine.

Selecting rows from multiple tables. How?

Let's say that we have tree tables.
Products Fields Fields Value
---------------- ------------- --------------
pid catid fid catid fid pid value
-------|-------| -----|------- ------|-----|--------
1 1 1 1 1 1 25%
2 1 2 1 1 2 32.5%
3 2 2 1 45%
2 2 42%
3 1 17.3%
3 2 21%
The normal way is selecting Products in a one query and loop through result set(RS1).
Then we select Fields for catid per each row (RS2).
Then doing the same action with RS2 for selecting `Fields Value'.
Only problem is performance issue that will be reduced due to executing a lot of queries` when there are a lot of rows in each table.
Would you suggest me better solution to execute less queries ?
edit
I want to show each product in a box and show fields for each product with it's proper value. joining tree tables together will returns duplicated values for each FieldValue in Products and not usable in loop.
Guessing what you need, try this:
SELECT f.catid, fv.* FROM Fields f
INNER JOIN Products p
ON f.catid = p.catid
INNER JOIN FieldsValue fv
ON fv.fid = f.fid AND fv.pid = p.pid
SELECT *
FROM Products
NATURAL JOIN Fields
NATURAL JOIN FieldsValue;
use Join Syntax :
SELECT * FROM Products as P
LEFT JOIN FieldsValue as FV ON FV.PID = P.PID
LEFT JOIN Fields as F on F.fid = FV.fid
You can join the tables together using left join:
select *
from Products p
left join Fields f on f.catid = p.catid
left join `fields value` fv on fv.fid = f.fid on fv.pid = p.pid
where p.pid = 1