Oracle ROUND HALF EVEN [closed] - oracle

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Is there any Oracle function to perform the ROUND HALF EVEN?
I've found this post MySQL round half however I couldn't make it work in Oracle
CREATE FUNCTION roundHalfEven (numberToRound IN NUMBER, roundPrecision IN NUMBER)
RETURN NUMBER
IS roundedNumber NUMBER;
BEGIN
DECLARE digitEvenOdd NUMBER;
DECLARE digitPosition NUMBER;
DECLARE digitToRound NUMBER;
DECLARE roundedNumber DECIMAL(20,6) DEFAULT 0;
SET digitPosition = INSTR(numberToRound, '.');
IF (roundingPrecision < 1) THEN
SET digitPosition = digitPosition + roundingPrecision;
ELSE
SET digitPosition = digitPosition + roundingPrecision + 1;
END IF;
IF (digitPosition > 0 AND digitPosition <= CHAR_LENGTH(numberToRound)) THEN
SET digitToRound = CAST(SUBSTR(numberToRound, digitPosition, 1) AS UNSIGNED);
SET digitPosition = digitPosition - 1;
IF (digitPosition > 0 AND digitPosition <= CHAR_LENGTH(numberToRound)) THEN
SET digitEvenOdd = CAST(SUBSTR(numberToRound, digitPosition, 1) AS UNSIGNED);
END IF;
END IF;
IF (digitToRound > -1) THEN
IF (digitToRound >= 5 AND digitEvenOdd IN (1,3,5,7,9)) THEN
SET roundedNumber = ROUND(numberToRound, roundingPrecision);
ELSE
SET roundedNumber = TRUNCATE(numberToRound, roundingPrecision);
END IF;
ELSE IF (roundingPrecision > 0) THEN
SET roundedNumber = numberToRound;
END IF;
RETURN(roundedNumber);
END;
/

SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test_data( value ) AS
SELECT (LEVEL -11)/2 FROM DUAL CONNECT BY LEVEL <= 21;
Query 1:
SELECT value,
ROUND( value ),
CASE
WHEN MOD( ABS( value ), 2 ) = 0.5
THEN TRUNC( value )
ELSE ROUND( value )
END AS round_half_even
FROM test_data
Results:
| VALUE | ROUND(VALUE) | ROUND_HALF_EVEN |
|-------|--------------|-----------------|
| -5 | -5 | -5 |
| -4.5 | -5 | -4 |
| -4 | -4 | -4 |
| -3.5 | -4 | -4 |
| -3 | -3 | -3 |
| -2.5 | -3 | -2 |
| -2 | -2 | -2 |
| -1.5 | -2 | -2 |
| -1 | -1 | -1 |
| -0.5 | -1 | 0 |
| 0 | 0 | 0 |
| 0.5 | 1 | 0 |
| 1 | 1 | 1 |
| 1.5 | 2 | 2 |
| 2 | 2 | 2 |
| 2.5 | 3 | 2 |
| 3 | 3 | 3 |
| 3.5 | 4 | 4 |
| 4 | 4 | 4 |
| 4.5 | 5 | 4 |
| 5 | 5 | 5 |
Or as a function:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test_data( value ) AS
SELECT (LEVEL -11)/20 FROM DUAL CONNECT BY LEVEL <= 21
/
CREATE FUNCTION round_half_even(
value NUMBER,
prec INTEGER DEFAULT 0
) RETURN NUMBER
IS
whole NUMBER := POWER( 10, -prec );
BEGIN
RETURN CASE
WHEN ABS( MOD( value, 2*whole ) ) = 0.5*whole
THEN TRUNC( value, prec )
ELSE ROUND( value, prec )
END;
END;
/
Query 1:
SELECT value,
ROUND( value , 1),
round_half_even( value, 1 )
FROM test_data
Results:
| VALUE | ROUND(VALUE,1) | ROUND_HALF_EVEN(VALUE,1) |
|-------|----------------|--------------------------|
| -0.5 | -0.5 | -0.5 |
| -0.45 | -0.5 | -0.4 |
| -0.4 | -0.4 | -0.4 |
| -0.35 | -0.4 | -0.4 |
| -0.3 | -0.3 | -0.3 |
| -0.25 | -0.3 | -0.2 |
| -0.2 | -0.2 | -0.2 |
| -0.15 | -0.2 | -0.2 |
| -0.1 | -0.1 | -0.1 |
| -0.05 | -0.1 | 0 |
| 0 | 0 | 0 |
| 0.05 | 0.1 | 0 |
| 0.1 | 0.1 | 0.1 |
| 0.15 | 0.2 | 0.2 |
| 0.2 | 0.2 | 0.2 |
| 0.25 | 0.3 | 0.2 |
| 0.3 | 0.3 | 0.3 |
| 0.35 | 0.4 | 0.4 |
| 0.4 | 0.4 | 0.4 |
| 0.45 | 0.5 | 0.4 |
| 0.5 | 0.5 | 0.5 |

