MySQL variable as result of subquery with elements of other table - mysql

I have a working query:
SELECT count(*),
AVG(
(SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE `type`='closed'
AND order_fills.transaction_id = transactions.id) -
(SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE `type`='opened'
AND order_fills.transaction_id = transactions.id)) AS avgProfit,
SUM(
(SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE `type`='closed'
AND order_fills.transaction_id = transactions.id)) AS volume,
FROM transactions
WHERE transactions.status='closed';
to make the code more readable I wish to set some parts of that query into variables.
I wish to achieve something like that (it does not work, returns null):
SET #transSells =
(SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE type='closed'
AND order_fills.transaction_id = transactions.id);
SET #transBuys =
(SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE type='opened'
AND order_fills.transaction_id = transactions.id);
SELECT avg(#transSells - #transBuys) AS `avgProfit`,
sum(#transSells + #transBuys) AS `volume`
FROM transactions WHERE transactions.status='closed'
I think the problem might be that part of subquery WHERE statement is the result of the main query and another table (transactions.id):
AND order_fills.transaction_id = transactions.id

The reason your variable query doesn't work is that transactions.id in the WHERE clause of your variable definitions is not defined (NULL), hence the queries won't return any results.
I think you can simplify your query by putting the variables into a derived table using conditional aggregation that you then JOIN to:
SELECT AVG(transSells - transBuys) AS avgProfit,
SUM(transSells + transBuys) AS volume
FROM transactions
JOIN (SELECT transaction_id,
SUM(CASE WHEN type='closed' THEN quant * price ELSE 0 END) AS transSells,
SUM(CASE WHEN type='opened' THEN quant * price ELSE 0 END) AS transBuys
FROM order_fills) o ON o.transaction_id = transactions.id
WHERE status = 'closed'

I found a slightly better solution for my case:
setting variables inside the query, and then using them in the same, single query.
SET #comission = 0.03;
SELECT count(*),
AVG(
( #transSells := (SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE `type`='closed'
AND order_fills.transaction_id = transactions.id))
-
( #transBuys := (SELECT sum(order_fills.quant * order_fills.price)
FROM order_fills
WHERE `type`='opened'
AND order_fills.transaction_id = transactions.id))) AS avgProfit,
SUM( #transSells ) AS volume,
SUM( #transSells * #comission )
FROM transactions
WHERE transactions.status='closed';

Related

Sql query on taking the value from a case within select statement in a CTE

I am trying to write a SQL. In this, I want columns Bank, and Y-Bank in the output. Y-Bank is being calculated based on certain case statements, using CTE, but I am not able to return Y-Plant as the column.
I also created a table as shown in the input/output here:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=749e4ca1570880e9c64c4553d18dea1a
Below is the code:
WITH CTE AS
(
SELECT
"BANK",
(select
case
when "TEST"=0 AND "TEST1">0
THEN ( SELECT COUNT("ZONES")FROM mytable I WHERE I.BANK = O.BANK AND I."ZONES"='Y' )
END AS "Y-BANK"
from(
(SELECT
CASE WHEN ( (SELECT COUNT("ZONES")FROM mytable I WHERE I.BINDER = O.BINDER AND I."ZONES"='N' ) = 0 ) AND ( (SELECT COUNT("ZONES")FROM mytable I WHERE I.BINDER = O.BINDER AND I."ZONES"='Y' ) > 0 )
THEN ( SELECT COUNT("ZONES")FROM mytable I WHERE I."TOTAL LINE"= O."TOTAL LINE"AND I."ZONES"='N' )
END AS "TEST",
CASE WHEN ( (SELECT COUNT("ZONES")FROM mytable I WHERE I.BINDER = O.BINDER AND I."ZONES"='' ) = 0 ) AND ( (SELECT COUNT("ZONES")FROM mytable I WHERE I.BINDER = O.BINDER AND I."ZONES"='Y' ) > 0 )
THEN ( SELECT COUNT("ZONES")FROM mytable I WHERE I."TOTAL LINE" = O."TOTAL LINE" AND I."ZONES"='Y' )
END AS "TEST1"
from mytable )
)
)
FROM mytable O
)
SELECT *
FROM CTE O
Can someone help me out on how can I correct it?
If I understand correctly, you want to count the number of "Y" values for each bank. You can use a window function:
select t1.*, sum(zones = 'Y') over (partition by Bank1) as y_bank
from t1
Here is a db<>fiddle.
you can use following query
select
bank1 as "bank",
(select count(*)over(partition by Bank1,Zones order by Bank1 desc) as "y_bank" from t1 where Zones = 'Y' and Bank1 = t.Bank1 limit 1) as "y_bank"
from t1 t

mariadb(mysql) slow query fix

SELECT
CAST(`a`.`selldate` AS DATE) AS `regdate`,
`a`.`market` AS `market`,
`a`.`user_seq` AS `user_seq`,
COUNT(0) AS `complete`,
ROUND(SUM(`a`.`sell`) - SUM(`a`.`buy`) - SUM(`a`.`buy_fee`) - SUM(`a`.`sell_fee`),8) AS `profit`,
ROUND(SUM(`a`.`buy`),8) AS `price`,
ROUND(SUM(`a`.`sell_fee`),8) AS `sell_fee`,
ROUND(SUM(`a`.`buy_fee`),8) AS `buy_fee`,
(
SELECT SUM(`yangpago`.`funding`.`price`) AS `funding_fee`
FROM `yangpago`.`funding`
WHERE
DATE_FORMAT(FROM_UNIXTIME(`yangpago`.`funding`.`time`),'%Y-%m-%d') = CAST(`a`.`selldate` AS DATE)
AND
`yangpago`.`funding`.`user_seq` = `a`.`user_seq`
GROUP BY `regdate`,`yangpago`.`funding`.`user_seq`
) AS `funding_fee`
FROM (
SELECT
`v_order`.`cnt` AS `cnt`,
`v_order`.`market` AS `market`,
`v_order`.`user_seq` AS `user_seq`,
`v_order`.`selldate` AS `selldate`,
`v_order`.`sell_price` * `v_order`.`sell_amount` AS `sell`,
`v_order`.`buy_price` * `v_order`.`buy_amount` AS `buy`,
`v_order`.`sell_price` * `v_order`.`sell_amount` * `f`.`sell_fee` AS `sell_fee`,
`v_order`.`buy_price` * `v_order`.`buy_amount` * `f`.`buy_fee` AS `buy_fee`
FROM (`yangpago`.`v_order`
JOIN `yangpago`.`fee` `f`
ON (
`f`.`market` = `v_order`.`market`
AND
`f`.`user_seq` = `v_order`.`user_seq`
AND
CAST(`v_order`.`selldate` AS DATE) BETWEEN `f`.`startdate`
AND
IFNULL(`f`.`enddate`, CURRENT_TIMESTAMP())
)
)
WHERE `v_order`.`state` = 'COMPLETE') `a`
GROUP BY CAST(`a`.`selldate` AS DATE),`a`.`market`,`a`.`user_seq`
here is my balance view query.
this query is speed very slow. run time (1~2s)
i try funding subquery remove and check time 0.2s~0.3s
so, remove join query too. and check time 0.1s
all of sum column remove, time is 0.004s. i want 0.01s under. this query result.
how to fix it?
You are in effect reading the data twice once to create the virtual table a then again to aggregate - the virtual table is not necessary consider refactoring your code
SELECT
CAST(v_order.selldate AS DATE) AS regdate,
v_order.market AS market,
v_order.user_seq AS user_seq,
COUNT(0) AS complete,
sum(v_order.sell_price * v_order.sell_amount) -
SUM(v_order.buy_price * v_order.buy_amount) -
SUM(v_order.buy_price * v_order.buy_amount * f.buy_fee) -
SUM(v_order.sell_price * v_order.sell_amount * f.sell_fee) as profit,
SUM(v_order.buy_price * v_order.buy_amount) AS price,
SUM(v_order.sell_price * v_order.sell_amount * f.sell_fee) AS sell_fee,
SUM(v_order.buy_price * v_order.buy_amount * f.buy_fee) AS buy_fee,
(SELECT SUM(funding.price) AS funding_fee
FROM funding
WHERE DATE_FORMAT(FROM_UNIXTIME(funding.time),'%Y-%m-%d') = CAST(a.selldate AS DATE)
AND funding.user_seq = v_order.user_seq
) AS funding_fee
FROM v_order
JOIN fee f ON f.market = v_order.market
AND f.user_seq = v_order.user_seq
AND CAST(v_order.selldate AS DATE) BETWEEN f.startdate
AND coalesce(f.enddate, CURRENT_TIMESTAMP())
WHERE v_order.state = 'COMPLETE'
GROUP BY regdate,market,user_seq;

Calculate two different sum with two different where in one query in mysql

Guys I have a query that will calculate a certain sum, same logic, same code, but with different where clause, Can I do this in one query? Example:
Select SUM( mi.myitem_price * msi.my_item_quantity) as order_sum from sometable where mi.myitem_order_id = 'somevalue';
2nd query:
Select SUM( mi.myitem_price * msi.my_item_quantity) as location_sum from sometable where mi.myitem_location_id = 'somevalue';
To make this clear, That first query will calculate all orders in different locations, while that 2nd query will calculate per location only. I need to get order_sum and location_sum simultaneously with different values.
You can try to do it this way (with conditional aggregation)
SELECT SUM(CASE WHEN mi.myitem_order_id = 'somevalue'
THEN mi.myitem_price * msi.my_item_quantity END) order_sum,
SUM(CASE WHEN mi.myitem_location_id = 'somevalue'
THEN mi.myitem_price * msi.my_item_quantity END) location_sum
-- WHERE mi.myitem_order_id = 'somevalue'
-- OR mi.myitem_location_id = 'somevalue'
FROM sometable
You can use the query like this also
SELECT (Select SUM( mi.myitem_price * msi.my_item_quantity)
from sometable AS mi where mi.myitem_order_id = 'somevalue') as order_sum,
(Select SUM( mi.myitem_price * msi.my_item_quantity)
from sometable AS mi where mi.myitem_location_id = 'somevalue') as location_sum

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

calculate percentage with subqueries

I'm trying to calculate a percentage in my SQL query.
This is what I have right now:
SELECT
DATE(processed_at) AS day,
(
SELECT
COUNT(*) FROM return_items
WHERE return_id IN (SELECT id FROM returns WHERE DATE(processed_at) = day)
) as products_returned,
COUNT(*) as return_count,
(
SELECT
COUNT(*) as co_returns
FROM returns
WHERE return_method = 'mondial_relais'
AND DATE(processed_at) = day
) as return_rate_mr
FROM returns
WHERE MONTH(processed_at) = 10
AND YEAR(processed_at) = 2011
GROUP BY day;
Basically I need the return_rate_mr to be a percentage value.
I tried doing something like return_rate_mr * 100 / return_count as perc_value but this doesn't work. (I don't actually need the current return_rate_mr value, just the percentage.
Any ideas?
Assuming your original query returns the desired results, you can wrap it as a subquery:
SELECT
day,
return_rate_mr * 100 / return_count as perc_value,
... any other columns ...
FROM
( ... your original query here ...) as myalias;
Basically, the subquery creates a result set where the columns are renamed. Then, the outer query is free to use those new column names.
Are you looking for this?
SELECT
`day`,
`products_returned`,
(`return_rate_mr` * 100) / `return_count` AS `percentage`
FROM (
SELECT
DATE(processed_at) AS day,
(
SELECT
COUNT(*) FROM return_items
WHERE return_id IN (SELECT id FROM returns WHERE DATE(processed_at) = day)
) as products_returned,
COUNT(*) as return_count,
(
SELECT
COUNT(*) as co_returns
FROM returns
WHERE return_method = 'mondial_relais'
AND DATE(processed_at) = day
) as return_rate_mr
FROM returns
WHERE MONTH(processed_at) = 10
AND YEAR(processed_at) = 2011
GROUP BY day) AS `ss`
Did you try something like:
SELECT (`return_rate_mr` * 100 ) / `return_count` as "yourValue", OthersFields
FROM SELECT
DATE(processed_at) AS day,
(
SELECT
COUNT(*) FROM return_items
WHERE return_id IN (SELECT id FROM returns WHERE DATE(processed_at) = day)
) as products_returned,
COUNT(*) as return_count,
(
SELECT
COUNT(*) as co_returns
FROM returns
WHERE return_method = 'mondial_relais'
AND DATE(processed_at) = day
) as return_rate_mr
FROM returns
WHERE MONTH(processed_at) = 10
AND YEAR(processed_at) = 2011
GROUP BY day;
Hope this helps
Try:
SELECT DATE(processed_at) AS day,
count(distinct id) as products_returned,
COUNT(*) as return_count,
100* sum(case return_method when 'mondial_relais' then 1 end) / COUNT(*)
as return_perc_mr
FROM returns
WHERE MONTH(processed_at) = 10
AND YEAR(processed_at) = 2011
GROUP BY day;
I suspect that products_returned should be counting distinct item_id values (or something similar), but this should duplicate the logic in the original query.