nested mysql case when - mysql

SELECT ( CASE
WHEN 1944.0000 >= country_from_price
AND 1944.0000 <= country_to_price
THEN ((1944.0000 + ((1944.0000 * country_percentage)/100)))
ELSE 1944.0000
END
)
FROM `country_markup`
WHERE estatus = '1'
AND country_id REGEXP '[[:<:]]138[[:>:]]'
Above query return value increased by percent but if condition is not full fill than it return NULL. What i want is if query return NULL value than it should return 1944.0000
and For this i have tried below code but did not get any success
SELECT IF( (SELECT (CASE
WHEN 1944.0000 >= country_from_price
AND 1944.0000 <= country_to_price
THEN ((1944.0000 + ((1944.0000 * country_percentage)/100)))
ELSE 1944.0000
END
) as f1
FROM `country_markup`
WHERE estatus = '1'
AND country_id REGEXP '[[:<:]]223[[:>:]]') IS NOT NULL, f1 ,1944.0000) as final_price
Thanks in advance

This appears to work with COALESCE (assuming your original query can only return a single record):
SELECT COALESCE((
SELECT
CASE WHEN 1944.0000 >= country_from_price AND 1944.0000 <= country_to_price
THEN ((1944.0000 + ((1944.0000 * country_percentage)/100)))
ELSE 1944.0000
END
FROM `country_markup`
WHERE estatus = '1'
AND country_id REGEXP '[[:<:]]138[[:>:]]'), 1944.0000) final_price
SQL Fiddle Demo
You can add LIMIT 1 to your subquery to make sure it only returns a single record as well if needed.
Here's an alternative using the MAX aggregate with COALESCE:
SELECT
COALESCE(MAX( CASE WHEN 1944.0000 >= country_from_price AND 1944.0000 <= country_to_price
THEN ((1944.0000 + ((1944.0000 * country_percentage)/100)))
ELSE 1944.0000
END ),1944.0000) final_price
FROM `country_markup`
WHERE estatus = '1'
AND country_id REGEXP '[[:<:]]138[[:>:]]'
More Fiddle

You just need to test that the country_percentage is not null in your expression:
SELECT (CASE WHEN 1944.0000 between country_from_price AND country_to_price and
country_percentage is not null
THEN ((1944.0000 + ((1944.0000 * country_percentage)/100)))
ELSE 1944.0000
END)
FROM `country_markup`
WHERE estatus = '1' AND country_id REGEXP '[[:<:]]138[[:>:]]';
I also changed the comparison logic to use between.

Related

SQLSERVER Running Balance

Actually i have problem on my query to get the running balance , i have debit and credit transaction i need one column to showing the cumulative running balance this is the code i used :
Select * From (
Select D.AccNo, H.[Date], A.AccountName, H.TrxNo,
(Case When ((D.Remark = '') or (D.Remark is Null)) Then H.Trxnote Else D.Remark End) As TrxDetailDescA,
(D.Debit * 1) AS DebitValue, (D.Credit * 1) AS CreditValue,SUM(COALESCE(D.Debit, 0) - COALESCE(D.Credit, 0)) AS Balance
From TblHeadTrans H, TblTransDetails D, TblAccount A
Where H.Guid = D.[LineNo]
And D.AccNo = A.AccountNo
And H.[Date] >= '01-01-2022' And H.[Date] <= '10-07-2022' And D.AccNo >= '1003'
group by AccNo,H.[Date],A.AccountName,H.TrxNo,D.Remark,h.Trxnote,d.Debit,d.Credit
Union All
Select D.AccNo, Null As TrxDate, A.AccountName, Null As TrxNo,
'Opening Balance' As TrxDetailDesc,
Case When (Sum(D.Debit * 1) - Sum(D.Credit *1)) < 0 then 0
Else (Sum(D.Debit * 1) - Sum(D.Credit * 1)) End As DebitValue,
Case When (Sum(D.Credit * 1) - Sum(D.Debit * 1)) < 0 then 0
Else (Sum(D.Credit * 1) - Sum(D.Debit * 1)) End As CreditValue
, SUM(COALESCE(d.Debit, 0) - COALESCE(d.credit, 0)) AS Balance
From TblHeadTrans H, TblTransDetails D, TblAccount A
Where H.guid = D.[LineNo] And D.AccNo = A.AccountNo
And d.[Date] < '01-01-2022' And D.accno = '1003'
Group By D.AccNo, A.AccountName,H.Date,H.TrxNo
) ReportData
WHERE 1=1
Order By AccNo, [Date], TrxNo
and the result showing as the picture:
the result

