Is it possible to CAST as FLOAT from an IIF statement? - sql

Is it possible to CAST as FLOAT from an IIF statement?
SELECT TOP 100 PeopleID, RateCount, IIF (People.RateCount < 100,
CAST(People.RateCount/100 as FLOAT), 1) as RateWeight
FROM People WHERE People.RateCount > 0 ORDER BY People.DateAdded DESC
The result I'm getting is
PeopleID RateCount RateWeight
8548 674 1
135698 30 0
426755 2 0
336714 106 1
276739 43 0
536577 7 0
57674 81 0
79670 32 0
44674 901 1
146784 16 0
What I want is
PeopleID RateCount RateWeight
8548 674 1
135698 30 .30
426755 2 .02
336714 106 1
276739 43 .43
536577 7 .07
57674 81 .81
79670 32 .32
44674 901 1
146784 16 .16
Is there a better way of doing this?

When performing division, the data types of the numbers being divided control the resulting data type. To get a FLOAT or DECIMAL result, one of the numbers must already be FLOAT or DECIMAL, i.e.:
SELECT TOP 100 PeopleID,
RateCount,
IIF (People.RateCount < 100, People.RateCount/CAST(100 as FLOAT), 1) as RateWeight
FROM People
WHERE People.RateCount > 0
ORDER BY People.DateAdded DESC
Alternately, get rid of the CAST and just make the value 100 into 100.0
SELECT TOP 100 PeopleID,
RateCount,
IIF (People.RateCount < 100, People.RateCount/100.0, 1) as RateWeight
FROM People
WHERE People.RateCount > 0
ORDER BY People.DateAdded DESC

Related

proc sql statement to sum on values/rows that match a condition

I have a data table like below:
Table 1:
ROWID PERSONID YEAR pidDifference TIMETOEVENT DAYSBETVISIT
10 111 2009 . 100 .
110 120 2009 9 10 .
231 120 2009 0 20 10
222 120 2010 0 40 20
221 222 2009 102 10 30
321 222 2009 0 30 20
213 222 2009 0 10 20
432 321 2009 99 10 0
211 432 2009 111 20 10
212 432 2009 0 20 0
I want to sum over the DAYSBETVISIT column only when the pidDifference value is 0 for each PERSONID. So I wrote the following proc sql statement.
proc sql;
create table table5 as
(
select rowid, YEAR, PERSONID, pidDifference, TIMETOEVENT, DAYSBETVISIT,
SUM(CASE WHEN PIDDifference = 0 THEN DaysBetVisit ELSE 0 END)
from WORK.Table4_1
group by PERSONID,TIMETOEVENT, YEAR
);
quit;
However, the result I got was not summing the DAYSBETVISIT values in rows where PIDDifference = 0 within the same PERSONID. It just output the same value as was present in DAYSBETVISIT in that specific row.
Column that I NEED (sumdays) but don't get with above statement (showing the resultant column using above statement as OUT:
ROWID PERSONID YEAR pidDifference TIMETOEVENT DAYSBETVISIT sumdays OUT
10 111 2009 . 100 . 0 0
110 120 2009 9 10 . 0 0
231 120 2009 0 20 10 30 10
222 120 2010 0 40 20 30 20
221 222 2009 102 10 30 0 0
321 222 2009 0 30 20 40 20
213 222 2009 0 10 20 40 20
432 321 2009 99 10 0 0 0
211 432 2009 111 20 10 0 0
212 432 2009 0 20 0 0 0
I do not know what I am doing wrong.
I am using SAS EG Version 7.15, Base SAS version 9.4.
For your example data it looks like you just need to use two CASE statements. One to define which values to SUM() and another to define whether to report the SUM or not.
proc sql ;
select personid, piddifference, daysbetvisit, sumdays
, case when piddifference = 0
then sum(case when piddifference=0 then daysbetvisit else 0 end)
else 0 end as WANT
from expect
group by personid
;
quit;
Results
pid
PERSONID Difference DAYSBETVISIT sumdays WANT
--------------------------------------------------------
111 . . 0 0
120 0 10 30 30
120 0 20 30 30
120 9 . 0 0
222 0 20 40 40
222 0 20 40 40
222 102 30 0 0
321 99 0 0 0
432 0 0 0 0
432 111 10 0 0
SAS proc sql doesn't support window functions. I find the re-merging aggregations to be a bit difficult to use, except in the obvious cases. So, use a subquery or join and group by:
proc sql;
create table table5 as
select t.rowid, t.YEAR, t.PERSONID, t.pidDifference, t.TIMETOEVENT, t.DAYSBETVISIT,
tt.sum_DaysBetVisit
from WORK.Table4_1 t left join
(select personid, sum(DaysBetVisit) as sum_DaysBetVisit
from WORK.Table4_1
group by personid
having min(pidDifference) = max(pidDifference) and min(pidDifference) = 0
) tt
on tt.personid = t.personid;
Note: This doesn't handle NULL values for pidDifference. If that is a concern, you can add count(pidDifference) = count(*) to the having clause.

