sql join and sum 3 - mysql

I have problem with join and sum column. My query is
SELECT
sum(IFNULL(`worker_hours`.`godziny`, 0)) as godziny,
sum(IFNULL(`worker_hours`.`wartosc`, 0)) as wartosc,
sum(IFNULL(`worker_cashes`.`kwota`, 0)) as kwota,
`workers`.*
FROM
`workers`
LEFT join `worker_hours` on `worker_hours`.`pracownik` = `workers`.`id`
LEFT join `worker_cashes` on `worker_cashes`.`pracownik` = `workers`.`id`
WHERE `workers`.`id_user` = '3'
group by
`workers`.`id`
The result sum *2 my query, what i do wrong? in i have this query is fine:
SELECT
sum(IFNULL(`worker_hours`.`godziny`, 0)) as godziny,
sum(IFNULL(`worker_hours`.`wartosc`, 0)) as wartosc,
`workers`.*
FROM
`workers`
left join `worker_hours` on `worker_hours`.`pracownik` = `workers`.`id`
WHERE `workers`.`id_user` = '3'
group by
`workers`.`id`
the problem is the second left join

You should aggregate first in the tables worker_hours and worker_cashes and then join workers to the resultsets of the aggregations so that you don't get the same row multiple times due to the multiple joins:
SELECT w.*,
COALESCE(h.godziny, 0) AS godziny,
COALESCE(h.wartosc, 0) AS wartosc,
COALESCE(c.kwota, 0) AS kwota
FROM workers AS w
LEFT JOIN (
SELECT pracownik,
SUM(godziny) AS godziny,
SUM(wartosc) AS wartosc
FROM worker_hours
GROUP BY pracownik
) AS h ON h.pracownik = w.id
LEFT JOIN (
SELECT pracownik,
SUM(kwota) AS kwota
FROM worker_cashes
GROUP BY pracownik
) AS c ON c.pracownik = w.id
WHERE w.id_user = '3';

Related

how to limit record in left join

SELECT commerce_product_field_data_commerce_product__field_data_field_products.entity_id, field_products_commerce_product.nid FROM commerce_order o
join commerce_payment_transaction t on o.order_id = t.order_id
join commerce_line_item i on o.order_id = i.order_id
LEFT JOIN field_data_commerce_total s ON i.line_item_id = s.entity_id AND (s.entity_type = 'commerce_line_item' AND s.deleted = '0')
LEFT JOIN field_data_commerce_product field_data_commerce_product ON i.line_item_id = field_data_commerce_product.entity_id AND (field_data_commerce_product.entity_type = 'commerce_line_item' AND field_data_commerce_product.deleted = '0')
INNER JOIN commerce_product commerce_product_field_data_commerce_product ON field_data_commerce_product.commerce_product_product_id = commerce_product_field_data_commerce_product.product_id
LEFT JOIN
(select * from field_data_field_products)
commerce_product_field_data_commerce_product__field_data_field_products ON commerce_product_field_data_commerce_product.product_id = commerce_product_field_data_commerce_product__field_data_field_products.field_products_product_id
LEFT JOIN ( select nid as nid from node order by nid)
field_products_commerce_product
ON commerce_product_field_data_commerce_product__field_data_field_products.entity_id = field_products_commerce_product.nid LEFT JOIN (
select r.entity_id, r.field_ranges_value from field_data_field_ranges r
) r
on r.entity_id = field_products_commerce_product.nid
WHERE t.status = 'success' and i.type = 'product' and o.Uid <> 0
AND o.status IN ('completed') and o.created >= '1483228800' and o.created <= '1483315200' and r.field_ranges_value = 'Tasty Sticks'
Is my sql
It is giving me 5 results. I only need 4
One of the product id's belong to two Drupal nodes and I only want one of them
I tried changing LEFT JOIN ( select nid as nid from node order by nid) to
LEFT JOIN ( select nid as nid from node order by nid limit 1) but then I don't get any records at all. Any idea what needs changing please other than removing one of the duplicate nodes. Thanks

SQL Query Aggregate Function