Related

Laravel leftJoin returns null from 2nd table

I have 2 table duty_sheets
centerId | centerName | p1 | p2 | p3 | p4 | ...p22 | examiId
1 | xyz | 1 | 5 | 8 | 7 | 1 | 1
2 | abc | 9 | 1 | 6 | 6 | 1 | 1
and feedback
id | centerId | inspectorId | A | B | C | examiId
1 | 1 | 1 | 1 | 5 | 8 | 1
2 | 2 | 9 | 9 | 1 | 6 | 1
here is my code
$center = DutySheet::select('duty_sheets.centerId', 'duty_sheets.centerName','feedback.id')
->leftJoin('feedback', function ($leftJoin) {
$leftJoin->on('duty_sheets.examId', 'feedback.examId')
->where("duty_sheets.centerId", 'feedback.centerId')
->where("feedback.inspectorId", 1);
})
->where("duty_sheets.examId", 1)
->where("p20", 1)
->get();
dd($center);
to retrieve "All rows from DutySheet where p20 = 1 and dutysheet.examId = 1, and relevant rows from feedback depend on centerId, inspectorId and examId.
The problem is that the query return feedback.id as null while the record exist in feedback table with the ids.
Laravel version = 9
The problem is in left Join
->where("duty_sheets.centerId", 'feedback.centerId')
This build a where against the value 'feedback.centerId'
duty_sheets.centerId='feedback.centerId'
You need use
->on("duty_sheets.centerId",'=', 'feedback.centerId')
Or
->whereColumn("duty_sheets.centerId", 'feedback.centerId')

Subtract value row by row in matlab

I have a 1 column matrix with the following values:
*-------*
| 6 |
| 4 |
| 3 |
| 1 |
| 1 |
*-------*
With this function, starting from the first value, I subtract the value in the following row and place 0 at the end. This is the result:
Delta = Ctv_ds_universal(1:(end-1),1)-Ctv_ds_universal(2:end,1);
Delta(end+1)=0;
*-----------*
| 2 (6-4) |
| 1 (4-3) |
| 2 (3-1) |
| 0 (1-1) |
| 0 |
*-----------*
Now, I would like to reverse the order and start subtracting from down to the top, placing 0 at the beginning. How can I modify the function?
*------------*
| 0 |
| -2 (4-6) |
| -1 (3-4) |
| -2 (1-3) |
| 0 (1-1) |
*------------*
Delta = 0;
Delta = [Delta; Ctv_ds_universal(2:end,1)-Ctv_ds_universal(1:end-1,1)];

SQL difference between different columns from different rows

