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.
Related
i have tables below
catalog_product_entity
entity_id
sku
type
1
1-1669197697
bundle
2
skua
single
3
skub
single
4
skuc
single
catalog_product_bundle_selection
parent_product_id
product_id
1
2
1
3
1
4
promotion
sku
1-1669197697
product_shipping
product_id
code
2
jne
2
jnt
3
jne
3
jnt
4
jne
4
jnt
and the sample queries
SELECT e.*, COUNT(DISTINCT bundle.product_id) AS children FROM catalog_product_entity AS e
INNER JOIN product_promotion AS promotion ON promotion.sku = e.sku
INNER JOIN catalog_product_bundle_selection AS bundle ON bundle.parent_product_id = e.entity_id
INNER JOIN product_shipping AS shipping ON shipping.product_id = bundle.product_id
INNER JOIN (
SELECT COUNT(DISTINCT bundle.product_id) AS total_item, product.sku
FROM catalog_product_bundle_selection AS bundle
INNER JOIN catalog_product_entity AS product ON product.entity_id = bundle.parent_product_id
INNER JOIN product_promotion AS promotion ON promotion.sku = product.sku
GROUP BY product.sku
) AS summary ON summary.sku = e.sku
GROUP BY e.entity_id, shipping.code, summary.total_item
HAVING COUNT(DISTINCT bundle.product_id) = summary.total_item
and the result is
There is a bundle with 3 items that have different shipping, but same as the others. The point is i want to get the data bundle with condition if the items have at least one or more similar shipping.
how can i retrieve only one record without put the above query inside subquery and group it by parent, anyone can help?
I have 2 tables, this is my fiddle http://sqlfiddle.com/#!9/da5e4e/3
so basically i have 2 tables called personal and interview_score with personal.id = interview_score.personal_id.
assume this is my personal table
id name
1 John Doe
2 Nian
3 Rijali
and this is my interview_score table
id personal_id aspect_id
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
on this case, i just want to count how many personal_id in my interview_score table with this query
SELECT COUNT(i.id) as interviewed FROM personal p LEFT JOIN interview_score i ON i.personal_id = p.id GROUP BY i.personal_id;
but it returns just like this
interviewed
0
3
2
meanwhile, my expected result is just like this
interviewed
2
because on that table there are 2 personal_id based on that condition.
where my wrong at?
You can use join instead of left join also you need to group by p.id
SELECT COUNT(i.id) as interviewed FROM personal p JOIN interview_score i ON i.personal_id = p.id GROUP BY p.id;
from the above query you can get the count
To get count for a particular person
SELECT COUNT(i.id) as interviewed FROM personal p JOIN interview_score i ON i.personal_id = p.id and p.id=1 GROUP BY p.id;
Problem:
I'm having trouble finding a solution building a query with QueryBuilder (perhaps getting it done with regular sql query first will help):
Trying to retrieve all customers for a user (has shop credits at one of the shops user is linked to), need the total credits (sum of credits at shops belonging to that user) as virtual column (to be able to order on), using paginate().
Database structure:
Table customers
id email other_fields
1 1#email.com f
2 2#email.com o
3 3#email.com o
Table users
id email other_fields
1 1#user.com b
2 2#user.com a
3 3#user.com r
Table shops
id name other_fields
1 Shop 1 m
2 Shop 1 o
3 Shop 1 o
Table user_shops
user_id shop_id
1 1
1 2
3 3
Table customer_shop_credits
customer_id shop_id credits
1 1 55
1 2 45
2 2 3
3 3 44
Expected result:
When retrieving customers for user 1, I'd expect to get back customer 1 with 100 credits and customer 2 with 3 credits
Closest I got:
$credits_query = CustomerShopCreditQuery::create()
->useShopQuery()
->useUserShopQuery()
->filterByUserId($user->getId())
->endUse()
->endUse()
;
$customers = CustomerQuery::create()
->addSelectQuery($credits_query, 'credits_alias', false)
->useCustomerShopCreditQuery()
->useShopQuery()
->useUserShopQuery()
->filterByUserId($user->getId())
->endUse()
->endUse()
->endUse()
->withColumn('sum(credits_alias.credits)', 'credits')
->groupById()
->orderBy($order_by_column, $direction)
->paginate($page, $page_size);
Which results in the following query:
SELECT customers.id, customers.email, sum(credits_alias.credits) AS credits
FROM customers
CROSS JOIN (
SELECT customer_shop_credits.id, customer_shop_credits.customer_id, customer_shop_credits.shop_id, customer_shop_credits.credits
FROM customer_shop_credits
INNER JOIN shops ON (customer_shop_credits.shop_id=shops.id)
INNER JOIN user_shops ON (shops.id=user_shops.shop_id)
WHERE user_shops.user_id=159
) AS credits_alias
INNER JOIN customer_shop_credits ON (customers.id=customer_shop_credits.customer_id)
INNER JOIN shops ON (customer_shop_credits.shop_id=shops.id)
INNER JOIN user_shops ON (shops.id=user_shops.shop_id)
WHERE user_shops.user_id=159
GROUP BY customers.id
ORDER BY customers.id DESC
LIMIT 25
But gives me results with wrong sum of credits.
Not to sure about the CROSS JOIN. When I edit this query and make it a JOIN and use ON (credits_alias.customer_id = customers.id) as a condition, the sum of credits is better, but seems to have the classic join problem of doubling the sum
I'm struggling to get my head around MySQL joins. I have three tables
-- events
id name
1 Event 1
2 Event 2
-- registrations
id event name
1 1 Alice
2 1 Bob
3 2 Alice
4 2 Charlie
-- scores
id event name score
1 1 Alice 10
2 1 Charlie 20
3 2 Alice 15
4 2 Bob 30
For each event I'm trying to work out
How many people registered (rows in registration table) but did NOT get a score (exclude rows in scores table)
How many people got a score (rows in scores table) but did NOT register (exclude rows in registration table)
How many people BOTH registered and got a score
I've tried different variations of
SELECT *
FROM registrations r
LEFT JOIN scores s
ON r.event = s.event
WHERE s.event IS NULL
AND r.event = 1
but I'm not sure what I should be joining on: event or name but neither are null and I never seem to get the correct numbers I'm looking for. The result at the end should be like
name reg_only score_only reg&score total
event Event 1 1 1 1 3
You can use below 3 queries in same sequence as you mentioned in your query-
SELECT e.id, e.name, COUNT(r.id) AS registered_user
FROM `events` AS e
INNER JOIN registrations AS r ON e.id=r.event
LEFT JOIN scores AS s ON e.id = s.event
WHERE s.event IS NULL;
SELECT e.id, e.name, COUNT(r.id) AS scored_user
FROM `events`scores AS e
INNER JOIN scores AS s ON e.id=s.event
LEFT JOIN registrations AS r ON e.id = r.event
WHERE r.event IS NULL;
SELECT e.id, e.name, COUNT(*) AS both_user
FROM `events` AS e
INNER JOIN registrations AS r ON e.id=r.event
INNER JOIN scores AS s ON e.id = s.event;
My tables
product
pid name
1 AA
2 bb
3 cc
History table
hid pid uid
1 1 1
2 1 2
3 1 1 // this one should join with pid 1
4 3 2 // this one should join with pid 3
5 2 3
6 2 1 // this one should join with pid 2
I like to display most recent bidder on a product.The history tables stores bidder
details.if no bid on product just need to return null.
Thanks
How about something like
SELECT *
FROM product p LEFT JOIN
(
SELECT ht.*
FROM History_table ht INNER JOIN
(
SELECT pid,
MAX(hid) last_hid
FROM History_table ht
GROUP BY pid
) lstItem ON ht.pid = lstItem.pid
AND ht.hid = lstItem.last_hid
) ht ON p.pid = ht.pid
First you need to retrieve the MAX hid per pid, which by definition should be the most recent entry.
Then join that back to the same history table to retrieve the uid.
And lastly join this (LEFT JOIN) back to the actual products table.
Hope that helps.