Insert into not inserting for mysql

I have below insert into statement , for mysql. When i run select statement alone it brings results.
Create statement for table is below
**create table if not exists analyze_checks(dbname varchar(50),table_name varchar(50),frag_ratio decimal, days integer,needs_optimization char(3),needs_analyzing char(3)) ENGINE=INNODB**
**insert into analyze_checks(dbname,table_name,frag_ratio, days,needs_optimization,needs_analyzing )
(select
'test' as dbname,
table_name,
frag_ratio,
days,
needs_optimization,
needs_analyzing
from
(select
table_name,
cast(frag_ratio as decimal(5,2)) as frag_ratio,
days,
case when frag_ratio > 1 then 'Yes' else 'No' end as needs_optimization,
case when days > -1 then 'Yes' else 'No' end as needs_analyzing
from (
select
t.ENGINE,
concat(t.TABLE_SCHEMA, '.', t.TABLE_NAME) as table_name,
round(t.DATA_FREE/1024/1024, 2) as data_free,
(t.data_free/(t.index_length+t.data_length)) as frag_ratio,
datediff(now(), last_update) as days
FROM information_schema.tables t
left join mysql.innodb_table_stats s on t.table_name=s.table_name
WHERE DATA_FREE > 0 ORDER BY frag_ratio DESC )d ) d
where needs_optimization='Yes' or needs_analyzing='Yes');**
There is no need to wrap the SQL statement used for the INSERT in brackets. Heck, the whole query can be simplified like this:
INSERT INTO analyze_checks(dbname,table_name,frag_ratio, days,needs_optimization,needs_analyzing )
SELECT 'test' AS dbname,
tmp.table_name,
CAST(tmp.frag_ratio AS DECIMAL(5,2)) AS frag_ratio,
tmp.days,
CASE WHEN tmp.frag_ratio > 1 THEN 'Yes' ELSE 'No' END AS needs_optimization,
CASE WHEN tmp.days > -1 THEN 'Yes' ELSE 'No' END as needs_analyzing
FROM (SELECT CONCAT(t.TABLE_SCHEMA, '.', t.TABLE_NAME) AS table_name,
ROUND(t.DATA_FREE/1024/1024, 2) AS data_free,
(t.data_free / (t.index_length + t.data_length)) AS frag_ratio,
DATEDIFF(NOW(), last_update) AS days
FROM information_schema.tables t LEFT JOIN mysql.innodb_table_stats s ON t.table_name = s.table_name
WHERE DATA_FREE > 0) tmp
WHERE 'Yes' = CASE WHEN tmp.frag_ratio > 1 THEN 'Yes'
WHEN tmp.days > -1 THEN 'Yes'
ELSE 'No' END
ORDER BY frag_ratio DESC;
Brackets and derived tables are fine when used in moderation 🤐

mysql equivalent of over function in lower versions

I wrote the following query for a project of mine, it is working perfect, however it is working only for mysql 8 since I am using 'over' function in the query which is not supported by earlier mysql versions. I need to rewrite the query without using over so that it will work for lower versions of mysql as well.
$new_query = "
update ospos_sales_items t
inner join (
select sales_items_id, sum(total_amount) over(order by sales_items_id) sum_rate
from ospos_sales_items t
where payment_type = 'Credit' AND t.customer_id = $pid
) t1 on t1.sales_items_id = t.sales_items_id
set
t.payment_type = 'Cash',
t.total_amount = case when t1.sum_rate >= $amount then t1.sum_rate - $amount else (t.total_amount) end,
t.payment_type = case when t1.sum_rate >= $amount then 'Credit' else 'Cash' end
where t1.sum_rate - (t.total_amount) < $amount AND t.customer_id = $pid
";
I tried the below but it is not working.
$new_query = "
update ospos_sales_items t
inner join (
select sales_items_id, sum(total_amount) sum_rate
from ospos_sales_items t
where payment_type = 'Credit' AND t.customer_id = $pid
) t1 on t1.sales_items_id = t.sales_items_id
set
t.payment_type = 'Cash',
t.total_amount = case when t1.sum_rate >= $amount then t1.sum_rate - $amount else (t.total_amount) end,
t.payment_type = case when t1.sum_rate >= $amount then 'Credit' else 'Cash' end
where t1.sum_rate - (t.total_amount) < $amount AND t.customer_id = $pid
";
UPDATE:
I have simplified the subquery that is using over so that an answer can be easy, please check the fiddle suggest how to write the query without using over function but get the same results as the fiddle
select sum(total_amount) over(order by item_id) sum_rate from mytable order by item_id
select sum(y.total_amount) sum_rate
from mytable x
join mytable y
on y.item_id <= x.item_id
group
by x.item_id
order
by x.item_id

