SQL Server : how to map decimals to corrected values - sql-server

I have a situation where I get trip data from another company. The other company measures fuel with a precision of ⅛ gallon.
I get data from the other company and store it in my SQL Server table. The aggregated fuel amounts aren't right. I discovered that while the other company stores fuel in 1/8 gallons, it was sending me only one decimal place.
Furthermore, thanks to this post, I've determined that the company isn't rounding the values to the nearest tenth but is instead truncating them.
Query:
/** Fuel Fractions **/
SELECT DISTINCT ([TotalFuelUsed] % 1) AS [TotalFuelUsedDecimals]
FROM [Raw]
ORDER BY [TotalFuelUsedDecimals]
Results:
TotalFuelUsedDecimals
0.00
0.10
0.20
0.30
0.50
0.60
0.70
0.80
What I'd like is an efficient way to add a corrected fuel column to my views which would map as follows:
0.00 → 0.000
0.10 → 0.125
0.20 → 0.250
0.30 → 0.375
0.50 → 0.500
0.60 → 0.625
0.70 → 0.750
0.80 → 0.875
1.80 → 1.875
and so on
I'm new to SQL so please be kind.
Server is running Microsoft SQL Server 2008. But if you know a way better function only supported by newer SQL Server, please post it too because we may upgrade someday soon and it may help others.
Also, if it makes any difference, there are several different fuel columns in the table that I'll be correcting.