This is my query:
select a.id, a.title,count(x.id) as Orders
-- from x_vendordeliveriesareas vda
-- left join x_vendordeliveries vd
-- on vd.id = vda.vendordelivery_id
from x_orders x
left join x_areas a
on x.delivery_area_id = a.id
-- on vda.area_id = a.id
-- left join x_orders x
left join x_vendors v
on v.id = x.vendor_id
where v.title like 'golden dragon%' and (date_format(x.date,'%Y-%m-%d') BETWEEN '2015-01-01' AND '2015-06-30')
and x.status_id=11
and x.country_id =11
and v.city_id=3
group by 1;
This works perfectly fine, but I want to return those areas to which have 0 orders.
I have tried IFNULL and coalesce functions
Your driving table should be x_areas:
select
a.id,
a.title,
coalesce(count(x.id), 0) as Orders
from x_areas a
left join x_orders x
on x.delivery_area_id = a.id
and x.status_id = 11
and x.country_id = 11
and (date_format(x.date,'%Y-%m-%d') BETWEEN '2015-01-01' AND '2015-06-30')
left join x_vendors v
on v.id = x.vendor_id
where
v.title like 'golden dragon%'
and v.city_id = 3
group by 1;
Note that I moved some of your WHERE conditions in the ON clause to prevent the LEFT JOIN from turning into an INNER JOIN, thus giving the same result, with the added x_areas with 0 Orders.

How to join 2 queries

I have 2 SQL queries:
SELECT accounts.assigned_user_id, jt0.user_name assigned_user_name,
SUM( IF(opp.opportunity_type='2', IFNULL(opp.amount,0), 0) ) AS amt_revenue,
SUM( IF(opp.opportunity_type='4', IFNULL(opp.amount,0), 0) ) AS amt_return
FROM accounts
LEFT JOIN users jt0
ON jt0.id=accounts.assigned_user_id AND jt0.deleted=0 AND jt0.deleted=0
LEFT JOIN accounts_opportunities AS a_o
ON a_o.account_id = accounts.id AND a_o.deleted=0
LEFT JOIN opportunities AS opp
ON (opp.id = a_o.opportunity_id AND opp.deleted=0 AND opp.sales_stage = 'Closed Won' AND opp.opportunity_type IN('2', '4'))
WHERE accounts.deleted=0
GROUP BY accounts.assigned_user_id, jt0.user_name
ORDER BY SUM(IFNULL(opp.amount,0)) DESC
And:
SELECT accounts.assigned_user_id,
SUM( IFNULL(accounts_collections.amount,0)) AS amount
FROM accounts
LEFT JOIN accounts_collections ON(accounts_collections.account_id = accounts.id AND accounts_collections.deleted=0)
GROUP BY accounts.assigned_user_id
How can I join the 2 queries above?
You may be able to put the second query into a subselect. There are two ways of doing this. In the select section or in the form section. Not sure which MySQL accepts but both work in other SQL engines.
SELECT
accounts.assigned_user_id,
jt0.user_name assigned_user_name,
SUM( IF(opp.opportunity_type='2',
IFNULL(opp.amount,0), 0)
) AS amt_revenue,
SUM( IF(opp.opportunity_type='4',
IFNULL(opp.amount,0), 0)
) AS amt_return,
(
SELECT SUM( IFNULL(accounts_collections.amount,0)) AS amount
FROM accounts
LEFT JOIN accounts_collections ON(accounts_collections.account_id = accounts.id AND accounts_collections.deleted=0)
GROUP BY accounts.assigned_user_id
) AS amount
FROM accounts
LEFT JOIN users jt0
ON jt0.id=accounts.assigned_user_id AND jt0.deleted=0 AND jt0.deleted=0
LEFT JOIN accounts_opportunities AS a_o
ON a_o.account_id = accounts.id AND a_o.deleted=0
LEFT JOIN opportunities AS opp
ON (opp.id = a_o.opportunity_id AND opp.deleted=0 AND opp.sales_stage = 'Closed Won' AND opp.opportunity_type IN('2', '4'))
WHERE accounts.deleted=0
GROUP BY accounts.assigned_user_id, jt0.user_name
ORDER BY SUM(IFNULL(opp.amount,0)) DESC
SELECT
accounts.assigned_user_id,
jt0.user_name assigned_user_name,
SUM( IF(opp.opportunity_type='2',
IFNULL(opp.amount,0), 0)
) AS amt_revenue,
SUM( IF(opp.opportunity_type='4',
IFNULL(opp.amount,0), 0)
) AS amt_return,
amount_tbl.amount
FROM accounts
LEFT JOIN users jt0
ON jt0.id=accounts.assigned_user_id AND jt0.deleted=0 AND jt0.deleted=0
LEFT JOIN accounts_opportunities AS a_o
ON a_o.account_id = accounts.id AND a_o.deleted=0
LEFT JOIN opportunities AS opp
ON (opp.id = a_o.opportunity_id AND opp.deleted=0 AND opp.sales_stage = 'Closed Won' AND opp.opportunity_type IN('2', '4'))
JOIN (
SELECT accounts.assigned_user_id,
SUM( IFNULL(accounts_collections.amount,0)) AS amount
FROM accounts
LEFT JOIN accounts_collections ON(accounts_collections.account_id = accounts.id AND accounts_collections.deleted=0)
GROUP BY accounts.assigned_user_id
) AS amount_tbl ON (amount_tbl.assigned_user_id = accounts.assigned_user_id)
WHERE accounts.deleted=0
GROUP BY accounts.assigned_user_id, jt0.user_name
ORDER BY SUM(IFNULL(opp.amount,0)) DESC