Explain me ways to understand this complex query

Can anyone help me to understand this big sql query. How do I break it down in small chunks to understand it ?
select t.Instrument as Instrument ,ClearingId as ClearingId,
ISNULL( PrevQty ,0) AS PrevQty,SettlePrice,
ISNULL(TodayBuyQty,0) as TodayBuyQty,
ISNULL( TodaySellQty ,0) AS TodaySellQty,
ISNULL(PrevQty +TodayBuyQty-TodaySellQty,0) as NetQty,
TodayBuyPrice, TodaySellPrice,LTP,PnL,Token
from
(
select Instrument,w.ClearingId as ClearingId,
ISNULL( PrevQty ,0) AS PrevQty,ISNULL(TodayBuyQty,0) as TodayBuyQty,
ISNULL( TodaySellQty ,0) AS TodaySellQty,
TodayAvgBuyPrice as TodayBuyPrice,TodayAvgSellPrice as TodaySellPrice,
LTP,PnL,w.Token
from
(
select Symbol as Instrument, ClearingId,
ISNULL(TodayBuyQty,0) as TodayBuyQty,
TodayAvgBuyPrice,
ISNULL( -TodaySellQty ,0) AS TodaySellQty,
TodayAvgSellPrice, NULL as LTP ,NULL as PnL ,
w.Token as Token
from
(
select Token, sum(Qty) as NetPositionQty, ClearingId,
sum(CASE WHEN Qty < 0 THEN Qty ELSE 0 END) as TodaySellQty,
sum(CASE WHEN Qty > 0 THEN Qty ELSE 0 END) as TodayBuyQty,
sum(CASE WHEN Qty < 0 THEN Qty * Price ELSE 0 END)
/
NULLIF(sum(CASE WHEN Qty < 0 THEN Qty ELSE 0 END), 0) as TodayAvgSellPrice,
sum(CASE WHEN Qty > 0 THEN Qty * Price ELSE 0 END)
/
NULLIF(sum(CASE WHEN Qty > 0 THEN Qty ELSE 0 END), 0) as TodayAvgBuyPrice
from
(
select m.Token,
(CASE WHEN ClearingId = 'SATP' THEN 'STRAITS' ELSE CASE WHEN ClearingId = 'BATP' THEN 'BPI' ELSE 'UOB' END END ) as ClearingId ,
Price/CAST(Multiplier AS float ) as Price,Qty
from
(
select Token , Exchange as ClearingId ,
LastTradePrice as Price ,
CASE WHEN Side = 'S' THEN -LastTradeQuantity ELSE LastTradeQuantity END as Qty
from Strategy_Orders
where ExchangeStatus in (9,10) )m
JOIN TokenMap t ON ( m.Token = t.Token)
UNION ALL
select m.Token, (CASE WHEN ClearingId = 'SATP' THEN 'STRAITS' ELSE CASE WHEN ClearingId = 'BATP' THEN 'BPI' ELSE 'UOB' END END ) as ClearingId ,
Price/CAST(Multiplier AS float ) as Price,
Qty
from
(
select Token , Exchange as ClearingId ,
LastTradePrice as Price ,
CASE WHEN Side = 'S' THEN -LastTradeQuantity ELSE LastTradeQuantity END as Qty
from Manual_Orders
where ExchangeStatus in (9,10) )m
JOIN TokenMap t ON ( m.Token = t.Token)
UNION ALL
select Token , ClearingId , TodayBuyPrice ,
TodayBuyQty as Qty
from EOD_Holdings
where CurrentDate =
( select top 1 CurrentDAte from EOD_Holdings
order by CurrentDAte desc
)
UNION ALL
select Token , ClearingId , TodaySellPrice ,
TodaySellQty as Qty
from EOD_Holdings
where CurrentDate = (
select top 1 CurrentDAte from EOD_Holdings
order by CurrentDAte desc
)
) x
group by Token,ClearingId) w
JOIN(select Token, Symbol from TokenMAp ) h on w.Token = h.Token
) w
FULL OUTER JOIN(
select Token, PrevQty , ClearingId
from EOD_Holdings
where CurrentDate = ( select top 1 CurrentDAte from EOD_Holdings order by CurrentDAte desc
)
) h
on w.Token = h.Token and w.ClearingId = h.ClearingId
)t
JOIN (
select * from LatestSettlePrices
) sp
on t.Instrument = sp.Instrument
You can break the query into chunks by looking at each subquery ("select ..." ) separately and running them to see the results. You need to start with the innermost queries that do not have other select statements in the "from" or "where" clause.
Also note that this query does not seem to be a clear, neither an optimal solution.
You would want to avoid using full outer joins and union all statements for the best performance.

