MySQL remove zeros from decimal part if the number is whole - mysql

I have a sales table with price column as decimal(8, 2) and I'm running the query below to get the total price
select sum(case when status = 1 then price * quantity when status = 2 then price * quantity * -1 else 0 end) as total from sales;
It's working perfectly but my results are usually intergers so I end up with trailing zeros all the time. It'd be nice to just return the whole number if there is no decimal part

like akina said in his comment ...
you can cast the sum result to UNSIGNED INTEGER
select
CAST(sum(case when status = 1 then price * quantity when status = 2 then price * quantity * -1 else 0 end) AS UNSIGNED)
as total from sales;

Related

Find the number of days before instock level goes negative

I want to find the number of days from my SQL table before my instock level goes negative. Is there a way to do that on SQL? I can find the number of days that have negative instock levels but I am not able to figure out a way to stop the counter for days when instock goes negative.
create TEMPORARY VIEW instock_ssd_fc as
( select
ilbo.asin,
ilbo.snapshot_day,
sum(coalesce(ilbo.on_hand_quantity, 0) - coalesce(greatest(ilbo.allocated_quantity, ilbo.bound_quantity), 0)) as inventory_units_ssd_fc,
sum(coalesce(ilbo.in_transit_quantity, 0)) as in_transit_quantity_ssd_fc,
sum(coalesce(ilbo.unallocated_customer_demand,0)) as unallocated_customer_demand_ssd_fc,
sum(case when iog.inventory_owner_group_id is not null then coalesce(ilbo.on_hand_quantity, 0) - coalesce(greatest(ilbo.allocated_quantity, ilbo.bound_quantity), 0) else 0 end) as inventory_units_retail_ssd_fc
from d_unified_inv_level_by_owner as ilbo
inner join asin_selected as a
on a.asin = ilbo.asin
left join iog
on ilbo.inventory_owner_group_id = iog.inventory_owner_group_id
and ilbo.region_id = ${region_id}
where ilbo.region_id = ${region_id}
and upper(ilbo.inventory_condition_code) = 'SELLABLE'
and ilbo.snapshot_day between cast('${date}' as timestamp) - interval 1 weeks and cast('${date}' as timestamp)
and ilbo.warehouse_id = '${fc}'
group by ilbo.asin, ilbo.snapshot_day
);
From the above query, I want to check how many days the ASIN had a positive inventory. For example, if I start looking for instock levels from 12/27 and go behind, if on snapshot_day of 12/06 the inventory level goes to negative for the first time starting from 12/27, my number of days will be 21.
Assuming your table has a column date for the date and instock for the quantity, you could use try:
SELECT COUNT(*)
FROM yourTable
WHERE date < (SELECT date FROM yourTable
WHERE instock < 0
ORDER BY date LIMIT 1);

is there a way to check if a value is zero and do this or do that in mysql

