SQL Sum() - 0 in field excluding row from aggregation? - mysql

Consider the following query:
$query = "
SELECT a_orders.id, a_orders.billing,
SUM(a_order_rows.quant_refunded*a_order_rows.price*((100-a_orders.discount)*.01)) as refund_total,
SUM(a_order_rows.quant*a_order_rows.price*((100-a_orders.discount)*.01)) as order_total
FROM a_order_rows JOIN a_orders
ON a_order_rows.order_id = a_orders.id
WHERE a_order_rows.quant_refunded > 0
GROUP BY a_orders.id, a_orders.billing
ORDER BY a_orders.id DESC
LIMIT 50";
The two uses of SUM() are attempting to aggregate the order total and the total amount that has been refunded. They are coming out correctly when when the quant_refunded field is not 0... for example take this data (excluding primary key, item_id for simplicity's sake, assuming each row is a unique item):
Table: a_order_rows
Fields: order_id, quant, quant_refunded
1, 1, 1
1, 2, 1
2, 1, 1
2, 1, 0
In the case of "order 1" the two aggregations are different and behave as expected. But for "order 2" the two numbers are coming out the same - both numbers are what I am expecting refund_total to be. It appears that the row with "0" in quant_refunded is being excluded from the order_total aggregation.
Hopefully this is explained thoroughly enough. Please let me know if you need more info and I will revise. THANKS!

$query = "
SELECT a_orders.id, a_orders.billing,
SUM(a_order_rows.quant_refunded*a_order_rows.price*((100-a_orders.discount)*.01)) as refund_total,
SUM(a_order_rows.quant*a_order_rows.price*((100-a_orders.discount)*.01)) as order_total
FROM a_order_rows JOIN a_orders
ON a_order_rows.order_id = a_orders.id
GROUP BY a_orders.id, a_orders.billing
HAVING MAX(a_order_rows.quant_refunded) > 0
ORDER BY a_orders.id DESC
LIMIT 50";
Change that to a HAVING clause. If any quant_refunded rows are > 0, the HAVING MAX will retain it.

Related

Order by value decrement to one + mysql

Ex : I have V001, V002, V003, V004 records,
tid is_premium
---- ----------
V001 0
V002 0
V003 0
V004 1
V005 1
How to get records order by below like this,
V001
V004
V005
V002
V003
2nd Ex : I have V006, V007, V008, V009 records,
tid is_premium
---- ----------
V006 0
V007 0
V008 1
V009 0
How to get records order by below like this,
V006
V008
V007
V009
I want to above order in MySQL, I have to write but not possible, I tried both multiple column order by using Mysql, but I am not getting correct response. Can anyone help in this., I want to above order in MySQL,
Well, what this query does is to sort it in descending order by is_premium and then displays it simply that way
SELECT * FROM CLIENTE ORDER BY `tid`='V001' DESC, `is_premium` DESC;
Note : Where it says table put your table
I put a link with the test code for you to try it. : https://www.db-fiddle.com/f/3PnzHErrf2fZFGZY67K12X/57
Probably, #Chinnu the most efficient way to do what you need is get all from your DB and do some logic in your backend instead use mysql-query. Once you have an object with everything, you can apply conditions that will make sure if some patient is already in the queue and if that patient is premium or not and so on.
(SELECT * FROM PATIENTS WHERE `is_serial` = 0 LIMIT 1)
UNION
(SELECT * FROM PATIENTS ORDER BY `is_serial` = 0 DESC, `is_premium` DESC LIMIT 0, 1000);
Test here: https://www.db-fiddle.com/f/3PnzHErrf2fZFGZY67K12X/93
Picture with is_premium=1 first
Picture with is_premium=0 first
That should resolve your problem but it will put all is_premium = 1 before the others keeping the first row intact.
For patients with checkup completed too.
If you want to select only unchecked patients:
(SELECT * FROM PATIENTS WHERE `is_serial` = 0 LIMIT 1)
UNION
(SELECT * FROM PATIENTS WHERE `is_serial` = 0 ORDER BY `is_premium` DESC LIMIT 0, 1000);

MySQL - Match certain IDs, but only those IDs

I have a table like so:
id_type id_option
"1" "1"
"1" "5"
"2" "1"
"2" "5"
"2" "8"
I am trying to write a query that given a list of option IDs finds the "type" that matches the list, but only those ID's
For example, if given 1 and 5 as options, it should return the type 1 but only the type 1 as the 8 required to match type 2 is not present.
I have tried the following:
SELECT *
FROM my_table
WHERE id_option IN (1, 5)
GROUP BY id_type
HAVING COUNT(DISTINCT id_option) = 2
This returns both "types" - I had hoped that the COUNT restriction of 2 would have helped but I now understand why it doesn't, but I can't think of a clever way to limit this.
I could just pull the first record as typically the types with less options are saved first but I don't think I can rely on this 100%
Thank you for your time
Here's a solution:
SELECT *
FROM my_table
GROUP BY id_type
HAVING SUM(id_option IN (1,5)) = COUNT(*)
It relies on a trick specific to MySQL: boolean true is literally the integer 1. So you can use SUM() to count the rows where a condition is true, but putting a boolean expression inside SUM().
For folks reading this who use other databases besides MySQL, you'd have to use an expression to convert the boolean condition to the integer 1:
HAVING SUM(CASE WHEN id_option IN (1,5) THEN 1 ELSE 0 END) = COUNT(*)
In this case, let all rows become part of the groups. That is, do not use a WHERE clause to restrict the query to rows where the id_option is 1 or 5. Then count the total rows in the group, and "count" (i.e. use the SUM() trick) the rows where the id_options is 1 or 5. Comparing these counts will be equal if there are no id_options values besides 1 or 5.
If you also want to make sure that both 1 and 5 are found, you need another condition:
SELECT *
FROM my_table
GROUP BY id_type
HAVING SUM(id_option IN (1,5)) = COUNT(*)
AND COUNT(DISTINCT CASE WHEN id_option IN (1,5) THEN id_option END) = 2
The CASE expression will return 1 or 5, or if there are any other values, those are converted to NULL. The COUNT() function ignores NULLs.
If you can pass the options as a sorted comma separated list string, then use GROUP_CONCAT():
SELECT id_type
FROM my_table
GROUP BY id_type
HAVING GROUP_CONCAT(id_option ORDER BY id_option) = '1,5'
If there are duplicate options for each type, use DISTINCT:
HAVING GROUP_CONCAT(DISTINCT id_option ORDER BY id_option) = '1,5'
While I can't comment yet, here's a tiny adjustment to Bill Karwin's last example (in the accepted solution):
SELECT *
FROM my_table
GROUP BY id_type
HAVING SUM(id_option IN (1,5)) = COUNT(*)
AND COUNT(DISTINCT id_option) = 2

MySQL: get sum of columns with multiply two columns on behalf of third column

I am trying to get sum of all rows with multiply two column values with where condition but getting some error of mysql. After try some example i achieve my result but i don't know that is right way or not:
Table: store_stocks
i just want to count the stock qty with amount multiply with qty according to with VAT, with non VAT and total stock.
I just created that query:
SELECT sum(qty*sale_price) as total_stock,
(select sum(qty*sale_price) from store_stocks where vat_status = 0 and store_id = 8) as non_vat_stock,
(select sum(qty*sale_price) from store_stocks where vat_status = 1 and store_id = 8) as with_vat_stock
FROM `store_stocks` where store_id = 8 group by store_id
and its showing result:
can any one tell me is there any another way to achieve this, because i think that's query is little bit complicated, each time i am using where in sub query and i also have to implement this query in laravel eloquent.
You do not need subqueries, you can use a condition within the sum() to make it summarise the specific records only:
SELECT sum(qty*sale_price) as total_stock,
sum(if(vat_status = 0, qty*sale_price, 0)) as non_vat_stock,
sum(if(vat_status = 1, qty*sale_price, 0)) as with_vat_stock
FROM `store_stocks` where store_id = 8 group by store_id
You can use a case expression instead of the if() function as well.

SQL SELECT ORDER BY multiple columns depending on value of other column

I have a table with the following columns:
id | revisit (bool) | FL (decimal) | FR (decimal) | RL (decimal) | RR (decimal) | date
I need to write a SELECT statement that will ORDER BY on multiple columns, depending on the value of the 'revisit' field.
ORDER BY 'revisit' DESC - records with this field having the value 1 will be first, and 0 will be after
If 'revisit' = 1 order by the lowest value that exists in FL, FR, RL and RR. So if record 1 has values 4.6, 4.6, 3.0, 5.0 in these fields, and record 2 has values 4.0, 3.1, 3.9, and 2.8 then record 2 will be returned first as it holds a lowest value within these four columns.
If 'revisit' = 0 then order by date - oldest date will be first.
So far I have the 'revisit' alone ordering correctly, and ordering by date if 'revisit' = 0, but ordering by the four columns simultaneously when 'revisit' = 1 does not.
SELECT *
FROM vehicle
ORDER BY
`revisit` DESC,
CASE WHEN `revisit` = 1 THEN `FL` + `FR` + `RR` + `RL` END ASC,
CASE WHEN `revisit` = 0 THEN `date` END ASC
Instead it seems to be ordering by the total of the four columns (which would make sense given addition symbols), so how do I ORDER BY these columns simultaneously, as individual columns, rather than a sum.
I hope this makes sense and thanks!
In your current query, you order by the sum of the four columns. You can use least to get the lowest value, so your order by clause could look like:
SELECT *
FROM vehicle
ORDER BY
`revisit` DESC,
CASE WHEN `revisit` = 1 THEN LEAST(`FL`, `FR`, `RR`, `RL`) END ASC,
CASE WHEN `revisit` = 0 THEN `date` END ASC
Of course this would sort only by the lowest value. If two rows would both share the same lowest value, there is no sorting on the second-lowest value. To do that is quite a bit harder, and I didn't really get from your question whether you need that.

how can I tell if the last x rows of 'state' = 1

I need help with a SQL query.
I have a table with a 'state' column. 0 means closed and 1 means opened.
Different users want to be notified after there have been x consecutive 1 events.
With an SQL query, how can I tell if the last x rows of 'state' = 1?
If, for example, you want to check if the last 5 consecutive rows have a state equals to 1, then here's you could probably do it :
SELECT IF(SUM(x.state) = 5, 1, 0) AS is_consecutive
FROM (
SELECT state
FROM table
WHERE Processor = 3
ORDER BY Status_datetime DESC
LIMIT 5
) as x
If is_consecutive = 1, then, yes, there is 5 last consecutive rows with state = 1.
Edit : As suggested in the comments, you'll have to use ORDER BY in your query, to get the last nth rows.
And for more accuracy, since you have a timestamp column, you should use Status_datetime to order the rows.
You should be able to use something like this (replace the number in the HAVING with the value of x you want to check for):
SELECT Processor, OpenCount FROM
(
SELECT TOP 10 Processor, DateTime, Sum(Status) AS OpenCount
FROM YourTable
WHERE Processor = 3
ORDER BY DateTime DESC
) HAVING OpenCount >= 10