Have been trying (unsuccessfully) to write a query with multiple joins, which is why I am now asking for your help.
Table structure:
A parent which has many children and many cars
A child which has one parent and many cars
A car which either has one parent or one child.
(source: zxq.net)
What I am trying to do:
I am trying to find to find the total value of the cars per parent. (A parent "owns" his childrens cars, so the sum of the value of the childrens cars should be added to the sum of the value of the parents cars).
For example, I want my query to return:
If Thomas has a car worth 5000, and one child who has two cars also worth 5000, the total value for thomas is 5000 + 5000 * 2 = 15000.
If John has two cars worth 2000, and two children who each have two cars worth 2000, the total value for John is : 2000 * 2 + 2000 * 2 + 2000 * 2 = 12000.
In short:
name | total
--------------
Thomas | 15000
John | 12000
So far I have:
SELECT p.name,
SUM(IFNULL(carparent.price, 0)+IFNULL(carchild.price, 0)) total
FROM parent p
# first get the childrens cars
INNER JOIN child c ON c.parent_id = p.id
INNER JOIN car carchild ON carchild.child_id = c.id
# now get the parents cars
LEFT JOIN car carparent ON carparent.parent_id = p.id
GROUP BY p.name
ORDER BY total DESC
Which is returning strange results when a parent has more than one child... I think I am getting confused with all the JOINS..
Anyways, if anyone could point me in the correct direction, I would be very grateful :)
Many thanks,
I tried to make your database as stated earlier.
Here is my solution.
select
Name,
(select sum(price)
from car
where car.Parent_id=parent.id) as `Value Parent Car(s)`,
(select sum(price)
from car
left join child
on car.child_id=child.id
where child.parent_id=parent.id) as `Value of Child car(s)`
from parent
Or to obtain a total
select
id,
Name,
((select sum(price)
from car
where car.Parent_id=parent.id) +
(select sum(price)
from car
left join child
on car.child_id=child.id
where child.parent_id=parent.id)) as `Total Value car(s)`
from parent
I am sure though that a better structure can be found... By example, a car is own by a person and a person can be a parent, a child or both...
Related
What's up guys? I'm trying get a sql query which returns some datas.
Look at the situation:
I have a set of categories, category unity and organization, that are my main category, inside these categories I have a lot more subcategory of them, e.g. math, dance, etc. inside these subcategories I have some more, e.g. Extension, Graduation, Other, etc. Inside these categories I have some courses that I call here leaf courses, e.g. applied mathematics, and/or I have another subcategories, e.g. math2016.2, math2017.1, etc. and inside can have courses and/or another subcategories. So you can see I might have a lot more of subcategories inside my main categories.
What happens next is, I got 2 queries, in my first one I can return only my leaf courses, in other words, I can return the courses that are directly associated to my subcategory Extension (that is the category I want return all courses inside), but I can't return the courses inside a subcategory inside Extesion, in other words, I can't return courses inside math2016.2 and math2017.1.
In my second query I can return all courses inside the subcategory math/extension/* but the problem is, I have to pass in the query only one subcategory id, in other words, I have to pass the id of the subcategory math in one query and in another query I have to pass the id of the subcategory dance, as I have many subcategories isn't trival do this.
So I guess these queries I have can be transformed to be only one and in only one query I return all courses inside all Extension subcategories, How can I do this?
The queries follows bellow:
1) Return leaf courses of a subcategory Extension
SELECT ct.id, c.fullname, ct.name, ct.path, COUNT(ct.id) AS coursecount
FROM mdl_course_categories ct
INNER JOIN mdl_course c ON c.category=ct.id
WHERE ct.name like "Extension%"
GROUP BY ct.id, ct.name, c.fullname, ct.path
ORDER BY COUNT(ct.id) DESC
2) Returns all courses that are inside of a specific subcategory
SELECT ct.id, c.fullname, ct.name, ct.path, COUNT(ct.id) AS coursecount
FROM mdl_course_categories ct
INNER JOIN mdl_course c ON c.category=ct.id
WHERE ct.path like "/2/36/76%"
GROUP BY ct.id, ct.name, c.fullname, ct.path
ORDER BY COUNT(ct.id) DESC
In the table mdl_course_categories I have the column path, this column has tha path of the subcategory, e.g. Unity is id 2, so the path is /2, math is id 4, then the path is /2/4 (it means math is inside unity), math2017.1 is id 6, so the path is /2/4/5/6
+----+------------+----------+
| id | course | path |
+----+------------+----------+
| 2 | unity | /2 |
| 4 | math | /2/4 |
| 5 | extension | /2/4/5 |
| 6 | math2017.1 | /2/4/5/6 |
+----+------------+----------+
I also have to say that the subcategory extension has a different id to each category up him, that is, extension inside math can have id 5 but extension inside dance has another id totally different, and has no pattern.
If you are trying to get the courses in a moodle plugin you can try this:
$categories = coursecat::get(0);
foreach($categories as $category) {
$courses_in_category = $category->get_courses();//You can pass an array of options also to the method.
//Process the course array
}
You can also pass a array of options to the get_courses method. Some of options are recursive (returns courses from sub categories as well) , sort etc.
Hope this helps
You probably want something like this:
SELECT ct.id, c.fullname, ct.name, ct.path
FROM mdl_course_categories ct
JOIN mdl_course_categories basecat ON basecat.id = ct.id OR ct.path LIKE CONCAT(basecat.path, '/%')
JOIN mdl_course c ON c.category = ct.id
WHERE ct.name LIKE 'Extension%'
Notes:
This is MySQL only - if you are doing this from within Moodle itself, you can replace the 'CONCAT' part with $DB->sql_concat() for cross-db compatibility (you'd also want to use $DB->sql_like() where possible).
From your question, "ct.path LIKE '/2/36/76%'" can go wrong, as this would also match subcategories of '/2/36/761' - which is why my query has "basecat.id = ct.id OR ct.path LIKE CONCAT(basecat.path, '/%')" (comparing directly by ID, then comparing the path with a trailing '/' added).
It is not valid to get the name of each course and the number of courses in each category at the same time (you'd need to split the query into subqueries to do this) - either you're grouping by the category and getting a count of courses, or you're not grouping but getting all the courses.
tables
sample data
walls
wall_id wall_name
1 wall_1
2 wall_2
6 wall_6
wall_categories
wall_id category_id
1 2
2 1
6 1
6 2
categories
category_id category_name
1 Wallpaper
2 Photography
html
Wallpaper
Photography
What I need to do is when the user click the Wallpaper link, I want the images with wallpaper as category to be displayed same with photography. I have built an initial query but it generates duplicate records as I'm using join, there must be something else that need to be added to make it work.
SELECT DISTINCT walls.wall_id, walls.wall_name, walls.wall_views, walls.upload_date,
categories.category_name FROM categories INNER JOIN wall_categories ON
wall_categories.category_id=categories.category_id INNER JOIN walls ON
walls.wall_id=wall_categories.wall_id;
or since the category_id is fixed, we can use walls and wall_categories table only. Then lets' say we can use the following html.
Wallpaper
Photography
You're not limiting your query by category_id, so it's returning all wall records that have an associated category.
SELECT DISTINCT walls.wall_id, walls.wall_name, walls.wall_views, walls.upload_date,
categories.category_name FROM categories INNER JOIN wall_categories ON
wall_categories.category_id=categories.category_id INNER JOIN walls ON
walls.wall_id=wall_categories.wall_id
WHERE category.category_id = ?
;
And then bind ? to the appropriate category ID from your user's selection.
ive been searching for hours but cant find a solution. its a bit complicated so i'll break it down into a very simple example
i have two tables; people and cars
people:
name_id firstname
1 john
2 tony
3 peter
4 henry
cars:
name_id car_name
1 vw gulf
1 ferrari
2 mustang
4 toyota
as can be seen, they are linked by name_id, and john has 2 cars, tony has 1, peter has 0 and henry has 1.
i simply want to do a single mysql search for who has a (1 or more) car. so the anwser should be john, tony, henry.
the people table is the master table, and im using LEFT JOIN to add the cars. my problem arises from the duplicates. the fact that the table im joining has 2 entries for 1 id in the master.
im playing around with DISTINCT and GROUP BY but i cant seem to get it to work.
any help is much appreciated.
EDIT: adding the query:
$query = "
SELECT profiles.*, invoices.paid, COUNT(*) as num
FROM profiles
LEFT JOIN invoices ON (profiles.id=invoices.profileid)
WHERE (profiles.id LIKE '%$id%')
GROUP BY invoices.profileid
";
try this
select distinct p.name_id, firstname
from people p, cars c
where p.name_id = c.name_id
or use joins
select distinct p.name_id, firstname
from people p
inner join cars c
on p.name_id = c.name_id
If you only want to show people that have a car, then you should use a RIGHT JOIN. This will stop any results from the left table (people) to be returned if they didn't have a match in the cars table.
Group by the persons name to remove duplicates.
SELECT firstname
FROM people P
RIGHT JOIN cars C ON C.name_id = P.name_id
GROUP BY firstname
SELECT DISTINCT firstname
FROM people
JOIN cars ON cars.name_id = people.name_id;
If this doesn't work you might have to show us the full problem.
The way to propose it there's no need for a left join since you need at least a car per person. Left join is implicitely an OUTER join and is intended to return the results with 0 corresponding records in the joinned table.
I have a MYSQL table called 'categories' from a project I inherited from someone else.
id parent_id name
1 NULL Travel
2 NULL Sleep
3 NULL Eat
4 NULL Bath
5 1 Prams
6 1 Travel Systems
7 2 Cots
8 3 High Chairs
The table is obviously a lot bigger than that, but you get the general idea. I have a MYSQL statement which brings together this table with other category, brand and product tables, but basically I want to list the parent category name from the above table with the sub-category in the statement. How do I do this?
My current statement is something like:
SELECT brands.name, products.name, categories.id, categories.name, brands.id,
FROM `products` , `brands` , `categories`
WHERE products.brand_id = brands.id
AND products.category_id = categories.id
AND brands.name = '$brand'
ORDER BY categories.name, products.name
How do I retrieve the parent category names in the results?
For example if the product is a Pram, how can I output "Travel". I could do seperate MYSQL statements in the loop but I want to avoid this. This is either a stupidly simple question (in which case I apologise for being brain dead) or a little more complicated! Thanks.
First you need to know the parent id of the current category and then get the name for that id, you could use a subquery in this way:
SELECT name FROM categories WHERE id = (SELECT pid FROM categories WHERE name = $brand)
EDIT: Since you need to get the category and subcategory names in the same row for a given subcategory id, try this:
SELECT sc.name AS subcategory, c.name AS category
FROM categories sc
LEFT JOIN categories c ON c.id = sc.parent
WHERE sc.id = $subcategory_id
**Table parent**
parentId | name
**Table children**
childId | parentId | pictureId | age
**Table childrenPictures**
pictureId | imgUrl
no i would like to return all parent names with their eldest son's picture (only return parents that have children, and only consider children that have pictures)
so i thought of something like :
SELECT c.childId AS childId,
p.name AS parentName,
cp.imgUrl AS imgUrl,
MAX(c.age) AS age
FROM parent AS p
RIGHT JOIN children AS c ON (p.parentId = c.parentId)
RIGHT JOIN childrenPictures AS cp ON (c.pictureId = cp.pictureId))
GROUP BY p.name
This query will return each parent's eldest son's age, but the childId will not correspond to the eldest sons id, so the output does not show the right sons picture.
you need to pre-query per family to get the age of the oldest child that has an image, then get parent's name / image information... something like...
select
PreQuery.parentID,
p.Name ParentsName,
c.childID,
c.age,
cp.imgUrl
from
( select
c.parentID,
max(c.age) OldestChildAgeWithPicture
from
Children c,
childrenPictures cp
where
c.pictureID = cp.pictureID
group by
c.parentID ) PreQuery,
Parent p,
Children c,
ChildrenPictures cp
where
PreQuery.parentID = p.parentID
and PreQuery.parentID = c.parentID
and PreQuery.OldestChildAgeWithPicture = c.age
and c.pictureID = cp.pictureID
The inner query is prequalifying just by parent, childs highest age that an image exists... So, if you have a family with 3 children, oldest has no picture, 2nd oldes DOES, the the 2nd oldest is the one that will show in the above query. Additionally, what do you want to do if a family has twins, and BOTH have pictures on file. This query would show BOTH children if age is based on actual integer representation. However, if age is computed based on date arithmetic and would be more accurate... Ex: one child born Jan 1 of year X, and within the same year, another child born Dec 1.... As of December, they would be the same integer based age, but one obviously 11 months older than the other.
Additionally, if you want the oldest REGARDLESS of having a picture, the above query would have to be changed only slightly... let me know if this is what you are looking for.
Not sure but a couple of notes:
- Since you only want to return parents with matching children you can do just join.
- Could you try group by c.parentID instead of group by p.name?