Oracle sql case over a computed column - sql

I Want to write in oracle sql, case over a computed column. The query is as follow.
Select trunc (Cost*100/Amt) as 'Computed_LTV',
Case
When Request_Term <19 THEN '60'
When Request_Term <=24THEN'-18'
When Computed_LTV <70.805 THEN '-20'
ELSE '-60'
END AS "Var_1"
FROM LOAN_APP

It is used only once, so I'd suggest you use the same formula:
SELECT TRUNC (Cost * 100 / Amt) AS Computed_LTV,
CASE
WHEN Request_Term < 19 THEN '60'
WHEN Request_Term <= 24 THEN '-18'
WHEN TRUNC (Cost * 100 / Amt) < 70.805 THEN '-20' --> here
ELSE '-60'
END AS Var_1
FROM LOAN_APP
If you insist on using a computed column, you'll have to use a CTE or an inline view, but that's probably a little bit too much in this simple case.
Also, get rid of double quotes in Oracle. They cause nothing but problems.
In order to sum several computed columns, do exactly that: sum them up. For example:
select trunc(cost * 100 / amt) as var1,
round(amount * price) as var2,
--
-- sum them using the "+" operator
(trunc(cost * 100 / amt) + round(amount * price)) as result
from ...
Or, if you computed them in a CTE, you'd then
with data as
(select trunc(cost * 100 / amt) as var1,
round(amount * price) as var2
from ...
)
-- now sum them up
select var1 + var2 as result
from data

You cannot re-use a column alias in the SELECT. But starting in Oracle 12C, you can use a lateral join to define it in the FROM clause:
SELECT x.Computed_LTV,
(Case When Request_Term < 19 THEN '60'
When Request_Term <= 24 THEN'-18'
When Computed_LTV < 70.805 THEN '-20'
ELSE '-60'
END) AS Var_1
FROM LOAN_APP la CROSS JOIN LATERAL
(SELECT TRUNC(Cost*100/Amt) as Computed_LTV FROM DUAL) x;
Note: Do not escape identifiers -- using either single quotes or double quotes. That just clutters queries, making them harder to write and to read.

Related

Trying to divide sum/ count of date by each step in SQL - Grouping Expression Sequence is Empty

I am having an issue with this SQL code. I am trying to divide sum/ by the count of a date. I keep getting the grouping expressions sequence is empty, and 'TableBlank.rep_date' is not an aggregate function error. I have tried with ORDER BY and GROUP BY statements and I'm still getting the error.
SELECT
rep_date,
1 AS AssignRank,
StepCompSum,
'StepCompA' AS FunCat,
CAST( StepCompSum / COUNT( rep_date ) AS double ) AS ParticRate
FROM
TableBlank
WHERE
FunCat = 'StepCompA'
UNION
SELECT
rep_date,
2 AS AssignRank,
StepCompSum,
'StepCompB' AS FunCat,
CAST( StepCompSum / COUNT( rep_date ) AS double ) AS ParticRate
FROM
TableBlank
WHERE
FunCat = 'StepCompB'
UNION
SELECT
rep_date,
3 AS AssignRank,
StepCompSum,
'StepCompC' AS FunCat,
CAST( StepCompSum / COUNT( rep_date ) AS double ) AS ParticRate
FROM
TableBlank
WHERE
FunCat = 'StepCompC'
GROUP BY
rep_date,
StepCompSum
Difficult to know without sample data, but this might work:
SELECT
rep_date
, 2 AS AssignRank
, StepCompSum
, FunCat
, CAST(StepCompSum / (COUNT(rep_date) OVER (PARTITION BY FunCat)) AS double) AS ParticRate
FROM TableBlank
Although, I suspect what you are wanting from the CAST is to get the result to not be an integer. Here's what you'll get:
2 / 3 = 1 (because, integer math)
cast(1 as double) = 1.000
when you probably expect 0.667
You need to either cast the values first, or just include a value of the appropriate type in the expression:
StepCompSum * 1.0 / (COUNT(rep_date) OVER (PARTITION BY FunCat))

Referencing other columns in a SQL SELECT

I have a SQL query in BigQuery:
SELECT
creator.country,
(SUM(length) / 60) AS total_minutes,
COUNT(DISTINCT creator.id) AS total_users,
(SUM(length) / 60 / COUNT(DISTINCT creator.id)) AS minutes_per_user
FROM
...
You may have noticed that the last column is equivalent to total_minutes / total_users.
I tried this, but it doesn't work:
SELECT
creator.country,
(SUM(length) / 60) AS total_minutes,
COUNT(DISTINCT creator.id) AS total_users,
(total_minutes / total_users) AS minutes_per_user
FROM
...
Is there any way to make this simpler?
Not really. That is, you cannot re-use column aliases in expressions in the same SELECT. If you really want, you can use a subquery or CTE:
SELECT c.*,
total_minutes / total_users
FROM (SELECT creator.country,
(SUM(length) / 60) AS total_minutes,
COUNT(DISTINCT creator.id) AS total_users
FROM
) c;
Another option is to move all business logic of metrics calculation into UDF (temp or permanent depends on usage needs) ...
create temp function custom_stats(arr any type) as ((
select as struct
sum(length) / 60 as total_minutes,
count(distinct id) as total_users,
sum(length) / 60 / count(distinct id) as minutes_per_user
from unnest(arr)
));
... and thus keep query itself simple and least verbose - as in below example
select creator.country,
custom_stats(array_agg(struct(length, creator.id))).*
from `project.dataset.table`
group by country

How to Group By in SQL Server Query

