SQL query not returning expect result - mysql

I wrote the following query to return some statistics about purchases made in the X amount of time. But for some reason every "COUNT" column return the total number of rows. Did I organize the query incorrectly?
SELECT COUNT(*) as countTotal, SUM(`cost`) as cost, COUNT(`paymentType` = 'credit') as count_credit, COUNT(`paymentType` = 'cash') as count_cash
FROM `purchase` WHERE `date` >= '2011-5-4'
update
I just decided to use sub-queries. This is what I ended up with.
SELECT
COUNT(*) as countTotal,
SUM(`cost`) as cost,
(SELECT COUNT(*) FROM `purchase` WHERE `paymentType` = 'credit') as count_credit,
(SELECT COUNT(*) FROM `purchase` WHERE `paymentType` = 'cash') as count_cash
FROM `purchase` WHERE `date` >= '2011-5-4'
update2
Used ypercubes answer below.

count does return the number of rows for the domain or group queried. Looks like you need to group by PaymentType to achieve what you are looking for.
SELECT PaymentType, COUNT(*) as countTotal, SUM(`cost`) as cost,
FROM `purchase`
WHERE `date` >= '2011-5-4'
Group by PaymentType
here is a reference
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

It doesn't look correct but changing COUNT() to SUM() works fine:
SELECT COUNT(*) AS countTotal
, SUM(cost) AS cost
, SUM(paymentType = 'credit') AS count_credit --- SUM does counting here
, SUM(paymentType = 'cash') AS count_cash --- and here
FROM purchase
WHERE `date` >= '2011-05-04'
Explanation: True == 1 and False == 0 for MySQL.

You need a GROUP BY clause after your WHERE clause

Related

How do I retrieve data from two tables?

I was on the "hospital_payment_data" table.
I want to call up the data of the number of data, the cache_account_received sum, and the total_medical_bills sum, and then bring up the mount sum value from the cash_recipit_rowtable to express. What should I do?
hospital_payment_data
cash_receipt_row
I want result
However, sending the following queries results in the following:
SELECT
COUNT(*) as total,
SUM(cash_amount_received) AS sum_cash_amount_received,
COUNT(
IF(total_medical_bills >= 100000 AND
cash_amount_received , total_medical_bills, NULL)
) as obligatory_issue,
SUM(
IF(total_medical_bills >= 100000 AND
cash_amount_received , cash_amount_received, NULL)
) as sum_obligatory_issue,
SUM(amount) AS sum_amount
FROM (
SELECT total_medical_bills, cash_amount_received, amount
FROM hospital_payment_data, cash_receipt_row
) AS a
wrong result
Try this.
SELECT
COUNT(*) as total,
SUM(cash_amount_received) AS sum_cash_amount_received,
COUNT(
IF(total_medical_bills >= 100000 AND
cash_amount_received , total_medical_bills, NULL)
) as obligatory_issue,
SUM(
IF(total_medical_bills >= 100000 AND
cash_amount_received , cash_amount_received, NULL)
) as sum_obligatory_issue,
SUM(amount) AS sum_amount
FROM (
SELECT total_medical_bills, cash_amount_received, amount
FROM hospital_payment_data, cash_receipt_row
WHERE hospital_payment_data.id = cash_receipt_row.id
) AS a
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
You can also simplify your counting logic in MySQL. There is no need for IF() or a subquery:
SELECT COUNT(*) as total,
SUM(cash_amount_received) AS sum_cash_amount_received,
SUM( total_medical_bills >= 100000 AND
obligatory_issue <> 0
) as obligatory_issue,
SUM(CASE WHEN total_medical_bills >= 100000
THEN cash_amount_received
END) as sum_obligatory_issue,
SUM(amount) AS sum_amount
FROM hospital_payment_data hpd JOIN
cash_receipt_row crr
ON hpd.id = crr.id;
You'll notice that where conditional logic is needed, then this uses the standard SQL construct, CASE, rather than IF.

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).

Let me know if i can optimize this query?

