How do I CAST AS DECIMAL in postgresql? - sql

The Percent_Failure in the query below is giving results as either 1.00 or 0.00. Can anyone help me understand why it's not giving me the actual decimal?
SELECT
sf.hierarchy_name AS Hierarchy_Name,
cl.cmh_id AS CMH_ID,
cl.facility_name AS Clinic_Name,
sf.billing_city AS City,
sf.billing_state_code AS State,
cl.num_types AS Num_Device_Dypes,
cl.num_ssids AS Num_SSIDs,
SUM(CAST(CASE WHEN (d.mdm_client_version NOT LIKE '1.14%' AND d.type = 'Wallboard')
OR (d.mdm_client_version NOT LIKE '1.14%' AND d.type = 'Tablet')
OR (d.mdm_client_version NOT LIKE '1.14%' AND d.type = 'AndroidMediaPlayer')
OR (d.mdm_client_version NOT LIKE '1.14%' AND d.type = 'InfusionRoomTablet') THEN 1 ELSE 0 END AS INTEGER)) AS Non_Updated,
COUNT(d.asset_id) AS Total_Devices
CAST((Non_Updated) / (Total_Devices) AS DECIMAL (5,4)) AS Percent_Failure
FROM
(SELECT id, clinic_table_id, type, asset_id, mdm_client_version, device_apk_version, ssid
FROM mdm.devices) d
JOIN
(SELECT a.id, a.cmh_id, a.facility_name, COUNT(DISTINCT b.ssid) AS num_ssids, COUNT(DISTINCT b.type) AS num_types
FROM mdm.clinics a
JOIN
(SELECT *
FROM mdm.devices
WHERE status = 'Active'
AND last_seen_at >= (CURRENT_DATE - 2)
AND installed_date <= (CURRENT_DATE - 3)) b
ON a.id = b.clinic_table_id
GROUP BY 1,2,3) cl
ON d.clinic_table_id = cl.id
JOIN
(SELECT x.cmh_id, x.hierarchy_group, x.hierarchy_name, x.billing_city, x.billing_state_code
FROM salesforce.accounts x) sf
ON sf.cmh_id = cl.cmh_id
GROUP BY 1,2,3,4,5,6,7
ORDER BY 10 DESC;

Integer / Integer = Integer. So, you need to cast it before you do the division:
cast (Non_Updated as decimal) / Total_Devices AS Percent_Failure
or shorthand:
Non_Updated::decimal / Total_Devices AS Percent_Failure
I've seen other cute implementations, such as
Non_Updated * 1.0 / Total_Devices AS Percent_Failure
Also, are you sure that total_devices is always non-zero? If not, be sure to handle that.

Try individually cast numerator or denominator as decimal, otherwise the result of the division is considered to be integers.
So you can use :
Non_Updated / CAST(Total_Devices AS DECIMAL)
or
CAST ( Non_Updated AS DECIMAL ) / Total_Devices

cast the numerator to decimal
CAST(Non_Updated) as decimal / Total_Devices
for e.g.
select cast(3 as decimal)/4 ;

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))

Get Decimal Places for 10/7

I am trying to make a Calculation where I want to update ideal hours based on number of Assistant and Head Coaches based on whether a restaurant is 5 day or 7 day a week. When I make a calculation where I use 10/7 or 20/7, it takes it as 1 and 2 respectively. I am currently using trunc but I have tried using cast :: decimal(10,6) etc and it doesn't work.
select
a.entity,
a.store_name,
a.order_date,
a.daily_ideal_hours,
a.daily_ideal_hours - (case when b.days_open like '%Weekdays%' then ((c.total_acs*(20/5) + c.total_hcs*(10/5)))
when b.days_open like '%All%' then ((c.total_acs * trunc(20/7,10)) + (c.total_hcs * trunc(10/7,10))) end) as updated_value
from scorecards_ideal_labor_hours as a
left join days_store_open as b
on a.entity = b.entity
left join hc_ac_data as c
on a.entity = c.entity_id
and a.order_date = c.report_date
where a.order_date between '2021-12-06' and '2021-12-12'
and a.entity = 66
order by a.order_date desc;
How do I fix this?
You don't need to use trunc function here.
Just typecast both numerator and denominator to float.
This will give the final answer with decimal places, without any rounding:
select (10::float)/(7::float);
This gives answer as:
1.4285714285714286
If you need to round the final answer to few digits only:
select trunc((10::float)/(7::float),2);

Oracle sql case over a computed column

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.

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.

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