MySQL COUNT query with or without HAVING clause giving same results

I am having issues with an SQL query which involves a COUNT and a HAVING clause.
The objective is to get the count of all products that have stock and are also not being 'picked' for another customer hence the HAVING clause.
However, when the query is run both with and without the HAVING clause at the end of the query below I get the same COUNT as the result.
To ensure that the COUNT results should not be the same I tried running queries to check if there were products that were out of stock since all products will need to be in stock for the results to match up and confirmed that there were definitely products out of stock.
SELECT
COUNT(DISTINCT p.product_id)
FROM product p
LEFT JOIN product_variant pv
ON pv.product_variant_id = p.product_id
LEFT JOIN depot_product_stock dps
ON dps.product_variant_id = pv.product_variant_id
LEFT JOIN (
SELECT pii.quantity, pii.product_variant_id
FROM `picklist_item` pii
WHERE pii.STATUS IN ('not picked')
) AS pickListNotPicked
ON pickListNotPicked.product_variant_id = pv.product_variant_id
LEFT JOIN (
SELECT pii.quantity, pii.product_variant_id
FROM `picklist_item` pii
LEFT JOIN `packing` packi ON packi.picklist_id = pii.picklist_id
WHERE pii.STATUS IN ('picked')
AND pii.date_picked > NOW() - INTERVAL 2 WEEK
AND packi.picklist_id IS NULL
) AS pickListPicked
ON pickListPicked.product_variant_id = pv.product_variant_id
LEFT JOIN (
SELECT pii.quantity, pii.product_variant_id
FROM `picklist_item` pii
LEFT JOIN `packing` packi ON packi.picklist_id = pii.picklist_id
WHERE packi.`status` IN ('new', 'in progress')
) AS pickListInProgress
ON pickListInProgress.product_variant_id = pv.product_variant_id
WHERE p.deleted = 0
HAVING SUM(dps.physical_stock)
- ifnull(SUM(pickListNotPicked.quantity),0)
- ifnull(SUM(pickListPicked.quantity) ,0)
- ifnull(SUM(pickListInProgress.quantity) ,0)
> 0
I don't know where I'm going wrong with the query. Kindly help. Thanks.
I don't think you want a having clause. Your query is just returning one row. That having clause might have it return zero rows instead of 1 row. And, the having clause is looking over all the products.
Perhaps you want a where clause instead:
WHERE p.deleted = 0 AND
(dps.physical_stock - ifnull(pickListNotPicked.quantity, 0) -
ifnull(pickListPicked.quantity, 0)
ifnull(pickListInProgress.quantity, 0)
) > 0
Note that I prefer replacing ifnull() with coalesce(). (When given the option, I generally prefer the ANSI standard functions.)
I think the issue is that you are mixing up all the quantities to check.
Your query appears to be trying to find a count of products where the physical stock quantity is not equal the the sum of the quantities in various status'.
The trouble is that you are SUMing up all the stock quanties and pick quantities for ALL products. Thus if any single product has a mismatch it will be reflected in the check in the HAVING clause.
I think you need one large sub query to get all the product ids where the quantities do not match, and then do a count based on that.
Something like this (untested).
SELECT COUNT(product_id)
FROM
(
SELECT p.product_id
FROM product p
LEFT JOIN product_variant pv
ON pv.product_variant_id = p.product_id
LEFT JOIN depot_product_stock dps
ON dps.product_variant_id = pv.product_variant_id
LEFT JOIN
(
SELECT pii.quantity, pii.product_variant_id
FROM `picklist_item` pii
WHERE pii.STATUS IN ('not picked')
) AS pickListNotPicked
ON pickListNotPicked.product_variant_id = pv.product_variant_id
LEFT JOIN
(
SELECT pii.quantity, pii.product_variant_id
FROM `picklist_item` pii
LEFT JOIN `packing` packi ON packi.picklist_id = pii.picklist_id
WHERE pii.STATUS IN ('picked')
AND pii.date_picked > NOW() - INTERVAL 2 WEEK
AND packi.picklist_id IS NULL
) AS pickListPicked
ON pickListPicked.product_variant_id = pv.product_variant_id
LEFT JOIN
(
SELECT pii.quantity, pii.product_variant_id
FROM `picklist_item` pii
LEFT JOIN `packing` packi ON packi.picklist_id = pii.picklist_id
WHERE packi.`status` IN ('new', 'in progress')
) AS pickListInProgress
ON pickListInProgress.product_variant_id = pv.product_variant_id
WHERE p.deleted = 0
GROUP BY p.product_id
HAVING SUM(dps.physical_stock)
- IFNULL(SUM(pickListNotPicked.quantity),0)
- IFNULL(SUM(pickListPicked.quantity) ,0)
- IFNULL(SUM(pickListInProgress.quantity) ,0)
> 0
) sub0
You might be able to remove some of the sub queries you already have like this:-
SELECT COUNT(DISTINCT p.product_id)
FROM
(
SELECT p.product_id
FROM product p
LEFT JOIN product_variant pv
ON pv.product_variant_id = p.product_id
LEFT JOIN depot_product_stock dps
ON dps.product_variant_id = pv.product_variant_id
LEFT JOIN
(
SELECT pii.product_variant_id,
SUM(IF(pii.STATUS IN ('not picked')), quantity, 0) AS pickListNotPicked_qty,
SUM(IF(pii.STATUS IN ('picked') AND pii.date_picked > NOW() - INTERVAL 2 WEEK AND packi.picklist_id IS NULL), quantity, 0) AS pickListPicked_qty,
SUM(IF(packi.`status` IN ('new', 'in progress')), quantity, 0) AS pickListInProgress_qty
FROM `picklist_item` pii
LEFT JOIN `packing` packi ON packi.picklist_id = pii.picklist_id
GROUP BY pii.product_variant_id
) AS quantities
ON quantities.product_variant_id = pv.product_variant_id
WHERE p.deleted = 0
GROUP BY p.product_id
HAVING SUM(dps.physical_stock)
- IFNULL(SUM(pickListNotPicked_qty),0)
- IFNULL(SUM(pickListPicked_qty) ,0)
- IFNULL(SUM(pickListInProgress_qty) ,0)
) sub0
This might be further cleaned down to :-
SELECT COUNT(DISTINCT p.product_id)
FROM
(
SELECT p.product_id
FROM product p
LEFT JOIN product_variant pv
ON pv.product_variant_id = p.product_id
LEFT JOIN depot_product_stock dps
ON dps.product_variant_id = pv.product_variant_id
LEFT JOIN
(
SELECT pii.product_variant_id,
SUM(quantities) AS relevant_qty
FROM `picklist_item` pii
LEFT JOIN `packing` packi ON packi.picklist_id = pii.picklist_id
WHERE pii.STATUS = 'not picked'
OR (pii.STATUS = 'picked' AND pii.date_picked > NOW() - INTERVAL 2 WEEK AND packi.picklist_id IS NULL)
OR packi.`status` IN ('new', 'in progress')
GROUP BY pii.product_variant_id
) AS quantities
ON quantities.product_variant_id = pv.product_variant_id
WHERE p.deleted = 0
GROUP BY p.product_id
HAVING SUM(dps.physical_stock)
- IFNULL(SUM(relevant_qty) ,0)
) sub0
Note that I am slightly unsure of your sum logic if I understand your requirement correctly. You could items that are not picked and items picked in the last week. You also count items that have a status of new or in progress, yet it would seem these items could already have been counted as picked / not picked, hence double counted for the sums and ensuring that the final sums did not match and the items were used for the count of product ids.

