Case statement with Multiple Nested Else - sql

I have this requirement where I have to emulate an Excel formula into Oracle SQL. Since Excel is very rudimentary, everything goes in it but SQL is regimented and must fall in line.
This is the formula in Excel (Business Category):
=IF([#[Order Days]]="","",
IF(OR([#business type]="Probation Touch Point",[#business type]="Referral",
[#business type]="Mystery Shopping"),IF([#[Order Days]]>45,"Allowed","Not Allowed"),
IF(OR(AND([#business status]="Assigned",[#[Order Days]]>60),
AND([#business status]="Pre-Review",[#[Order Days]]>60),
AND([#business status]="In-Review",[#[site]]="Location",[#[Order Days]]>44),
AND([#business status]="In-Review",[#[site]]="Headquarters",[#[Order Days]]>74)),"Permitted",
IF([#business status]="Post-Review",IF([#business review]=0,IF([#[Order Days]]>44,"Allowed","Not
Allowed"),
IF(OR(AND([#[site]]="Headquarters",[#[Order Days]]>90),
AND([#[site]]="Location",[#[Order Days]]>60)),"Allowed","Not Allowed")),"Not Allowed"))))
As its conspicuous, there are multiple else within a single formula and its purposeful.
My SQL formula:
case when order_days is null then null
when business_type like '%Touch%' or business_type = 'Referral'
or business_type like 'Myster%' and order_days > 45 then 'Allowed'
when (business_status = 'Assigned' and order_days > 60) or
(business_status = 'Pre-Review' and order_days > 60) or
(business_status = 'In-Review' and site like 'Loca%' and order_days > 44) or
(business_status = 'In-Review' and site like 'Head%' and order_days > 74) then 'Permitted'
when (business_status like 'Post%' or business_type = 0 or order_days > 44) then 'Allowed'
when (site like 'Head%' and order_days > 90) then 'Allowed'
when (site like 'Loca%' and order_days > 60) then 'Allowed' else 'Not Allowed'
end as business_category
The sql case is futile because it results in wrongful figures.
Excel result:
Business Category Count of Rows
Allowed 130
Not Allowed 1122
Permitted 200
SQL Result:
business_category Count
Allowed 980
Not Allowed 272
Permitted 200
Can someone please provide assistance!

You switched the logic to use LIKE in some places. Because you didn't include any data it's impossible to determine if this was causing some of the problems you reported, but I've restored the comparison to the individual values used in the Excel formula. In addition, I think your interpretation of the "business_review <> 0" and the "business_status <> 'Post Review'" branches may have been in error.
The following should do what you want:
case
when order_days is null
then null
when business_type in ('Probation Touch Point', 'Referral', 'Mystery Shopping') AND order_days > 45
then 'Allowed'
when (business_status = 'Assigned' and order_days > 60) or
(business_status = 'Pre-Review' and order_days > 60) or
(business_status = 'In-Review' and site = 'Location' and order_days > 44) or
(business_status = 'In-Review' and site = 'Headquarters' and order_days > 74) then 'Permitted'
when (business_status = 'Post-Review' and business_review = 0 and order_days > 44) then 'Allowed'
when (business_status = 'Post-Review' and business_review = 0 and order_days <= 44) then 'Not Allowed'
when (business_status = 'Post-Review' and business_review <> 0 and ((site = 'Headquarters' and order_days > 90) or
(site = 'Location' and order_days > 60))
then 'Allowed'
else 'Not Allowed'
when business_status <> 'Post-Review' then 'Not Allowed'
end as business_category
In future you might want to post test data - CREATE TABLE statement(s) and INSERT statements to put data into those table(s) are a good idea - along with expected results.

Related

Conversion failed when converting the varchar value '5005A' to data type int

So I get the data from my server and the mvmt number consists of 3 characters and 4 digits (EX: CVG5694) or unless they start when it starts with X because it's 1 character (the letter x), and 5 digits (ex: X12051). This code worked for me until I got the error,
Conversion failed when converting the varchar value '5005A' to data type int.
I assume because it has the character A in the end. Anyone know how to fix?
SQL_Query = pd.read_sql_query('''SELECT[MVMT_DT],
[MVMT_NUMBER],
CAST(RIGHT([MVMT_NUMBER], PATINDEX('%[0-9][^0-9]%', REVERSE([MVMT_NUMBER])+' ')) as INT) as movement,
[MVMT_TYPE],
[OPERATOR],
[EQUIPMENT],
[ORIG],
[DEST],
[MVMT_STATUS],
CASE WHEN [GROSS_WEIGHT_(KG)] < 0 THEN 0 ELSE [GROSS_WEIGHT_(KG)] END AS [GROSS_WEIGHT_(KG)],
CASE WHEN [NET_WEIGHT_(KG)]< 0 THEN 0 ELSE [NET_WEIGHT_(KG)] END AS [NET_WEIGHT_(KG)],
CASE WHEN [NMBR_ULDS] < 0 THEN 0 ELSE [NMBR_ULDS] END AS [NMBR_ULDS],
CASE WHEN [NMBR_POS] < 0 THEN 0 ELSE [NMBR_POS] END AS [NMBR_POS]
FROM PATH
WHERE [F-T-O] = 'T'
AND ORIG IN ('CVG', 'CVG CRN', 'MIA', 'MIA GTW', 'LAX', 'LAX GTW', 'JFK', 'JFK GTW', 'ORD', 'ORD GTW')
AND MVMT_TYPE IN ('O/XL', 'O/XL/AH', 'T/XL', 'T/XL/AH', 'CL/AH', 'O/AH', 'T/AH')
AND [MVMT_NUMBER] NOT LIKE '%AMZ%'
AND [MVMT_NUMBER] NOT LIKE '%A0%'
AND [MVMT_NUMBER] NOT LIKE '%K0%'
AND [MVMT_NUMBER] NOT LIKE '%A1%'
AND [MVMT_NUMBER] NOT LIKE '%K1%'
--AND RIGHT([MVMT_NUMBER], 4) <= 5000
AND MVMT_DT = '2021-12-06' --DATEADD(DAY, -2, GETDATE()) AND DATEADD(DAY, -1, GETDATE())''',conn_)
CXL_Filter = ['O/XL', 'O/XL/AH', 'T/XL', 'T/XL/AH']
Ad_Hoc_Filter = ['CL/AH', 'O/AH', 'T/AH']
CXL_CVG = SQL_Query[SQL_Query.MVMT_TYPE.isin(CXL_Filter) & (SQL_Query['ORIG'] == 'CVG') & (SQL_Query['movement'] >= 5000)]
CXL_CVG_CRN = SQL_Query[SQL_Query.MVMT_TYPE.isin(CXL_Filter) & (SQL_Query['ORIG'] == 'CVG CRN') & (SQL_Query['movement'] >= 5000)]
Ad_Hoc_CVG = SQL_Query[SQL_Query.MVMT_TYPE.isin(Ad_Hoc_Filter) & (SQL_Query['ORIG'] == 'CVG') & (SQL_Query['movement'] >= 5000)]
Ad_Hoc_CVG_CRN = SQL_Query[SQL_Query.MVMT_TYPE.isin(Ad_Hoc_Filter) & (SQL_Query['ORIG'] == 'CVG CRN') & (SQL_Query['movement'] >= 5000)]```

Power BI Report Builder Indicator Formula

I am adding in an indicator to a PBI Report Builder Report. The indicator is based off multiple fields from the dataset so I need to use a formula, to create the three up/down/side arrows.
Previously in Crystal Reports this could be implemented using a series of IF statements as follows. The below example is what is required for the down arrow. (the other 2 arrows also have multiple calculations)
IF (({spScorecard_SLView;1.CATEGORY_ID} = 4) OR
({spScorecard_SLView;1.CATEGORY_ID} = 25)) THEN
IF ({spScorecard_SLView;1.PM_3MM_NC_CNT}-{spScorecard_SLView;1.3MM_NC_CNT}) <
0 THEN 'Down Arrow'
ELSE IF (({spScorecard_SLView;1.CATEGORY_ID} = 21)
OR({spScorecard_SLView;1.CATEGORY_ID} = 26) OR
({spScorecard_SLView;1.CATEGORY_ID} = 41)) THEN
IF ({spScorecard_SLView;1.CM_TOTAL_CNT}> 0) AND
(({spScorecard_SLView;1.PM_3MM_TOTAL_CNT} = 0) OR
({spScorecard_SLView;1.3MM_TOTAL_CNT} = 0)) AND
({spScorecard_SLView;1.3MM_NC_CNT} > 0) AND
(((({spScorecard_SLView;1.3MM_TOTAL_CNT} - {spScorecard_SLView;1.3MM_NC_CNT})
/ {spScorecard_SLView;1.3MM_TOTAL_CNT}) * 100) >= 0.00) THEN 'Down Arrow' //
ELSE IF ((((({spScorecard_SLView;1.3MM_TOTAL_CNT} -
{spScorecard_SLView;1.3MM_NC_CNT}) / {spScorecard_SLView;1.3MM_TOTAL_CNT}) *
100) -((({spScorecard_SLView;1.PM_3MM_TOTAL_CNT} -
{spScorecard_SLView;1.PM_3MM_NC_CNT}) /
{spScorecard_SLView;1.PM_3MM_TOTAL_CNT}) * 100))/100) < 0.00 THEN
'Down Arrow'
I am stuck as to how to do something similar in PBI Report builder. Should I create a formula in the Value field under Value and States, and then delete any arrow settings under the Indicator States?
Can you create a formula using 'Down Arrow' etc in an IIf statement? I can only get indicator data returned when selecting 1 field under Value, but I need multiple fields & conditions.
SSRS Reports are similar to PBI Report builder so if there are any examples using it that may be of help. I am connecting to a SQL Server stored proc to pull back the data.
Thanks
Blowers
I would approach it like this...
Set a formula in the Indicator Value so that you return a number that corresponds to the arrow you want to show (e.g. return 1, 2 or 3)
You can use whatever format you feel comfotable with but I would suggest using the SWITCH() function rather than nested IIFs.
For example this checks two fields and returns one of three values, (this is just a random example to illustrate the point)
=SWITCH(
SUM(Fields!Amount.Value) >5000 AND Fields!Year.Value >2019, 1
, SUM(Fields!Amount.Value) >10000 AND Fields!Year.Value <2019, 2
, True, 3
)
Switch takes pairs of expressions and return values. It returns the value when it hits the first expression that evaluates to True. So this reads...
If the aggregated Amount is greater than 5000 and the Year >2019 then return 1
If the aggregated Amount is greater than 10000 and the Year <2019
then return 12
Else return 3
The final 'True', as it will always return true acts like an ELSE
Anyway, this will return a value of either 1, 2 or 3
Then in the Indicator Properties, just set the range for each indicator to 1, 2 or 3 like this
I ended up using IIF Logic to solve this, some of the calculations were too awkward in the end and it was easier for me to use IIF.
Using the 1,2,3 indicator values works well.
Here is the expression that i ended up using:
=IIF(Fields!CATEGORY_ID.Value = 4 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) < 0,1,
IIF(Fields!CATEGORY_ID.Value = 25 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) < 0,1,
IIF(Fields!CATEGORY_ID.Value = 4 AND Fields!PM_3MM_NC_CNT.Value <> 0
AND Fields!Q3MM_NC_CNT.Value <> 0 AND Fields!PM_3MM_NC_CNT.Value =
Fields!Q3MM_NC_CNT.Value ,2,
IIF(Fields!CATEGORY_ID.Value = 25 AND Fields!PM_3MM_NC_CNT.Value <> 0
AND Fields!Q3MM_NC_CNT.Value <> 0 AND Fields!PM_3MM_NC_CNT.Value =
Fields!Q3MM_NC_CNT.Value ,2,
IIF(Fields!CATEGORY_ID.Value = 4 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) > 0, 3,
IIF(Fields!CATEGORY_ID.Value = 25 AND Sum(Fields!PM_3MM_NC_CNT.Value -
Fields!Q3MM_NC_CNT.Value) > 0, 3,
IIF(Fields!CATEGORY_ID.Value = 4 AND Fields!PM_3MM_NC_CNT.Value = 0 AND
Fields!Q3MM_NC_CNT.Value = 0,4,
IIF(Fields!CATEGORY_ID.Value = 25 AND Fields!PM_3MM_NC_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value = 0,4,
IIF(Fields!CATEGORY_ID.Value = 21 AND Fields!CM_TOTAL_CNT.Value > 0 AND
Fields!PM_3MM_TOTAL_CNT.Value =0,1,
IIF(Fields!CATEGORY_ID.Value = 26 AND Fields!CM_TOTAL_CNT.Value > 0 AND
Fields!PM_3MM_TOTAL_CNT.Value =0,1,
IIF(Fields!CATEGORY_ID.Value = 41 AND Fields!CM_TOTAL_CNT.Value > 0 AND
Fields!PM_3MM_TOTAL_CNT.Value =0,1,
IIF(Fields!CATEGORY_ID.Value = 21 AND Fields!Q3MM_TOTAL_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value > 0 AND Fields!TrendCalculation1.Value -
Fields!TrendCalculation2.Value > 0.00,1,
IIF(Fields!CATEGORY_ID.Value = 26 AND Fields!Q3MM_TOTAL_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value > 0 AND Fields!TrendCalculation1.Value -
Fields!TrendCalculation2.Value > 0.00,1,
IIF(Fields!CATEGORY_ID.Value = 41 AND Fields!Q3MM_TOTAL_CNT.Value = 0
AND Fields!Q3MM_NC_CNT.Value > 0 AND Fields!TrendCalculation1.Value -
Fields!TrendCalculation2.Value > 0.00,1,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!PM_3MM_TOTAL_CNT.Value = 0,3,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!Q3MM_TOTAL_CNT.Value = 0,3,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!TrendCalculation1.Value - Fields!TrendCalculation2.Value <
0.00,1,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!TrendCalculation1.Value - Fields!TrendCalculation2.Value >
0.00,3,
IIF(Fields!CATEGORY_ID.Value <> 12 AND Fields!CATEGORY_ID.Value <> 30
AND Fields!TrendCalculation1.Value - Fields!TrendCalculation2.Value =
0.00,2,
5)))))))))))))))))))

SQL - JOIN with condition CASE - how to make - if condition is met stop to meet next one

Cashier can input to field C40_DATA 3 different values (9962**********, id_invoice, web_order)
what I would like to have as result:
if substr from C40_DATA contains p.id_invoice => show these lines
if C40_contains contains id_web_order or id_incvoice => show these lines
-> it means point 1 shows always but point 2 -> do not show both, if exist id_web_order, show it and stop, if it not exists find id_incvoice
When I create this (below), result contains all 3 together, but I need 1 + (if exist 2 and if not find 3)
select * from web_data p
inner join POS_DATA re on
(case
when substr(re.C40_DATA,5,8) = p.id_invoice and substr(re.C40_DATA,1,4) ='9962' then 1 else
(case
when re.C40_DATA = p.id_web_order and p.d_mnozstvi < '0' then 1 else
(case
when re.C40_DATA = p.id_invoice and p.d_mnozstvi < '0' then 1 else 0 END)
END)
END=1)
Could you please help how to make contitions in JOINs which do - if one condition is met stop and do not find the next one?
Thank you,
Your attempted query would have been better written this way:
select * from web_data p
inner join POS_DATA re on
substr(re.C40_DATA, 5, 8) = p.id_invoice and substr(re.C40_DATA, 1, 4) = '9962'
or re.C40_DATA = p.id_web_order and p.d_mnozstvi < '0'
or re.C40_DATA = p.id_invoice and p.d_mnozstvi < '0'
Had you really needed to do this as a case expression it could have been done as below. The cases fall through in order:
case
when substr(re.C40_DATA, 5, 8) = p.id_invoice and substr(re.C40_DATA, 1, 4) ='9962' then 1
when re.C40_DATA = p.id_web_order and p.d_mnozstvi < '0' then 1
when re.C40_DATA = p.id_invoice and p.d_mnozstvi < '0' then 1
end = 1
As far as matching only on a single condition, I think you want something like this:
with data as (
select *,
case
when re.C40_DATA = '9962' + p.id_invoice then 1
when re.C40_DATA = p.id_web_order and p.d_mnozstvi < '0' then 2
when re.C40_DATA = p.id_invoice and p.d_mnozstvi < '0' then 3
end as match_rank,
min(case
when re.C40_DATA = '9962' + p.id_invoice then 1
when re.C40_DATA = p.id_web_order and p.d_mnozstvi < '0' then 2
when re.C40_DATA = p.id_invoice and p.d_mnozstvi < '0' then 3
) over (partition by p.id_invoice, p.web_order) as min_match_rank
from web_data p
inner join POS_DATA re on
re.C40_DATA = '9962' + p.id_invoice
or re.C40_DATA = (p.id_web_order, p.id_invoice) and p.d_mnozstvi < '0'
)
select * from data where match_rank = min_match_rank;
I've taken the liberty of rewriting some of your conditions in case those options are useful to you. Also, I'm not sure what < '0' is supposed to mean. Finally, I'm not sure which values to be partitioning over because I don't understand the relationship between id_invoice and id_web_order.

How to make a case condition inside codeigniter query

I have some query like this :
$this->db->query("SELECT `no_request`,`date_in`,`location`,`d_point`,`username`,SUM(request.`persen`) AS 'Persen',
CASE
WHEN SUM(Persen) = 0 THEN 'Pending'
WHEN SUM(persen) = 100 THEN 'Complete'
WHEN SUM(persen) > 0 AND SUM(persen) < 100 THEN 'On Process'
END AS 'states'
FROM request WHERE `location` = '$lokasi' GROUP BY `no_request`
HAVING
CASE
WHEN `Persen` = 0 THEN `states` = 'Pending'
END", TRUE)->result_array();
I want make query original from codeigniter but i have some problem with my query :
$this->db->select($this->fetching_column);
$this->db->select_sum($this->persen);
$this->db->select("
CASE
WHEN SUM('persen') = 0 THEN 'Pending'
WHEN SUM('persen') = 100 THEN 'Complete'
WHEN SUM('persen') > 0 SUM('persen') < 100 THEN 'On Process'
END", FALSE);
$this->db->from($this->table);
$this->db->where($this->location . ' = ' . $location);
$this->db->group_by($this->group);
$result = $this->db->get();
Is my query is wrong?, or I can't use case inside $this->db->select()
$this->db->select() acknowledges a discretionary second parameter. In the event that you set it to FALSE, CodeIgniter won't attempt to ensure your field or table names. This is helpful on the off chance that you need a compound select explanation where programmed getting away of fields may break them.
for reference:- https://codeigniter.com/userguide3/database/query_builder.html#selecting-data
I have make a some fault in my query to make my query isn't working, but now is code is fine and I already done with my code, I change my query like this :
From this code :
$this->db->select($this->fetching_column);
$this->db->select_sum($this->persen);
$this->db->select("
CASE
WHEN SUM('persen') = 0 THEN 'Pending'
WHEN SUM('persen') = 100 THEN 'Complete'
WHEN SUM('persen') > 0 SUM('persen') < 100 THEN 'On Process'
END", FALSE);
$this->db->from($this->table);
$this->db->where($this->location . ' = ' . $location);
$this->db->group_by($this->group);
$result = $this->db->get();
Became like this :
$this->db->select($this->fetching_column);
$this->db->select_sum($this->persen, 'Persen');
$this->db->select("
CASE
WHEN SUM(Persen) = 0 THEN 'Pending'
WHEN SUM(Persen) = 100 THEN 'Complete'
WHEN SUM(Persen) > 0 AND SUM(Persen) < 100 THEN 'On Process'
END AS 'states'");
$this->db->from($this->table);
$this->db->where($this->location, $location);
$this->db->group_by($this->group);
$result = $this->db->get();

How to turn else if statements into single Excel nested statement

I am trying to create a single Excel IF function that incorporates the below IF statements:
If Date_Time_of_Request <= Authorization_Start_Date then REVIEW_TYPE = 'Prospective';
Else If Authorization_Start_Date <= Date_Time_of_Request <= Discharge_Date then REVIEW_TYPE = 'Concurrent';
Else If Date_Time_of_Request > = Discharge_Date then REVIEW_TYPE = 'Retrospective';
Else If Date_Time_of_Request > = Authorization_End_Date then REVIEW_TYPE = 'Retrospective';
My attempt at this is: =IF(AS2 <= J2, "PROSPECTIVE", IF(AND(AS2 >= J2,AS2 <= V2),"CONCURRENT",IF(OR(AS2 > V2,AS2 > H2),"RETROSPECTIVE","UNKNOWN")))
However, V2 is blank in most rows, and I need it to move onto the next statement if V2 is blank. As it is currently written, AS2 > V2 being true most of the time (even with it being blank).
Something like:
and(AS2>V2,LEN(V2)>0)