I want to do an sql query
SELECT * from members m where abs(due/30*service_charge)>='0'
AND abs(due/30*service_charge)<='200' group by id
But in some cases the value of service_charge will 0 , so i want to write it like if service_charge = 0 , then service_charge = 1;
Is there a way for this ?.
Use case:
select *
from members m
where abs(due/30*(case when service_charge = 0 then 1 else service_charge end) >= 0 and
abs(due/30*(case when service_charge = 0 then 1 else service_charge end)<= 200
group by id;
However, this is typically handled using NULLIF() -- meaning that NULL would be returned from the calculation:
select *
from members m
where abs(due / 30 * nullif(service_charge, 0) >= 0 and
abs(due / 30 * nullif(service_charge, 0) <= 200
group by id;
Also, don't use single quotes around numeric constants. This confuses people and could confuse the SQL optimizer.

Query to display the % of the failure rate

I have written this query to get my data, and all the data is fine.
I have one column which has either Pass Or Fail. I want to calculate the % of number of bookings that failed, and output it in a single value.
I will have to write another query to show that one number.
Perhaps this? You didn't really offer much to go on:
SELECT
SUM(CASE
WHEN trip_rating.rating <= 3 OR
TIMESTAMPDIFF(MINUTE, booking_activity.activity_time, booking.pick_up_time) < 0
THEN 1.00 ELSE NULL END
) / COUNT(*)
FROM ...
Query
select
concat(
cast(
(
sum(case when t.Decision = 'Fail' then 1 else 0 end) / count(*)) * 100
as varchar(3)
), '%') as `fail rate`
from
(
select ........
case ........ end as Decision
)t;

Getting a syntax error on my mysql query around doing math with my where function

I am trying to select from my database of scores only the scores that are 1 and 5, group those scores by the productid and then do some math on those scores to only pull the productids that have a close number of 1 and 5 scores. My query is below and I'm getting a syntax error on the 7th line, though I'm not sure what the issue is. Thank you for any help.
SELECT title, productid,
count(*) as total,
sum(case when score = '5.0' then 1 else 0 end) as high,
sum(case when score = '1.0' then 1 else 0 end) as low
FROM `reviews`
WHERE total > 0 AND
WHERE (`high` + `low`)/`total` > '.5' AND
WHERE abs((`high`-`low`)/`low`) <= '.1'
GROUP BY productid
ORDER BY total DESC;
The problem with your query appears to be the and where. That doesn't exist in SQL. The following is another way to write your query:
SELECT title, productid, count(*) as total,
sum(score = 5.0) as high, sum(score = 1.0) as low
FROM `reviews`
WHERE total > 0 AND
(`high` + `low`)/`total` > 0.5 AND abs((`high`-`low`)/`low`) <= 0.1
GROUP BY productid
ORDER BY total DESC;
Some notes about this query:
This simplifies the sum() but not using case. The case is correct and fine to use. MySQL happens to support the above syntax because booleans are treated as integer, as they are in the C and C++ languages (0 = false, 1 = true).
Numeric constants do not need to be in single quotes. I think putting them in single quotes is a bad idea because it is misleading.
You have equality comparisons to values that might be floating point numbers. This is dangerous. If your columns are declared as decimals, then it should be okay (decimals are fixed point representation).
For the last point, you might consider:
sum( abs(score - 5.0) < 0.0001 )
Or something similar to handle values that are very close to 5.
EDIT:
I hadn't noticed that the columns in the where clause area really aliases. That means you want a having clause:
SELECT title, productid, count(*) as total,
sum(score = 5.0) as high, sum(score = 1.0) as low
FROM `reviews`
GROUP BY productid
HAVING total > 0 AND
(`high` + `low`)/`total` > 0.5 AND abs((`high`-`low`)/`low`) <= 0.1
ORDER BY total DESC;
You have two issues here:
There is only one where clause in a query. It's find to add several conditions with ands (or ors for that matter), but you only need to specify where once.
If you're comparing numerical results, you need to use a numerical literal (0.1), not a character literal ('0.1').
So:
SELECT title, productid,
count(*) as total,
sum(case when score = '5.0' then 1 else 0 end) as high,
sum(case when score = '1.0' then 1 else 0 end) as low
FROM `reviews`
WHERE total > 0 AND
WHERE (`high` + `low`)/`total` > 0.5 AND
abs((`high`-`low`)/`low`) <= 0.1
GROUP BY productid
ORDER BY total DESC;

Dynamic Average Calculations Against Partial Amounts of Distinct Groups

We have a table representing purchases of a particular SKU. Let's say it has 4 columns, PurchaseNo, SKU, QTY and PRICE.
The QTY column represents the number of an SKU involved in each particular purchase. The PRICE column represents the dollar value paid for each unit on that particular purchase.
We need a query to determine the average PRICE of all currently “in stock” AG1TBA.
Let us assume that the QTY currently in stock is known to be 200. Let's also assume the top 3 rows of this table have the following QTY and PRICE information: 50, 22 | 120, 21 | 96, 25 |.
Since we only have 200 in stock, we somehow need the query to calculate the average from all 50 (at $22), all 120 (at $21) and 30 of the 96 (at $25). Obviously, the average price here is $21.85, but how could the query dynamically modify itself to limit the calculation of the average values to a specific amount of the the previous transactions (in this case, 200).
Here is an image of this hypothetical table:
Assuming the name of your table was endurion, you could solve it with following statements:
SET #stock := 200.0;
SET #amount := 0;
SELECT
SUM(e1.costs)/#stock as average_price_per_unit
FROM
(
SELECT
e.PurchaseNo,
e.SKU,
e.QTY,
#amount := #amount + e.QTY,
CASE
WHEN #amount <= #stock THEN e.QTY
ELSE e.QTY + #stock - #amount
END as part,
e.PRICE,
CASE
WHEN #amount <= #stock THEN e.QTY * e.PRICE
ELSE (e.QTY + #stock - #amount) * e.PRICE
END as costs
FROM (
SELECT
*
FROM
endurion e1 -- replace your table name here
WHERE
SKU = 'AG1TBA'
ORDER BY PurchaseNo DESC
) AS e
WHERE
#amount <= #stock
) as e1;
Explanation:
The innermost Subselect
SELECT
*
FROM
endurion e1
WHERE
SKU = 'AG1TBA'
ORDER BY
PurchaseNo DESC
ensures we match the latest purchases, because as you stated those will give us the current stock.
The outermost query will give us the average price per unit in stock. That should be obvious.
The outer subquery calculates the total of units by purchases. If this is greater than the stock, then only a part contributes to the stock. This part is calculated in the case statement and the second one calculates the total price for this units.
Hint
The complete query works for my installation of MySQL v5.6.16 but not in the v5.5.32 of the current sqlfiddle. I would consider to insert the result of
SELECT
e.PurchaseNo,
e.SKU,
e.QTY,
#amount := #amount + e.QTY,
CASE
WHEN #amount <= #stock THEN e.QTY
ELSE e.QTY + #stock - #amount
END AS part,
e.PRICE,
CASE
WHEN #amount <= #stock THEN e.QTY * e.PRICE
ELSE (e.QTY + #stock - #amount) * e.PRICE
END AS costs
FROM (
SELECT
*
FROM
endurion e1 -- replace your table name here
WHERE
SKU = 'AG1TBA'
ORDER BY PurchaseNo DESC
) AS e
WHERE
#amount <= #stock
into a temporary table and calculate the average by this temporary table.