sql order by not working with decimal(18,6) - mysql

The SQL query with order by clause is not working properly.
Query:
select cast(actual_qty as decimal(18,2)) from `Bin`
where warehouse = `Warehouse`.name
order by actual_qty desc
Output of above query:
303.00
550.00
0.00
3.00
The type of actual_qty is decimal(18,6). I tried using cast function in order by, didn't work.
Any help is much appreciated!!
Update1:
Here's my full query that is being fired:
select `tabWarehouse`.name, CONCAT_WS(" : ", "Actual Qty", ifnull( ( select round(`tabBin`.actual_qty, 2) as qty
from `tabBin` where `tabBin`.warehouse = `tabWarehouse`.name
and `tabBin`.item_code = '30440'
order by qty desc), 0) ) as actual_qty
from `tabWarehouse` where `tabWarehouse`.`name` like '%%%%' and ifnull(`tabWarehouse`.company, '') in ('', 'TILE TEST') and `tabWarehouse`.is_group = 0.0
limit 0, 20
The output is still the same which is not really ordered by the qty in a descending manner.
Update 2:
This is how my code looks:
query = """select tw.name,
CONCAT_WS(" : ", "Actual Qty", ifnull(round(`tabBin`.actual_qty, 2), 0 ) actual_qty
from `tabWarehouse` tw left join `tabBin` tb
on tb.warehouse = tw.name {bin_conditions}
where
tw.`{key}` like {txt}
{fcond} {mcond}
order by ifnull(round(tb.actual_qty, 2), 0) desc
limit
{start}, {page_len}
""".format(
bin_conditions=get_filters_cond(doctype, filter_dict.get("Bin"),bin_conditions, ignore_permissions=True),
# sub_query=sub_query,
key=searchfield,
fcond=get_filters_cond(doctype, filter_dict.get("Warehouse"), conditions),
mcond=get_match_cond(doctype),
start=start,
page_len=page_len,
txt=frappe.db.escape('%{0}%'.format(txt))
)

The cast in select doesn't change the type of the column -- and the order by is referring to the column in the table, not the expression in the select.
One option is to give it a new name and use that:
select cast(actual_qty as decimal(18,2)) as qty
from `Bin`
where warehouse = `Warehouse`.name
order by qty desc;
Or repeat the expression:
select cast(actual_qty as decimal(18,2)) as qty
from `Bin`
where warehouse = `Warehouse`.name
order by cast(actual_qty as decimal(18,2)) desc

There is no ORDER BY clause in your query.
The ORDER BY inside the correlated subquery is useless because that subquery will work only if it returns only 1 row and does not effect the final results.
Try this:
select tw.name,
CONCAT_WS(" : ", "Actual Qty", ifnull(round(tb.actual_qty, 2), 0)) actual_qty
from tabWarehouse tw left join tabBin tb
on tb.warehouse = tw.name and tb.item_code = '30440'
where tw.name like '%%%%'
and ifnull(tw.company, '') in ('', 'TILE SELECT')
and tw.is_group = 0.0
order by ifnull(round(tb.actual_qty, 2), 0) desc limit 0, 20
Also what is this condition:
`tabWarehouse`.`name` like '%%%%'

Related

Getting the sum of column grouped by date