SQL Query Problem

I've been at this for a bit now. Basically, I'm needing to add a derived column to count the hits to a weblog entry in the database. The problem is, the hits are being totaled and shown on only on the first record. Any Ideas? I've emboldened the parts of the query I'm talking about. The query is below:
SELECT DISTINCT(t.entry_id),
exp_categories.rank,
**exp_hits.hits,**
t.entry_id,
t.weblog_id,
t.forum_topic_id,
t.author_id,
t.ip_address,
t.title,
t.url_title,
t.status,
t.dst_enabled,
t.view_count_one,
t.view_count_two,
t.view_count_three,
t.view_count_four,
t.allow_comments,
t.comment_expiration_date,
t.allow_trackbacks,
t.sticky,
t.entry_date,
t.year,
t.month,
t.day,
t.entry_date,
t.edit_date,
t.expiration_date,
t.recent_comment_date,
t.comment_total,
t.trackback_total,
t.sent_trackbacks,
t.recent_trackback_date,
t.site_id as entry_site_id,
w.blog_title,
w.blog_name,
w.search_results_url,
w.search_excerpt,
w.blog_url,
w.comment_url,
w.tb_return_url,
w.comment_moderate,
w.weblog_html_formatting,
w.weblog_allow_img_urls,
w.weblog_auto_link_urls,
w.enable_trackbacks,
w.trackback_use_url_title,
w.trackback_field,
w.trackback_use_captcha,
w.trackback_system_enabled,
m.username,
m.email,
m.url,
m.screen_name,
m.location,
m.occupation,
m.interests,
m.aol_im,
m.yahoo_im,
m.msn_im,
m.icq,
m.signature,
m.sig_img_filename,
m.sig_img_width,
m.sig_img_height,
m.avatar_filename,
m.avatar_width,
m.avatar_height,
m.photo_filename,
m.photo_width,
m.photo_height,
m.group_id,
m.member_id,
m.bday_d,
m.bday_m,
m.bday_y,
m.bio,
md.*,
wd.*
FROM exp_weblog_titles AS t
LEFT JOIN exp_weblogs AS w ON t.weblog_id = w.weblog_id
LEFT JOIN exp_weblog_data AS wd ON t.entry_id = wd.entry_id
LEFT JOIN exp_members AS m ON m.member_id = t.author_id
LEFT JOIN exp_member_data AS md ON md.member_id = m.member_id
LEFT JOIN exp_category_posts ON wd.entry_id = exp_category_posts.entry_id
**LEFT JOIN
(
SELECT COUNT(*) AS hits, exp_hits.entry_id FROM exp_hits ORDER BY exp_hits.entry_id
) exp_hits ON t.entry_id = exp_hits.entry_id**
LEFT JOIN
(
SELECT exp_categories.cat_id, cat_name as rank
FROM exp_categories
WHERE exp_categories.group_id = '9'
) exp_categories ON exp_categories.cat_id = exp_category_posts.cat_id
WHERE t.entry_id IN (2,3,4) ORDER BY exp_categories.rank DESC, **exp_hits.hits DESC**, entry_date desc
Try changeing the subselect to
SELECT COUNT(*) AS hits,
exp_hits.entry_id
FROM exp_hits
GROUP BY exp_hits.entry_id
Out of curiosity, is your hits functionality something that can't be accomplished with the view_count_one/two/three/four fields already present in the database and supported by ExpressionEngine template tags?