Calculate Sub Query Column Based On Calculated Column

I have a table ScheduleRotationDetail that contains these as columns:
ScheduleRotationID ScheduleID Ordinal Duration
379 61 1 1
379 379 2 20
379 512 3 1
379 89 4 20
I have a query that goes like this in order to get the day of the year each schedule is supposed to start on:
SELECT ScheduleID, Ordinal, Duration,
,Duration * 7 AS DurationDays
,( SELECT ( ISNULL( SUM(ISNULL( Duration, 0 )), 0 ) - 1 ) * 7
FROM ScheduleRotationDetail WHERE ScheduleRotationID = srd.ScheduleRotationID
AND Ordinal <= srd.Ordinal ) AS StartDay
FROM ScheduleRotationDetail srd
WHERE srd.ScheduleRotationID = 379
That outputs this as the result set:
ScheduleID Ordinal Duration DurationDays StartDay
61 1 1 7 0
379 2 20 140 140
512 3 1 7 147
89 4 20 140 287
Yet what I need the start day column values to be are:
0
7
147
154
I have tried CTEs but can't get it to work so I've come to here for advice.
It looks like you want a cumulative sum. In SQL Server 2012+, you can do:
SELECT ScheduleID, Ordinal, Duration,
SUM(Duration*7) OVER (ORDER BY Ordinal) - Duration*7 as StartDate
FROM ScheduleRotationDetail srd ;
In earlier versions, you can use APPLY for this purpose (or a correlated subquery).

How to increment a variable inside CASE WHEN clause?

I'm trying to make a new column with a variable that increments given a condition clause.
This is my query:
SELECT
[timestamp],
[load],
[timestamp] % 60 AS module,
group_by_column = CASE WHEN ([timestamp] % 60)= 0 then 1 else 0 end
FROM
table_01
And this is my return:
timestamp load module group_by_column
1432592618 24 38 0
1432592619 32 39 0
1432592620 21 40 0
1432592621 31 41 0
1432592622 28 42 0
1432592640 22 0 1
1432592641 31 1 0
1432592642 39 2 0
1432592643 33 3 0
1432592644 36 4 0
1432592649 32 9 0
1432592698 21 58 0
1432592700 25 0 1
1432592701 20 1 0
1432592702 27 2 0
1432592703 31 3 0
I need a table like this:
timestamp load module group_by_column
1432592618 24 38 0
1432592619 32 39 0
1432592620 21 40 0
1432592621 31 41 0
1432592622 28 42 0
1432592640 22 0 1
1432592641 31 1 1
1432592642 39 2 1
1432592643 33 3 1
1432592644 36 4 1
1432592649 32 9 1
1432592698 21 58 1
1432592700 25 0 2
1432592701 20 1 2
1432592702 27 2 2
1432592703 31 3 2
For Example, every time I found the condition [timestamp] % 60 = 0 is satisfied, I increment in the forth column.
I don't know if this is the best way to solve this problem, I just need an output as described below.
Thanks
In SQL Server 2012+, you would do a cumulative sum:
SELECT [timestamp], [load], [timestamp] % 60 AS module,
SUM(CASE WHEN [timestamp] % 60 = 0 THEN 1 ELSE 0 END) OVER
(ORDER BY timestamp) as group_by_column
FROM table_01;
In SQL Server 2008, I think you can get the same effect using dense_rank():
SELECT [timestamp], [load], [timestamp] % 60 AS module,
DENSE_RANK() OVER (ORDER BY [timestamp] / 60)
FROM table_01;
In case the counting integer should reflect the minutes that have passed since the first event, then the following will work:
SELECT [timestamp], [load], [timestamp] % 60 AS module,
([timestamp] / 60) - (SELECT min([timestamp]) / 60 FROM table_01) grp
FROM table_01;

