MySQL Use of Having and Where Clause - mysql

Having difficulty returning the desired results.
Here is my query:
SELECT
DATABASE()AS INVOICES_Range_$0,
count(
DISTINCT invoice_lines.invoice_header_id
)AS 'Invoice Header Count',
sum(invoice_lines.accounting_total)AS 'Dollar_Value',
100 * COUNT(
DISTINCT invoice_lines.invoice_header_id
)/(
SELECT
COUNT(
DISTINCT invoice_lines.invoice_header_id
)
FROM
invoice_lines
WHERE
(
invoice_lines. STATUS NOT LIKE '%new%'
)
AND(
invoice_lines. STATUS NOT LIKE '%voided%'
)
)AS 'Percent of All Invoices',
COUNT(approvals.approvable_id)/ count(
DISTINCT invoice_lines.invoice_header_id
)AS 'AVG_APPROVALS'
FROM
invoice_lines
LEFT JOIN approvals ON invoice_lines.invoice_header_id = approvals.approvable_id
WHERE
(
invoice_lines.accounting_total = 0
)
AND(
invoice_lines. STATUS NOT LIKE '%new%'
)
AND(
invoice_lines. STATUS NOT LIKE '%voided%'
);
This query returns results where any invoice line has a value of $0.
For reference, we may have an invoice where one line is $0 but the other lines total $600.
I am wanting to only include in the above query where the total of all the invoice lines equal $0.
I've tried:
SELECT
DATABASE()AS INVOICES_Range_$0,
count(
DISTINCT invoice_lines.invoice_header_id
)AS 'Invoice Header Count',
sum(invoice_lines.accounting_total)AS 'Dollar_Value',
100 * COUNT(
DISTINCT invoice_lines.invoice_header_id
)/(
SELECT
COUNT(
DISTINCT invoice_lines.invoice_header_id
)
FROM
invoice_lines
WHERE
(
invoice_lines. STATUS NOT LIKE '%new%'
)
AND(
invoice_lines. STATUS NOT LIKE '%voided%'
)
)AS 'Percent of All Invoices',
COUNT(approvals.approvable_id)/ count(
DISTINCT invoice_lines.invoice_header_id
)AS 'AVG_APPROVALS'
FROM
invoice_lines
LEFT JOIN approvals ON invoice_lines.invoice_header_id = approvals.approvable_id
WHERE
(
invoice_lines. STATUS NOT LIKE '%new%'
)
AND(
invoice_lines. STATUS NOT LIKE '%voided%'
)
HAVING
SUM(
invoice_lines.accounting_total = 0
);
However, that returns the same results. Also, when modified to
HAVING (SUM(invoice_lines.accounting_total) < 500 )
It returns all invoices and the total amount.
Any assistance would be greatly appreciated, as I cannot determine the proper method for limiting my results to those invoice_header_id to only count those invoices where the sum of all lines is equal to 0.

HAVING
SUM(
invoice_lines.accounting_total = 0
);
probably wants to be
HAVING
SUM(
invoice_lines.accounting_total
) = 0

The solution was to evaluate in the WHERE clause using the 'Dollar Value' identified earlier in the query.
I changed the SUM(invoice_lines.accounting_total) as TOTAL
and then in the WHERE clause I added AND (TOTAL = 0);
Worked like a champ.

Related

SQL SUM if field is a specific value

I have an SQL Query that used to have inclusive <> '1' as a clause but I had to remove it to ensure I pick up all the data but I still need to count the value of the inclusive field in the SUM
Is it possible to make the SUM(customer_cost) as customer_total not include rows where inclusive <> '1'
$callChargesSql = "SELECT
customer,
source,
source_name,
calltype,
SUM(customer_cost) as customer_total,
SUM(cost) as cost,
SUM(recording_cost) as recording_cost,
SUM(recording_customer) as recording_customer
FROM
billing_calldata
WHERE
(
customer = '".db_string($result["sequence"])."' OR
customer IN
(
SELECT
sequence
FROM
customer
WHERE
resellerid = '".db_string($result["sequence"])."'
)
) AND
(
(
MONTH(timestamp) = '".db_string($calls["month"])."' AND
YEAR(timestamp) = '".db_string($calls["year"])."'
) OR
status = 'y'
)
GROUP BY customer, source, calltype
ORDER BY customer, timestamp ASC;";
In MySQL you can use IF statement within SUM operator like:
SUM(IF(inclusive = '1',customer_cost, 0)) as customer_total
Below simplified example:
select
customer_id,
sum(customer_cost) as total_customer_cost,
sum(if(inclusive=1, customer_cost, 0)) as inclusive_customer_cost
from billing_calldata
group by customer_id
;
Here you can test it: SQLize.online
In my test you can
You can use something like this: SUM(case when inclusive = '1' then customer_cost else 0 end) as customer_total
In your example query:
$callChargesSql = "SELECT
customer,
source,
source_name,
calltype,
SUM(case when inclusive = '1' then customer_cost else 0 end) as customer_total,
SUM(cost) as cost,
SUM(recording_cost) as recording_cost,
SUM(recording_customer) as recording_customer
FROM
billing_calldata
WHERE
(
customer = '".db_string($result["sequence"])."' OR
customer IN
(
SELECT
sequence
FROM
customer
WHERE
resellerid = '".db_string($result["sequence"])."'
)
) AND
(
(
MONTH(timestamp) = '".db_string($calls["month"])."' AND
YEAR(timestamp) = '".db_string($calls["year"])."'
) OR
status = 'y'
)
GROUP BY customer, source, calltype
ORDER BY customer, timestamp ASC;";