does anybody have any suggestions to optimize this query :
SELECT COUNT(client_id) FROM (
SELECT client_id FROM `cdr` WHERE
(DATE(start) BETWEEN '2014-04-21' AND '2014-04-25') AND
`service` = 'test'
GROUP BY client_id
HAVING SUM(duration) > 300
)as t1
The problem is , inner query scans millions of rows and returns thousands of rows and it makes main query lazy.
Thanks.
Try below query, avoid functions in searching as it does not use index and kill the performance. "start" columns must be indexed.
SELECT COUNT(client_id) FROM (
SELECT client_id FROM `cdr` WHERE
(start BETWEEN '2014-04-21 00:00:00' AND '2014-04-25 23:59:59') AND
`service` = 'test'
GROUP BY client_id
HAVING SUM(duration) > 300
)as t1
Why not this?I have read somewhere that comparing dates directly with < or > works faster than Between.
SELECT Count(client_id) FROM `cdr`
WHERE DATE(start) >= '2014-04-21'
AND DATE(start) <= '2014-04-25'
AND `service` = 'test'
GROUP BY client_id
HAVING SUM(duration) > 300
What was logic behind having sub query in your sql?
you can use direct query instead of sub query like as
SELECT COUNT(client_id) FROM `cdr`
WHERE (DATE(start) BETWEEN '2014-04-21' AND '2014-04-25')
AND `service` = 'test'
GROUP BY client_id
HAVING SUM(duration) > 300

View - Return 0 if no rows found in a grouped by query

Let's say I have the following MySQL view:
create or replace view total_transactions(account_id, total) as
select
t.account_id,
ifnull(sum(t.value), 0) as total
from transactions t
where t.paid IS TRUE
group by t.bank_account_id;
Let's say the account doesn't have any transaction yet, I want the view to return 0.
Right now, if I do a select like:
select * from total_transactions where account_id = 2060;
And account 2060 didn't had any transaction, it will return me nothing, instead of 0.
How could I fix that?
Thanks in advance.
EDIT
I think it could be something with the group by...
If I execute the query that I'm using for the view without the group by, it works (return 0 even with no results), but if I use group by it comes null:
select
t.account_id,
ifnull(sum(t.value), 0) as total
from transactions t
where t.paid IS TRUE
and account_id = 2060;
Returns 0, and
create or replace view total_transactions(account_id, total) as
select
t.account_id,
ifnull(sum(t.value), 0) as total
from transactions t
where t.paid IS TRUE
and account_id = 2060
group by t.bank_account_id;
Return an empty set.
If there is not an entry in the view results, then this will always return NULL - That's SQL. If you change your SELECT that you use against the view, you can achieve what you want:
SELECT IFNULL(total, 0) FROM total_transactions WHERE account_id = 2060
Edit:
(SELECT IFNULL(total, 0) total FROM total_transactions WHERE account_id = 2060)
UNION
(SELECT 0 total)
In production, don't use SELECT *. See this SO question for a thorough response as to why.
So, assuming you're not, you can use COALESCE, which will return the first non-null value.
SELECT
COALESCE(total, 0)
FROM
total_transactions
WHERE
account_id = '2600'
For positive values I use
select max(x.cnt) as cnt
from (
select ifnull(meta_value, 0) as cnt from wp_postmeta where post_id = 5543 and meta_key = '_bbp_voice_count'
union
select 0 as cnt) x
or for any
select x.cnt
from (
select ifnull(meta_value, 0) as cnt from wp_postmeta where post_id = 5543 and meta_key = '_bbp_voice_count'
union
select 0 as cnt
) x
limit 1

MySQL SELECT Query - Subtract a SUM() value with the combined total of two other SUM() values

I have two SELECT statements that give the values "TotalSales" and "VendorPay_Com". I want to be able to subtract VendorPay_Com from TotalSales within the one MySQL statement to get the value "Outstanding_Funds" but I haven't found a reliable way to do so.
These are my two statements:
Query 1:
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold';
Query 2:
SELECT SUM(AC.Amount) AS VendorPay_Comm
FROM (
SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS `Amount` FROM COMMISSION AS C WHERE C.`status` = 'Paid') AS AC
Any help on this matter would be greatly appreciated :)
You can do it as follows :
select (select ...) - (select ...)
In your example, simply :
select
(
SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold'
)
-
(
SELECT SUM(AC.Amount) AS VendorPay_Comm
FROM (
SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS `Amount` FROM COMMISSION AS C WHERE C.`status` = 'Paid') AS AC
) AS Outstanding_Funds
Try
SELECT TotalSales-VendorPay_Comm AS Outstanding_Funds
FROM
(SELECT SUM(Price) AS TotalSales
FROM PROPERTY
WHERE Status = 'Sold') t1,
(SELECT SUM(Amount) AS VendorPay_Comm
FROM (SELECT Amount FROM lawyer_pays_vendor
UNION ALL
SELECT CommissionEarned AS Amount
FROM COMMISSION
WHERE Status = 'Paid') t0) t2
Here is sqlfiddle