EMBEDDED DATEDIFF EXCLUD WEEKENDS + CASE STATEMENT

I have the below query that utilizes a case statement. I would like to datediff two dates but exclude weekend days.
I have the below that excutes but now I would like to exclude Sat and Sunday from this... AND DATEDIFF(DD,A.ALERTS_CREATE_DT,S.CreatedDate) <= 2
CASE WHEN
S.Name IN ('Assessment','Survey')
AND A.ALERT_DESC = 'ER'
AND CAST(A.ALERTS_CREATE_DT AS DATE) <= CAST(S.CreatedDate AS DATE)
AND DATEDIFF(DD,A.ALERTS_CREATE_DT,S.CreatedDate) <= 2 /*EXCLUDE Sat and Sunday from the calculation*/
Full Query
SELECT
CASE WHEN
S.Name IN ('Assessment','Survey')
AND A.ALERT_DESC = 'ER'
AND CAST(A.ALERTS_CREATE_DT AS DATE) <= CAST(S.CreatedDate AS DATE)
AND
( DATEDIFF(DD,A.ALERTS_CREATE_DT,S.CreatedDate) <= 2 /*Business Days*/
--DATEDIFF(DD,A.ALERTS_CREATE_DT,S.CreatedDate) + 1
---(DATEDIFF(WK,A.ALERTS_CREATE_DT,S.CreatedDate) * 2)
---(CASE WHEN DATENAME(DW,A.ALERTS_CREATE_DT) = 'SUNDAY' THEN 1 ELSE 0 END)
---(CASE WHEN DATENAME(DW,S.CreatedDate) = 'SATURADAY' THEN 1 ELSE 0 END)
)
THEN 'Y'
WHEN A.ALERT_DESC = 'model' OR S.CreatedDate IS NULL OR S.Name = 'ER'
THEN ''
ELSE 'N'
END 'Count towards Alerts'
FROM A
FULL S ON A.id= S.id
WHERE 1=1
This should give you the required result by excluding the Saturdays and Sundays.
SELECT A.ALERT_DESC,A.ALERTS_CREATE_DT,S.Name,S.CreatedDate,
CASE WHEN
S.Name IN ('Assessment','Survey') AND A.ALERT_DESC = 'ER'
AND CAST(A.ALERTS_CREATE_DT AS DATE) <= CAST(S.CreatedDate AS DATE)
AND
(( DATEDIFF(DD,A.ALERTS_CREATE_DT,S.CreatedDate)+1
- (datediff(wk,A.ALERTS_CREATE_DT,S.CreatedDate)*2)
- case when datepart(dw,A.ALERTS_CREATE_DT)=1 then 1 else 0 end
- case when datepart(dw,S.CreatedDate)=7 then 1 else 0 end
)) <=2 THEN 'Y'
WHEN A.ALERT_DESC = 'model' OR S.CreatedDate IS NULL OR S.Name = 'ER' THEN ''
ELSE 'N' END 'Count towards Alerts'
FROM A,S