Optimizing MySQL query that includes a repeated subquery

I have the following query that is working perfectly right now, I have been trying to optimize it since I am using the same subquery 4 times. It will be great to come up with a better/smarter solution. Thank you
Here is the query:
select
invoices.invoice_id
,invoices.invoice_amount
,(
select SUM(invoice_payment_amount) as total
FROM invoice_payments
where invoice_payment_invoice_id = invoices.invoice_id
) as payments
,round((invoices.invoice_amount-(
select SUM(invoice_payment_amount) as total
FROM invoice_payments
where invoice_payment_invoice_id = invoices.invoice_id
)),2) as balance
from invoices
where (
round((invoices.invoice_amount -
(select SUM(invoice_payment_amount) as total
FROM invoice_payments
where invoice_payment_invoice_id = invoices.invoice_id)
),2)
) > 0
or (
round((invoices.invoice_amount -
(select SUM(invoice_payment_amount) as total
FROM invoice_payments
where invoice_payment_invoice_id = invoices.invoice_id)
),2)
) IS NULL
order by balance
SQL Fiddle: http://sqlfiddle.com/#!9/aecea/1
Just use a subquery:
select i.invoice_id, i.invoice_amount, i.payments,
round((i.invoice_amount- i.payments), 2) as balance
from (select i.*,
(select sum(ip.invoice_payment_amount)
from invoice_payments ip
where ip.invoice_payment_invoice_id = i.invoice_id
) as payments
from invoices i
) i
where round((i.invoice_amount- i.payments), 2) > 0 or
round((i.invoice_amount- i.payments), 2) is null
order by balance;
For better performance, you want an index on invoice_payments(invoice_payment_invoice_id, invoice_payment_amount).

Sum of a joined table

It is possible that this has been answered somewhere already but I couldn't find it.
So would appreciate if someone could help me with this sql statement again.
This is the sql statement which I have so far:
SELECT * , Round( (Rate * TIME_TO_SEC( Total ) /3600 ) , 2) AS revenue
FROM (SELECT event.eventID, event.staffID, event.role, TIMEDIFF( Time, Pause )
AS Total,
CASE WHEN Position = 'Teamleader'
THEN (Teamleader)
WHEN Position = 'Waiter'
THEN (Waiter)
ELSE '0'
END AS Rate
FROM event, rates, eventoverview
WHERE Storno =0
AND event.eventID= eventoverview.eventID
AND event.clientid = rates.clientid
GROUP BY event.eventID, event.clientID)q1
GROUP BY q1.staffID
The table I am getting is now giving me a total rate per staff and event.
But what I would like to achieve is a sum of those rates per staff.
So basically a sum of the revenue.
Hope someone can help me. Thanks in advance
You can enclose your query in a subquery and do that in the outer query like this:
SELECT *,
SUM(revenue)
FROM
(
SELECT * ,
Round( (Rate * TIME_TO_SEC( Total ) /3600 ) , 2) AS revenue
FROM
(
SELECT
event.eventID,
event.staffID,
event.role,
TIMEDIFF( Time, Pause ) AS Total,
CASE WHEN Position = 'Teamleader' THEN (Teamleader)
WHEN Position = 'Waiter' THEN (Waiter)
ELSE '0'
END AS Rate
FROM event
INNER JOIN rates ON event.clientid = rates.clientid
INNER JOIN eventoverview ON event.eventID = eventoverview.eventID
WHERE Storno =0
GROUP BY event.eventID, event.clientID
)q1
GROUP BY q1.staffID
) AS t
GROUP BY staffID;
Note that: You might get inconsistent data, due to the use of SELECT * with GROUP BY staffID only, the columns that are not in the GROUP BY clause need to be enclosed with an aggregate function otherwise mysql will get an arbitrary value for it. This is not recommended and it it is not the standard way to do so.

Mysql Self Join to find a parent child relationship in the same table