Was wondering if there is a way to get the sum of the stock_case column for items with the same date_of_export ?
Updated with fiddle here and some relevant data:
https://www.db-fiddle.com/f/szC1Ftj3ZGEC24gSYp6ad4/4
The expected output would be this:
This is the query used
SELECT
st.product_code,
st.date_of_export,
st.best_before_date,
st.stock_case,
(
SELECT
SUM(st2.stock_case)
FROM
stock_tracking AS st2
WHERE
st2.product_code IN ('MGN003')
AND MONTH(st2.date_of_export) IN (07)
AND YEAR(st2.date_of_export) IN (2018)
AND st2.stock_case != 0
) AS total
FROM
stock_tracking st
WHERE
product_code IN ('MGN003')
AND MONTH(st.date_of_export) IN (07)
AND YEAR(st.date_of_export) IN (2018)
AND stock_case != 0
and my results
Would like to have a total column like 16, 16, 16, ... , 19, etc
For another case I used a subquery like so
SELECT
d.products_name,
stock_case,
st.date_of_export,
st.best_before_date,
st.product_code,
(SELECT
SUM(st2.stock_case)
FROM
stock_tracking AS st2
WHERE
DATE(st2.date_of_export) = (SELECT
DATE(tmp.last_update)
FROM
(SELECT
date_of_export AS last_update
FROM
stock_tracking
ORDER BY date_of_export DESC
LIMIT 1) AS tmp
WHERE
product_code = 'MGN003')) AS total
FROM
stock_tracking st
LEFT JOIN
products AS p ON p.products_model = st.product_code
LEFT JOIN
products_description AS d ON d.products_id = p.products_id
WHERE
product_code = 'MGN003'
AND d.language_id = 2
AND DATE(st.date_of_export) = (SELECT
DATE(tmp.last_update)
FROM
(SELECT
date_of_export AS last_update
FROM
stock_tracking AS st
ORDER BY date_of_export DESC
LIMIT 1) AS tmp)
with this result:
You can write a subquery to sum(stock_case) by date_of_export, then self join on Date, then you can get your expect result.
SELECT
s.product_name,
s.date_of_export,
s.best_before_date,
s.product_code,
s.stock_case,
t.totle
FROM
stock_tracking s
INNER JOIN
(
SELECT SUM(stock_case) totle,date_of_export dt
FROM stock_tracking
where
product_code = 'MGN003'
AND MONTH(date_of_export) =07
AND YEAR(date_of_export) =2018
AND stock_case != 0
GROUP BY date_of_export
) t on DATE_FORMAT(s.date_of_export, "%d-%m-%Y") = DATE_FORMAT(t.dt, "%d-%m-%Y")
where
s.product_code = 'MGN003'
AND MONTH(s.date_of_export) =07
AND YEAR(s.date_of_export) =2018
AND s.stock_case != 0
sqlfiddle
Without giving you the exact answer: You should think in the direction of:
SELECT SUM(column) FROM table WHERE ... GROUP BY date
or
SELECT SUM(column), DISTINCT date FROM table WHERE ...
So lookup the way GROUP BY and DISTINCT work :-)

How to select last and last but one records

I have a table with 3 columns id, type, value like in image below.
What I'm trying to do is to make a query to get the data in this format:
type previous current
month-1 666 999
month-2 200 15
month-3 0 12
I made this query but it gets just the last value
select *
from statistics
where id in (select max(id) from statistics group by type)
order
by type
EDIT: Live example http://sqlfiddle.com/#!9/af81da/1
Thanks!
I would write this as:
select s.*,
(select s2.value
from statistics s2
where s2.type = s.type
order by id desc
limit 1, 1
) value_prev
from statistics s
where id in (select max(id) from statistics s group by type) order by type;
This should be relatively efficient with an index on statistics(type, id).
select
type,
ifnull(max(case when seq = 2 then value end),0 ) previous,
max( case when seq = 1 then value end ) current
from
(
select *, (select count(*)
from statistics s
where s.type = statistics.type
and s.id >= statistics.id) seq
from statistics ) t
where seq <= 2
group by type

Mysql LEFT to match first 3 chars

Im trying to get all matching records from the invoice_id field where the first 3 characters are RBK, case sensitivity not important. I've tried to use the LEFT function in the bottom 2 ways but its not working. Any ideas on how to achieve this?
SELECT *, IF( LEFT( invoice_id, 3) = 'RBK') FROM `invoices` ORDER BY id ASC
SELECT *, IF( LEFT( invoice_id, 3) = 'RBK', 3, 0) FROM `invoices` ORDER BY id ASC
an if inside the select is not to filter results,if you want to filter result use where clause.
SELECT * FROM `invoices` WHERE LEFT(invoice_id, 3) = "RBK" ORDER BY id ASC