Lets say i have a table as follows:
| id | dir | p1 | p2 |
|----------------------|
| a | x | 1.2 | 1.3 |
| a | x | 1.2 | 1.3 |
| a | z | 2.1 | 3 |
| a | z | 2.1 | 3 |
| b | x | 1 | null|
| b | z | 4 | null|
I would like to have unique rows of row a and b where dir = x and dir = z. So two rows each.
Then when dir = z. Take the value in p1 - (p2 of the previous row for that id) as newval1 and the value in p2 - (p1 of the previous row for that id) as new val2.
Treating nulls as zeroes.
In steps I suppose it will be:
| id | dir | p1 | p2 |
|----------------------|
| a | x | 1.2 | 1.3 |
| a | z | 2.1 | 3 |
| b | x | 1 | null|
| b | z | 4 | null|
Desired result will be:
| id | newval1 | newval2 |
|--------------------------------|
| a | 0.8(2.1-1.3) | 1.8(3-1.2 |
| b | 4 (4-0) | -1(0-1) |
Is it possible to do this in SQL?
select id,
nvl(max(case when dir = 'z' then p1 end), 0)
- nvl(max(case when dir = 'x' then p2 end), 0) as newval1,
nvl(max(case when dir = 'z' then p2 end), 0)
- nvl(max(case when dir = 'x' then p1 end), 0) as newval2
from tbl
where dir in ('x', 'z')
group by id
;
ID NEWVAL1 NEWVAL2
-- ---------- ----------
a .8 1.8
b 4 -1
Or, if you are on version 11.1 or higher, you can use the pivot operator:
select id, z_p1 - x_p2 as newval1, z_p2 - x_p1 as newval2
from tbl
pivot ( max(nvl(p1, 0)) as p1, max(nvl(p2, 0)) as p2
for dir in ('x' as x, 'z' as z)
)
;

Recursive Oracle query to calculate two values that depends on each other

I have this table with materials stock data:
Date(MM/DD) |received_qty| returned_qty | used_qty
01/01 | 5000 | 0 | 3500
01/02 | 0 | 0 | 1500
01/03 | 7500 | 0 | 1250
01/04 | 0 | 0 | 0
I need to add two more columns to calculate the "start quantity" and the "daily stock", assuming this:
"start quantity" is zero in the first day, after that is "daily
stock" from the previous day.
"daily stock" is "start quantity" + received_qty - returned_qty - used_qty
As you can see, each value depend on each other...
So, the data would like this after adding these two columns:
Date(MM/DD) |Start_qty |received_qty| returned_qty | used_qty | daily_stock
01/01 | 0 | 5000 | 0 | 3500 | 1500
01/02 | 1500 | 0 | 0 | 1500 | 0
01/03 | 0 | 7500 | 0 | 1250 | 6250
01/04 | 6250 | 0 | 0 | 0 | 6250
I'm sure these columns can be generated using recursives queries with start with and connect by clauses present in Oracle, but I'm struggled with the script...
Try this query
Select t.*,
Coalesce(
Sum( "received_qty" - "returned_qty" - "used_qty" )
Over ( order by "Date" ) ,
0) as daily_stock,
Coalesce(
Sum( "received_qty" - "returned_qty" - "used_qty" )
Over ( order by "Date"
Rows between unbounded preceding
And 1 preceding ),
0) as start_quantity
from table1 t
Demo http://sqlfiddle.com/#!4/94417/13
| Date | received_qty | returned_qty | used_qty | DAILY_STOCK | START_QUANTITY |
|-----------------------|--------------|--------------|----------|-------------|----------------|
| 2001-01-01 00:00:00.0 | 5000 | 0 | 3500 | 1500 | 0 |
| 2001-01-02 00:00:00.0 | 0 | 0 | 1500 | 0 | 1500 |
| 2001-01-03 00:00:00.0 | 7500 | 0 | 1250 | 6250 | 0 |
| 2001-01-04 00:00:00.0 | 0 | 0 | 0 | 6250 | 6250 |

Is it possible to do a 'normalized' dense_rank() in hive?

I have a consumer table like so.
consumer | product | quantity
-------- | ------- | --------
a | x | 3
a | y | 4
a | z | 1
b | x | 3
b | y | 5
c | x | 4
What I want is a 'normalized' rank assigned to each consumer so that I can split the table easily for testing and training. I used the dense_rank() in hive, so I got the below table.
rank | consumer | product | quantity
---- | -------- | ------- | --------
1 | a | x | 3
1 | a | y | 4
1 | a | z | 1
2 | b | x | 3
2 | b | y | 5
3 | c | x | 4
This is well and good, but I want to scale this to use with any number of consumers, so I would ideally like the range of ranks between 0 and 1, like so.
rank | consumer | product | quantity
---- | -------- | ------- | --------
0.33 | a | x | 3
0.33 | a | y | 4
0.33 | a | z | 1
0.67 | b | x | 3
0.67 | b | y | 5
1 | c | x | 4
This way, I'd always know what the range of ranks is, and can split the data in a standard way (rank <= 0.7 training, and rank > 0.7 testing)
Is there a way to achieve this in hive?
Or, is there a different and better approach to my original issue of splitting the data?
I tried to do a select * where rank < 0.7*max(rank), but hive says the MAX UDAF is not yet available in where clause.
percent_rank
select percent_rank() over (order by consumer) as pr
,*
from mytable
;
+-----+----------+---------+----------+
| pr | consumer | product | quantity |
+-----+----------+---------+----------+
| 0.0 | a | z | 1 |
| 0.0 | a | y | 4 |
| 0.0 | a | x | 3 |
| 0.6 | b | y | 5 |
| 0.6 | b | x | 3 |
| 1.0 | c | x | 4 |
+-----+----------+---------+----------+
For filtering you'll need a sub-query / CTE
select *
from (select percent_rank() over (order by consumer) as pr
,*
from mytable
) t
where pr <= ...
;

Resources