While writing up the question, I tried the following method using a temp table and multiple joins which seemed to work. I expect there are better solutions out there to be had.
CREATE TABLE #TempMap
([from] decimal(18,2), [to] decimal(18,3))
;
INSERT INTO #TempMap
([from], [to])
VALUES
(0.0, 0.000),
(0.1, 0.125),
(0.2, 0.250),
(0.3, 0.375),
(0.5, 0.500),
(0.6, 0.625),
(0.7, 0.750),
(0.8, 0.875)
;
SELECT [TotalFuelUsed]
,[TotalFuelCorrect].[to] + ROUND([TotalFuelUsed], 0, 1) AS [TotalFuelUsedCorrected]
,[IdleFuelUsed]
,[IdleFuelCorrect].[to] + ROUND([IdleFuelUsed], 0, 1) AS [IdleFuelUsedCorrected]
FROM [Raw]
JOIN [#TempMap] AS [TotalFuelCorrect] ON [TotalFuelUsed] % 1 = [TotalFuelCorrect].[from]
JOIN [#TempMap] AS [IdleFuelCorrect] ON [IdleFuelUsed] % 1 = [IdleFuelCorrect].[from]
ORDER BY [TotalFuelUsed] DESC
DROP TABLE #TempMap;

Try adding a column as:
select ....
, case when right(cast([TotalFuelUsed] as decimal(12,1)), 1) = 1 then [TotalFuelUsed] + 0.025
when right(cast([TotalFuelUsed] as decimal(12,1)), 1) = 2 then [TotalFuelUsed] + 0.05
when right(cast([TotalFuelUsed] as decimal(12,1)), 1) = 3 then [TotalFuelUsed] + 0.075
when right(cast([TotalFuelUsed] as decimal(12,1)), 1) = 6 then [TotalFuelUsed] + 0.025
when right(cast([TotalFuelUsed] as decimal(12,1)), 1) = 7 then [TotalFuelUsed] + 0.05
when right(cast([TotalFuelUsed] as decimal(12,1)), 1) = 8 then [TotalFuelUsed] + 0.075
else [TotalFuelUsed] end as updatedTotalFuelUsed

Related

SQL- Using lead with group by to get closest value for a group

I would like to use the Lead function to get the closest value for a group
Below is some sample data from flx_alps_boundaries
Subject code
Grade
Score
20-BD-AC-AL
1
1.12
20-BD-AC-AL
2
1.03
20-BD-AC-AL
3
0.97
20-BD-AC-AL
4
0.92
20-BD-AC-AL
5
0.86
20-BD-AC-AL
6
0.84
20-BD-AH-AL
1
1.15
20-BD-AH-AL
2
1.10
20-BD-AH-AL
3
1.05
20-BD-AH-AL
4
1.00
20-BD-AH-AL
5
0.98
20-BD-AH-AL
6
0.96
I am calculating the score for a subject using a formula and getting the grade for the nearest matching score from the above table . eg if score is 0.95 for subject 20-BD-AC-AL the grade should be 4
This is my current sql
select top 1
ab.alps_grade as alps_grade,
round( sum (actual_alps_points - expected_alps_points)
/ (count(reference) * 100) + 1,2 ) as alps_score
from alps_cte
inner join [flx_alps_boundaries] ab
on alps_cte.course = ab.course_code
where ab.course_code in ('20-BD-AC-AL','20-BD-AH-AL')
group by course,ab.alps_grade,ab.alps_score
order by abs(round(sum(actual_alps_points
- expected_alps_points)
/ (count(reference)*100) + 1, 2)
- ab.alps_score)
This query only returns one row. How do I use LEAD to get the appropriate grade for each
subject's score?

Alternative for PSM package

Anyone could suggest an alternative for PSM package in R for parametric survival model since this package has been removed?
psm() is a function within the rms package; can you clarify which psm package do you mean?
the PSM package is here: https://rdrr.io/cran/PSM/
You can reproduce the results of the paper with the following codes:
Zhang Z. Parametric regression modelfor survival data: Weibull
regression model as an example. Ann Transl Med 2016;4(24):484. doi:
10.21037/atm.2016.08.45
> install.packages("rms")
> library(rms)
> library(survival)
> data(lung)
> psm.lung<-psm(Surv(time, status)~ph.ecog+sex*age+
+ ph.karno+pat.karno+meal.cal+
+ wt.loss,lung, dist='weibull')
> anova(psm.lung)
Wald Statistics Response: Surv(time, status)
Factor Chi-Square d.f. P
ph.ecog 13.86 1 0.0002
sex (Factor+Higher Order Factors) 10.24 2 0.0060
All Interactions 3.22 1 0.0728
age (Factor+Higher Order Factors) 3.75 2 0.1532
All Interactions 3.22 1 0.0728
ph.karno 5.86 1 0.0155
pat.karno 3.54 1 0.0601
meal.cal 0.00 1 0.9439
wt.loss 3.85 1 0.0498
sex * age (Factor+Higher Order Factors) 3.22 1 0.0728
TOTAL 33.18 8 0.0001

Adverse Events table in SAS

I have the following SAS data set:
Subject AETERM1 AETERM2 TREATMENT
001 Illness Fever 0
001 Illness Cold 0
002 Cardiac AFIB 1
003 Cardiac AFLUT 1
I would like to create a table like this in SAS:
___________________________________________________________________________________________________
AETERM1
AETERM2 TREATMENT = 0 (N = 1) TREATMENT = 1 (N = 2) OVERALL (N = 3)
__________________________________________________________________________________________________
Any Event 1 (100%) 2 (100%) 3 (100%)
Illness 1 (100%) 1 (33%)
Fever 1 (100%) 1 (33%)
Cold 1 (100%) 1 (33%)
Cardiac 2 (100%) 2 (67%)
AFIB 1 (50%) 1 (33%)
AFLUT 1 (50%) 1 (33%)
I'm able to generate something close with the following PROC FREQ statement:
proc freq data = have order = freq;
table aeterm1 * aeterm2 / missing;
run;
You could actually use
proc freq data = have order = freq;
table aeterm1 * aeterm2 * treatment / out = results;
run;
and process the results dataset to get the view you want

Count total balls from cricket overs and sum overs (mssql)

I'm creating a stored procedure in SQL Server for a cricket application. How can I find the total number of balls, given there are 6 balls in an over.
Suppose there are 4 overs. We can easily calculate 4 * 6. But what if there were 4.5 overs? I also want to sum the two different cricket matches over of a particular bowler over.
For example:
match1 overs 4.5
match2 overs 6.3
addition should be 11.2
With a calculator we get 10.8
Here is what I tried
COALESCE(Sum(Overs),0) * 6 + (COALESCE(Sum(Overs),0) - COALESCE(Sum(Overs),0))* 10 as Totalballs,
Based on your last comment, we can first FLOOR the over to find what the first multiple will be.
Then we subtract the over from that, convert to INT, and add.
declare #over decimal(4,1) = 4.5
select
SixeTimesThis = floor(#over)
,Remainder = (#over - floor(#over))
,RemainderAsInt = cast(replace((#over - floor(#over)),'.','') as int)
,FinalResult = floor(#over) * 6 +cast(replace((#over - floor(#over)),'.','') as int)
You can use modulus % to get the extra balls.
Example snippet:
select *, coalesce(floor(Overs)*6 + floor((Overs%1)*10), 0) as Balls
from (values
(1.0),
(4.0),
(4.5),
(null)
) as v(Overs);
Test on db<>fiddle here
Result:
Overs Balls
----- -----
1.0 6
4.0 24
4.5 29
NULL 0

Selecting the row before and after the value changes in one column and correlate with the change in value in next column

I have the following problem that I am trying to solve using SQL server 2008.
The table has 4 columns
1- Identifier such as (a,a,a,b,b,c,c)
2- Time (in seconds)
3- Value 1 (integer)
4- Value 2 (Float)
When sorted by time for each identifier the Value 1 is repeated for several rows. Once the Value 1 changes there is a corresponding change in Value 2 after several rows (ranging between 1 and 5+ seconds).
1- Detect when the Value 1 changes and correspond it to when Value 2 changes
2- Difference in seconds between Value 1 changes.
I cannot use Partition by because there are recurring values for Value 1 and Value 2.
Identifier TimeStamp Value1 Value2
a 12:10:01 2 0.98
a 12:10:02 2 0.98
a 12:10:03 3 0.98
a 12:10:05 2 0.98
a 12:10:06 3 0.50
a 12:10:09 2 0.98
a 12:10:12 2 0.50
a 12:10:13 2 0.98
b 12:10:10 2 0.98
b 12:10:11 4 0.98
b 12:10:12 5 0.98
b 12:10:12 5 0.80
b 12:10:12 5 1.20
I have been trying the following query but it is taking too long to run. For every change in Value1 there is a corresponding change in Value2. The change in value 2 can happen any time over the period of several seconds. I cannot figure out a way to correlate the two changes.
;WITH Value1Change AS (
SELECT
ROW_NUMBER () OVER (ORDER BY TimeStamp) AS [RNum]
,Identifier
,T1.[TimeStamp] AS [T1 TimeStamp]
,T2.[TimeStamp] AS [T2 TimeStamp]
,T1.[Value1] AS [T1_Value 1]
,T2.[Value2] AS [T2_Value 1]
FROM Table T1
INNER JOIN Table T2 ON T1.[Identifier]=T2.[Identifier] AND T1.RNum=T2.RNum+1
WHERE T2.[Value1]<>T1.[Value1]
)
SELECT
VC1.Identifier
,VC1.[T2 TimeStamp]
,VC2.[T2 TimeStamp]
,DATEDIFF(S,VC1.[T2 TimeStamp],VC2.[T2 TimeStamp]) AS [Time Between Change]
,VC1.[T1_Value 1]
,VC1.[T2_Value 1]
FROM ValueChange VC1
INNER JOIN ValueChange VC2 ON VC1.Unit=VC2.Unit AND VC1.RNum=VC2.RNum+1
ORDER BY VC1.RNum

Resources