I'm using this query to get the Sum of SaleAmount for each type (SOType) of Sale Invoices.
I am getting the result but the result is not grouped by SOType. Have tried to use Group by Outside the query after where condition but getting an error as
"Column 'SaleInvoices.InvoiceID' is invalid because it is not
contained in either aggregate or group by function".
DECLARE #fromDate Datetime = '2019/05/23'
DECLARE #toDate Datetime = '2019/10/25'
DECLARE #isKpi int = '1'
SELECT (
(Select Sum((Isnull(I.Quantity,0)*Isnull(I.SalePrice,0))+((Isnull(I.Quantity,0)*Isnull(I.SalePrice,0) - I.Discount) *(I.TAX/100)))
from ItemsSold as I
where I.InvoiceId= S.InvoiceID and I.InvoiceType='Sale Invoice'
) -
(Select isnull(Sum((Isnull(I.Quantity,0)*Isnull(I.SalePrice,0))+((Isnull(I.Quantity,0)*Isnull(I.SalePrice,0) - I.Discount)*(I.TAX/100))),0)
from ItemsSold as I
where I.InvoiceId= S.InvoiceID and I.InvoiceType='Sale Return'
)) as Total
,S.SOType as SOType
FROM SaleInvoices AS S
where S.OrderDate>=Convert(VARCHAR,#fromDate,111) and S.OrderDate<=Convert(varchar,#toDate,111)
You want conditional aggregation. The logic should look something like this:
select s.SOType,
sum(case when i.invoicetype = 'Sale Invoice'
then (I.Quantity * I.SalePrice) * (1 - i.discount) * i.tax / 100.0
when i.invoicetype = 'Sale Return'
then - (I.Quantity * I.SalePrice) * (1 - i.discount) * i.tax / 100.0
end) as Total
from SaleInvoices s join
ItemsSold i
on i.InvoiceId= s.InvoiceID
where s.OrderDate >= #fromDate and
s.OrderDate <= #toDate
group by s.SOType ;
I'm not sure I got the arithmetic correct.
Notes:
The group by clause defines the rows being returned by the query. If you want one row per SOType then you want to GROUP BY SOType.
Use date comparisons and functions for dates. It is absurd to convert a date to a string to compare to a date.
You probably don't need COALESCE() or ISNULL() to handle NULL values. These are generally ignored by aggregation functions.

SQL Increment column value in select statement

I'm trying to write a Select statement that increments a column value by 50, but the range can end up being 200,000 so I can't do it all in a case statement manually.
Something similar to this, but instead of manually writing the increments
Select count(order_id) as order_count,
case when revenue between 0 and 50 then ‘$50’
when order_value between 51 and 100 then ‘$100’
else ‘over $101’
end as revenue_bucket
from Orders
group by 2
Turn your revenue into the bucket value, then make string out of it:
SELECT count(order_id) AS order_count,
'$' || ((((revenue - 0.01)/50)::int + 1) * 50)::text AS revenue_bucket
FROM Orders
GROUP BY 2;
This obviously runs well past $200,000.
You can work with modulo to get this. Limit would be 101 in your example. All you have to do, is cast the result in a string and add the $ before it
Select count(order_id) as order_count,
case when revenue < limit then revenue - (revenue % 50) + 50
else ‘over $101’
end as revenue_bucket
from Orders
group by 2
You can round to the nearest 50 with div (integer division):
revenue div 50 * 50
To round up instead of down:
(revenue div 50 + 1) * 50
To include 50 in the next bracket (so 50 as $50 instead of $100):
((revenue-1) div 50 + 1) * 50
Example query:
select revenue
, concat('$', ((revenue-1) div 50 + 1) * 50) as revenue_bucket
from YourTable
See it working at SQL Fiddle.
figured out something similar
select floor((revenue+49)/50)*50 as revenue_bucket,
count(1) as order_count
from Orders
group by 1;

Dividing 2 numbers returns 0 [duplicate]

This question already has answers here:
Division of integers returns 0
(2 answers)
Closed 10 months ago.
I'm trying to divide 2 counts in order to return a percentage.
The following query is returning 0:
select (
(select COUNT(*) from saxref..AuthCycle
where endOfUse is null and addDate >= '1/1/2014') /
(select COUNT(*) from saxref..AuthCycle
where addDate >= '1/1/2014')
) as Percentage
Should I be applying a cast?
It can be done more succinctly by moving the common condition to the where clause:
select sum(case when endOfUse is null then 1 end) * 100.0 / count(*) percentage
from saxref..AuthCycle
where addDate >= '1/1/2014'
Note how you don't need the case of 0 for false either, since nulls are ignored with sum()
The issue is caused because you are dividing 2 int values, which by default will output an int as it takes the data types used in the calculation to determine the data type of the output, so effectively if you do this:
select 50/100 as result
You get 0.5 output as 0 as it rounds it to an int (no decimal places).
If you however specify decimals:
select 50.0/100.0 as result
You would get 0.5 as a decimal, which you could multiply by 100 to get 50%.
So updating your syntax to multiply by 1.0 and making the counts into decimals would give you the correct result:
select (
(select COUNT(*) from saxref..AuthCycle where endOfUse is null and addDate >= '1/1/2014')*1.0 /
(select COUNT(*) from saxref..AuthCycle where addDate >= '1/1/2014')*1.0
) as Percentage
I would do it differently, using two sums:
select sum
( case
when endOfUse is null and addDate >= '1/1/2014'
then 1
else 0
end
)
* 100.0 -- if you want the usual 0..100 range for percentages
/
sum
( case
when addDate >= '1/1/2014'
then 1
else 0
end
)
percentage
from saxref..AuthCycle