aggregation condition in case when

I have a dataset with a structure similar to the one bellow
fruit, value
apple, 234
apple, 2341
pear, 3233
grape, 323
pear, 3234
grap 1234
I am trying to find a count of a range of the numbers that are in the bottom 10% of the range by performing a query like the one below. (the ultimate goal of the query is to calculate and see the ranges of the calc go up in increments of 10%) I also have a group by clause so I would like the counts to be grouped by the fruit and aggregated that way. Bellow is the query I have tried
select fruit, count(case when (value <= (((max(value) - min(value)) * .1) + min(value))) then 1 end)
from fruit_juice
group by substring(fruit, 5, 5);
Aggregate the table in the from clause to get the limits you want. Join those results back to your query and use those values for the query:
select substring(fj.fruit, 5, 5),
sum(fj.value <= fmm.minv + (fmm.maxv - fmm.minv) * 0.1)
from fruit_juice fj join
(select substring(fruit, 5, 5) as fruit5,
max(value) as maxv, min(value) as minv
from fruit_juice
group by substring(fruit, 5, 5)
) fmm
on fmm.fruit5 = substring(fj.fruit, 5, 5)
group by substring(fruit, 5, 5);
Note that your group by expressions should match the expressions in the select clause.
EDIT:
I'm not sure where the substring() is coming from in your question, so this version removes it:
select fj.fruit, sum(fj.value <= fmm.minv + (fmm.maxv - fmm.minv) * 0.1)
from fruit_juice fj join
(select fruit,
max(value) as maxv, min(value) as minv
from fruit_juice
group by fruit
) fmm
on fmm.fruit = fj.fruit
group by fruit;

MySQL GROUP BY each comma separated value

Before anyone comments, I did not design this database with comma separated values :)
I have spent time trying to find the answer but all I could find was GROUP_CONCAT() which seemed to do the opposite of what I wanted.
I would like to GROUP BY each of the values within the comma separated value field.
SELECT round(avg(DATEDIFF( dateClosed , dateAded ) * 1.0), 2) AS avg, department
FROM tickets GROUP BY assignedto
the assignedto field is the comma separated value field
row1 54,69,555
row2 54,75,555
row3 75,555
DESIRED OUTPUT: an average rounded figure for each value in assignedto field grouped.
EDIT - TRYING TO TAKE THIS TO THE NEXT LEVEL:
I want to include the ticket answer table to get the first response for that ticket, use its datetime field to work out the average response time for each user.
SELECT a.id as theuser, round(avg(DATEDIFF( ta.dateAded , t.dateAded ) * 1.0), 2) as avg
FROM tickets t join
mdl_user a
on find_in_set(a.id, t.assignedto) > 0
INNER JOIN (SELECT MIN(ta.dateAded) as started FROM ticketanswer GROUP BY ta.ticketId) ta ON t.id = ta.ticketId
GROUP BY a.id ORDER BY avg ASC
Yuck. You can do this, assuming you know the maximum number of assignments. Here is an approach:
select substring_index(substring_index(assignedto, ',', n.n), ',', -1) as assignedto,
round(avg(DATEDIFF( dateClosed , dateAded ) * 1.0), 2) as avg
from tickets t join
(select 1 as n union all select 2 union all select 3)
on length(assignedto) - length(replace(assignedto, ',', '')) < n.n
group by substring_index(substring_index(assignedto, ',', n.n), ',', -1);
Or, an easier way if you have a list of assigned values, say in an AssignedTo table:
select a.assignedto, round(avg(DATEDIFF( dateClosed , dateAded ) * 1.0), 2) as avg
from tickets t join
assignedto a
on find_in_set(a.assignedto, t.assignedto) > 0
group by a.assignedto;
I'm sorry you have to deal with this malformed database structure.