Im trying to calculate the amount of money won by all the offspring of a male race horse (Sire) over a time period. Listed by the Sire with the most amount of money won.
I run the query and get the result Im after with one problem, I cant display the sires name, only their ID.
SELECT `horses`.`SireID` AS `SireID` , `horses`.`HorseName` AS `Sire Name`,
COUNT( `runs`.`HorsesID` ) AS `Runs` ,
COUNT(
CASE WHEN `runs`.`Finish` =1
THEN 1
ELSE NULL
END ) AS `Wins` ,
CONCAT( FORMAT( (
COUNT(
CASE WHEN `runs`.`Finish` =1
THEN 1
ELSE NULL
END ) / COUNT
( `runs`.`TrainersID` ) ) *100, 0 ) , '%'
) AS `Percent` ,
FORMAT( SUM( `runs`.`StakeWon` ) , 0 ) AS `Stakes`
FROM runs
INNER JOIN horses ON runs.HorsesID = horses.HorsesID
INNER JOIN races ON runs.RacesID = races.RacesID
WHERE `races`.`RaceDate` >= STR_TO_DATE( '2012,07,01', '%Y,%m,%d' )
AND `races`.`RaceDate` < STR_TO_DATE( '2012,07,01', '%Y,%m,%d' ) + INTERVAL 1
MONTH
AND `horses`.`SireID` <> `horses`.`HorsesID`
GROUP BY `horses`.`SireID`, `horses`.`HorseName`
ORDER BY SUM( `runs`.`StakeWon` ) DESC
Take a record in the horse table for example, a horse has a horsesID and they also have a sireID (their father). The sireID has an equivalent horsesID in another record in the same table as it is also a horse
Basically I need to map the horseName to the sireID.
I thought a self join would work.
`AND `horses`.`SireID` <> `horses`.`HorsesID``
but it doesn't return the correct Sire name corresponding to the SireID.
You can do a JOIN on the table itself. Here's a simpler example:
SELECT Horses.HorseID, Horses.HorseName, Horses.SireID, b.HorseName as SireName
FROM Horses
LEFT JOIN Horses b ON (Horses.SireID = b.HorseID)
You can probably figure out how to add the conditions from here.
join horses sires on sires.HorsesID = horses.SireID

How to merge the result of this 2 queries in mysql server

I am actually stuck in merging the result of this two queries:
first query:
SELECT c.code, c.name, pc.sku, pc.cat_code, pp.title
FROM `cat_parent` cp, cat c, prod_cat pc, products pp
WHERE c.code = cp.cat_code
AND cp.cat_code = pc.cat_code
AND pp.sku = pc.sku
AND cp.parent_code = 01110
AND hide =0
The result I get is:
Second query:
SELECT `sku` , `update_date` , `description` , count( * ) AS total_sold
FROM `orderline`
WHERE `update_date` >= ( DATE_ADD(CURDATE( ) , INTERVAL -14 DAY ) )
AND `update_date` <= ( DATE_ADD(CURDATE( ) , INTERVAL -7 DAY ) )
GROUP BY left( sku, 7 )
ORDER BY total_sold DESC
The result:
The question I want to ask that how can I get the result by filtering the sku available in both tables.
Just bit confused on that part....any ideas will be appreciated.
This is only part of the data. there is heaps of data. Yes, I want to merge the both tables and want to find the common sku available in both tables.
My expected result will be sku, title, total sold.
Thanks, anyway I managed to get around to get the result.
My final query:
SELECT * FROM (
SELECT sku , update_date , description FROM orderline WHERE
update_date >= '2012-03-06' AND update_date <= '2012-03-07' )g
JOIN (
SELECT c.code, c.name, pc.sku, pc.cat_code FROM cat_parent cp, cat
c, prod_cat pc, products pp WHERE c.code = cp.cat_code AND cp.cat_code
= pc.cat_code AND pp.sku = pc.sku AND cp.parent_code =01110 AND hide =0 )p ON left( g.sku, 7 ) = left( p.sku, 7 )
Something like this -
SELECT
`c`.`code`, `c`.`name`, `pc`.`sku`, `pc`.`cat_code`, `pp.title`,
`ol`.`sku`, `ol`.`update_date`, `ol`.`description`, COUNT(*) AS `total_sold`
FROM `cat_parent` `cp`
INNER JOIN `cat` `c`
ON `c`.`code` = `cp`.`cat_code`
INNER JOIN `prod_cat` `pc`
ON `cp`.`cat_code` = `pc`.`cat_code`
INNER JOIN `products` `pp`
ON `pp`.`sku` = `pc`.`sku`
INNER JOIN `orderline` `ol`
ON LEFT(`pc`.`sku`, 7) = LEFT(`ol`.`sku`, 7)
WHERE `cp`.`parent_code` = 01110
AND `hide` = 0
AND `ol`.`update_date` >= ( DATE_ADD(CURDATE( ) , INTERVAL -14 DAY ) )
AND `ol`.`update_date` <= ( DATE_ADD(CURDATE( ) , INTERVAL -7 DAY ) )
GROUP BY left( `ol`.`sku`, 7 )
ORDER BY `total_sold` DESC