Issue with Oracle select query 2

I have a table report of production, and I want to bridge between minus value and positive value on QTY field.
I want to make a new column with positive value, and another column with negative value selected from the QTY field.
mtl_trx qty uom
1 20 1230 KG
2 39 950 KG
3 45 100 LBR
4 91 250 KG
5 118 -500 KG
6 125 -284 KG
7 137 -120 KG
8 143 -80 KG
If I understand correctly, you want to select two columns, one showing the positiv values, one the negative ones? Use a case construct to decide whether to show a value or not.
select mtl_trx, qty, uom,
case when qty > 0 then qty end as qty_pos,
case when qty < 0 then qty end as qty_neg
from mytable;
select mtl_trx, qty, uom,
case when qty > 0 then qty else 0 end as positive,
case when qty < 0 then qty else 0 end as negative
from production;

SQL order by 100% not ordering first

I have a query that shows my counter's accuracy and I'm doing a simple order by accuracy. But, what is happening it is ordering correctly BUT 100% appears at the bottom and not in correct order. I have moved the order by, but I may be missing something?
QUERY:
select counted_by_user_id, total, defects, trunc((total-defects)/total*100,2)||'%' as accuracy from
(
select counted_by_user_id, sum(locations) as total, sum(numberOfDefectBins) as defects from
(
select counted_by_user_id, locations, numberOfDefectBins from
(
select trunc(ical.last_updated_date_utc) as CountDate,ip.process_name,ipl.icqa_process_id,ical.counted_by_user_id,count(*) as locations, (
SELECT COUNT(iid.icqa_ical_detail_id)
FROM icqa_process_locations ipl1, icqa_count_attempt_logs ical1, icqa_ical_details iid
WHERE ipl1.icqa_process_id = ipl.icqa_process_id
AND ical1.icqa_count_attempt_id = ipl1.icqa_count_attempt_id
AND ical1.counted_by_user_id = ical.counted_by_user_id
AND iid.icqa_count_attempt_log_id = ical1.icqa_count_attempt_log_id
AND iid.is_defective = 'Y' and trunc(ipl1.last_updated_date_utc) = trunc(sysdate)) as numberOfDefectBins
from icqa_count_attempt_logs ical left join icqa_process_locations ipl
on ical.icqa_count_attempt_id = ipl.icqa_count_attempt_id
left join ICQA_PROCESSES ip on ipl.icqa_process_id= ip.icqa_process_id
where trunc(ical.last_updated_date_utc) = trunc(sysdate)
AND ical.counted_by_user_id IS NOT NULL
group by trunc(ical.last_updated_date_utc), ip.process_name, ipl.icqa_process_id, ical.counted_by_user_id
order by ical.counted_by_user_id
))
group by counted_by_user_id
)
order by accuracy desc;
RESULT:
counted_by_user_id total defects accuracy
dggonza 346 1 99.71%
giermanc 225 1 99.55%
kylecoll 659 4 99.39%
manansal 71 1 98.59%
jssuarez 271 5 98.15%
jhheredi 464 10 97.84%
tabilinl 185 4 97.83%
darinc 102 3 97.05%
tostab 484 18 96.28%
alicmena 25 1 96%
reyesk 733 31 95.77%
genej 478 22 95.39%
yadirac 73 4 94.52%
lhherold 505 28 94.45%
anamarih 465 30 93.54%
pineiror 380 25 93.42%
nallelys 349 31 91.11%
almquij 112 12 89.28%
kustance 357 50 85.99%
arteagaa 54 12 77.77%
gardne 848 0 100%
willij 5 0 100%
castnera 21 0 100%
pbarbara 43 0 100%
caudilr 493 0 100%
jennifei 27 0 100%
Of course. Because you are sorting a string not a number.
There are multiple solutions:
order by length(accuracy) desc, accuracy;
is probably the easiest.
Some others:
order by cast(replace(accuracy, '%', '') as float);
order by (total-defects)/total;
order by (case when accuracy = '100%' then 1
when accuracy >= '10%' then 2
else 3
end), accuracy desc