Related
I would like to distribute a set of data into a table shown below:
RANGE(days) No of days. Amount
0-30 - 0
31-180 1 4,185.78
181-365 2 74,056.86
366 and above 6 587,198.35
TOTAL 9 665,440.99
SOURCE Data
S/N START DATE Details Tran Amt END DATE
1 22/05/2015 A 448,749.14 30/06/2018
2 22/09/2015 B 4,883.02 30/06/2018
3 04/11/2015 C 45,646.27 30/06/2018
4 26/04/2016 D 42,861.99 30/06/2018
5 16/06/2016 E 23,144.23 30/06/2018
6 27/07/2016 F 21,913.70 30/06/2018
7 11/08/2017 G 61,396.94 30/06/2018
8 30/11/2017 H 12,659.92 30/06/2018
9 19/03/2018 I 4,185.78 30/06/2018
TOTAL 665,440.99
Thanks
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE data ( SN, START_DATE, Details, TranAmt ) AS
SELECT 1, DATE '2015-05-22', 'A', 448749.14 FROM DUAL UNION ALL
SELECT 2, DATE '2015-09-22', 'B', 4883.02 FROM DUAL UNION ALL
SELECT 3, DATE '2015-11-04', 'C', 45646.27 FROM DUAL UNION ALL
SELECT 4, DATE '2016-04-26', 'D', 42861.99 FROM DUAL UNION ALL
SELECT 5, DATE '2016-06-16', 'E', 23144.23 FROM DUAL UNION ALL
SELECT 6, DATE '2016-07-27', 'F', 21913.70 FROM DUAL UNION ALL
SELECT 7, DATE '2017-08-11', 'G', 61396.94 FROM DUAL UNION ALL
SELECT 8, DATE '2017-11-30', 'H', 12659.92 FROM DUAL UNION ALL
SELECT 9, DATE '2018-03-19', 'I', 4185.78 FROM DUAL;
Query 1:
WITH end_date ( end_date ) AS (
SELECT DATE '2018-06-30' FROM DUAL
),
ranges ( first, last ) AS (
SELECT 0, 30 FROM DUAL UNION ALL
SELECT 31, 180 FROM DUAL UNION ALL
SELECT 181, 365 FROM DUAL UNION ALL
SELECT 366, NULL FROM DUAL
)
SELECT NVL2(
r.first,
r.first || NVL2(
MAX( r.last ),
' - ' || MAX( r.last ),
' and above'
),
'Total'
) AS range,
COUNT( d.sn ) AS "No of days",
COALESCE( SUM( d.TranAmt ), 0 ) AS Amount
FROM data d
CROSS JOIN end_date e
RIGHT OUTER JOIN ranges r
ON ( d.start_date < e.end_date + 1 - r.first
AND ( r.last IS NULL
OR d.start_date >= e.end_date - r.last ) )
GROUP BY ROLLUP( r.first )
ORDER BY r.first
Results:
| RANGE | No of days | AMOUNT |
|---------------|------------|-----------|
| 0 - 30 | 0 | 0 |
| 31 - 180 | 1 | 4185.78 |
| 181 - 365 | 2 | 74056.86 |
| 366 and above | 6 | 587198.35 |
| Total | 9 | 665440.99 |
I am creating a function that returns a table type object based on the split of the chain, the query is the following:
WITH COLUMNA AS (
SELECT ROWNUM COL_ID, REGEXP_SUBSTR ('A,B,C:D,E,F:','[^:]+',1,LEVEL) COL FROM DUAL
CONNECT BY REGEXP_SUBSTR ('A,B,C:D,E,F:','[^:]+',1,LEVEL) IS NOT NULL
ORDER BY COL_ID
)
SELECT * FROM (SELECT COL_ID, ROWNUM FIL_ID, SUBSTR(COL, INSTR(COL, ',', 1, LVL) + 1, INSTR(COL, ',', 1, LVL + 1) - INSTR(COL, ',', 1, LVL) - 1) NAME
FROM
( SELECT ',' || COL || ',' AS COL, COL_ID FROM COLUMNA ),
( SELECT LEVEL AS LVL FROM DUAL CONNECT BY LEVEL <= 100 )
WHERE LVL <= LENGTH(COL) - LENGTH(REPLACE(COL, ',')) - 1
ORDER BY COL_ID, NAME
) FILA
The result is as follows:
COL_ID FIL_ID NAME
1 1 A
1 2 B
1 3 C
2 4 D
2 5 E
2 6 F
And I Need To Get The Following Result
COL_ID VAL1 VAL2 VAL3 VALN
1 A B C X
2 D E F Y
I hope your valuable help!!!
You need to have a fixed number of columns in your object:
CREATE TYPE values_obj AS OBJECT(
COL_id INTEGER,
VAL1 VARCHAR2(10),
VAL2 VARCHAR2(10),
VAL3 VARCHAR2(10),
VAL4 VARCHAR2(10),
VAL5 VARCHAR2(10)
)
/
CREATE TYPE values_tab AS TABLE OF values_obj
/
CREATE OR REPLACE FUNCTION split_values(
in_list VARCHAR2
) RETURN values_tab
IS
vals VALUES_TAB;
BEGIN
SELECT values_obj(
LEVEL,
REGEXP_SUBSTR( in_list, '([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*).*?(:|$)', 1, LEVEL, NULL, 1 ),
REGEXP_SUBSTR( in_list, '([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*).*?(:|$)', 1, LEVEL, NULL, 2 ),
REGEXP_SUBSTR( in_list, '([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*).*?(:|$)', 1, LEVEL, NULL, 3 ),
REGEXP_SUBSTR( in_list, '([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*).*?(:|$)', 1, LEVEL, NULL, 4 ),
REGEXP_SUBSTR( in_list, '([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*).*?(:|$)', 1, LEVEL, NULL, 5 )
)
BULK COLLECT INTO vals
FROM DUAL
CONNECT BY LEVEL < REGEXP_COUNT( in_list, '([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*),?([^:,]*).*?(:|$)' );
RETURN vals;
END;
/
Then you can do:
SELECT *
FROM TABLE( split_values( 'A,B,C:D,E,F,G:H,I,J,K,L,M::N' ) );
Which outputs:
COL_ID VAL1 VAL2 VAL3 VAL4 VAL5
------ ---- ---- ---- ---- ----
1 A B C - -
2 D E F G -
3 H I J K L
4 - - - - -
5 N - - - -
I have a small requirement.How to get the following output:
Input string is 123456
I need to find the reverse position,starting from 2,i.e 234567.
Now multiply each value with the reverse position value and add.
eg:1*7+2*6+3*5+4*4+5*3+6*2 in plsql.
SQL Fiddle
Query 1:
WITH data ( value, total ) AS (
SELECT 123456, 0 FROM DUAL
UNION ALL
SELECT TO_NUMBER( SUBSTR( value, 2 ) ),
total + SUBSTR( value, 1, 1 ) * ( 1 + LENGTH( value ) )
FROM data
WHERE value IS NOT NULL
)
SELECT total FROM data WHERE value IS NULL
Results:
| TOTAL |
|-------|
| 77 |
I've source data Like this
Childid | Parent ID
------- | ---------
1 | NULL
2 | 1
3 | 1
4 | 2
5 | 4
6 | 5
7 | 6
I need an oracle query to show the out put like this.
Child | L1Parent | l2Parent | L3Parent | L4Parent | L5Parent
----- | -------- | -------- | -------- | -------- | --------
1 | NULL
2 | 1
3 | 1
4 | 1 | 2
5 | 1 | 2 | 4
6 | 1 | 2 | 4 | 5
7 | 1 | 2 | 4 | 5 | 6
This seems to me easier:
SELECT childId,
trim(SYS_CONNECT_BY_PATH(decode(level,2,parentId,''), ' ')) AS L1,
trim(SYS_CONNECT_BY_PATH(decode(level,3,parentId,''), ' ')) AS L2,
trim(SYS_CONNECT_BY_PATH(decode(level,4,parentId,''), ' ')) AS L3,
trim(SYS_CONNECT_BY_PATH(decode(level,5,parentId,''), ' ')) AS L4,
trim(SYS_CONNECT_BY_PATH(decode(level,6,parentId,''), ' ')) AS L5,
trim(SYS_CONNECT_BY_PATH(decode(level,7,parentId,''), ' ')) AS L6,
trim(SYS_CONNECT_BY_PATH(decode(level,8,parentId,''), ' ')) AS L7
FROM table_name
START WITH parentId is null
CONNECT BY PRIOR childId = parentId;
Oracle Setup:
CREATE TABLE table_name ( childId, parentId ) AS
SELECT 1, NULL FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 1 FROM DUAL UNION ALL
SELECT 4, 2 FROM DUAL UNION ALL
SELECT 5, 4 FROM DUAL UNION ALL
SELECT 6, 5 FROM DUAL UNION ALL
SELECT 7, 6 FROM DUAL;
Query:
SELECT childId,
CASE WHEN p02 = 1 THEN NULL WHEN p03 = 1 THEN SUBSTR( path, p02 ) ELSE SUBSTR( path, p02, p03 - p02 - 1 ) END AS Lp1,
CASE WHEN p03 = 1 THEN NULL WHEN p04 = 1 THEN SUBSTR( path, p03 ) ELSE SUBSTR( path, p03, p04 - p03 - 1 ) END AS lp2,
CASE WHEN p04 = 1 THEN NULL WHEN p05 = 1 THEN SUBSTR( path, p04 ) ELSE SUBSTR( path, p04, p05 - p04 - 1 ) END AS lp3,
CASE WHEN p05 = 1 THEN NULL WHEN p06 = 1 THEN SUBSTR( path, p05 ) ELSE SUBSTR( path, p05, p06 - p05 - 1 ) END AS lp4,
CASE WHEN p06 = 1 THEN NULL WHEN p07 = 1 THEN SUBSTR( path, p06 ) ELSE SUBSTR( path, p06, p07 - p06 - 1 ) END AS lp5,
CASE WHEN p07 = 1 THEN NULL WHEN p08 = 1 THEN SUBSTR( path, p07 ) ELSE SUBSTR( path, p07, p08 - p07 - 1 ) END AS lp6
FROM (
SELECT childId,
path,
INSTR( path, '/', 1, 2 ) + 1 AS p02,
INSTR( path, '/', 1, 3 ) + 1 AS p03,
INSTR( path, '/', 1, 4 ) + 1 AS p04,
INSTR( path, '/', 1, 5 ) + 1 AS p05,
INSTR( path, '/', 1, 6 ) + 1 AS p06,
INSTR( path, '/', 1, 7 ) + 1 AS p07,
INSTR( path, '/', 1, 8 ) + 1 AS p08
FROM (
SELECT childId,
SYS_CONNECT_BY_PATH( parentId, '/') AS path
FROM table_name
START WITH parentId IS NULL
CONNECT BY PRIOR childId = parentId
)
);
Output:
CHILDID LP1 LP2 LP3 LP4 LP5 LP6
---------- --- --- --- --- --- ---
1
2 1
4 1 2
5 1 2 4
6 1 2 4 5
7 1 2 4 5 6
3 1
Query 2 - Regular Expressions:
SELECT childId,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 2, NULL, 1 ) ) AS lp1,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 3, NULL, 1 ) ) AS lp2,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 4, NULL, 1 ) ) AS lp3,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 5, NULL, 1 ) ) AS lp4,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 6, NULL, 1 ) ) AS lp5,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 7, NULL, 1 ) ) AS lp6,
TO_NUMBER( REGEXP_SUBSTR( path, '/([^/]*)', 1, 8, NULL, 1 ) ) AS lp7
FROM (
SELECT childId,
SYS_CONNECT_BY_PATH( parentId, '/') AS path
FROM table_name
START WITH parentId IS NULL
CONNECT BY PRIOR childId = parentId
);
I need to convert ISBN from 10 digits to 13 digits. I tried but not getting correct result.This is the code that I have tried and its not giving correct result.
Create or replace FUNCTION F_ISBN_CONV_13 (ISBN_10 IN VARCHAR2) RETURN VARCHAR2
AS
V_ISBN_13 VARCHAR2(13);
BEGIN
SELECT
CASE WHEN LENGTH(ISBN_10) = 10 THEN
CASE WHEN SUBSTR(ISBN_10,1,3) = '801' THEN
'201' ||
SUBSTR(ISBN_10,1,9) ||
SUBSTR(
(
10 -
SUBSTR(
(
(
2 +
1 +
SUBSTR(ISBN_10,2,1) +
SUBSTR(ISBN_10,4,1) +
SUBSTR(ISBN_10,6,1) +
SUBSTR(ISBN_10,8,1)
) +
(
(
0 +
SUBSTR(ISBN_10,1,1) +
SUBSTR(ISBN_10,3,1) +
SUBSTR(ISBN_10,5,1) +
SUBSTR(ISBN_10,7,1) +
SUBSTR(ISBN_10,9,1)
)
) * 3
)
,-1
,1
)
)
,-1
,1
)
ELSE
'978' ||
SUBSTR(ISBN_10,1,9) ||
SUBSTR(
(
10-
SUBSTR(
(
(
9 +
8 +
SUBSTR(ISBN_10,2,1) +
SUBSTR(ISBN_10,4,1) +
SUBSTR(ISBN_10,6,1) +
SUBSTR(ISBN_10,8,1)
) +
(
(
7 +
SUBSTR(ISBN_10,1,1) +
SUBSTR(ISBN_10,3,1) +
SUBSTR(ISBN_10,5,1) +
SUBSTR(ISBN_10,7,1) +
SUBSTR(ISBN_10,9,1)
)
) * 3
)
,1
,1
)
)
,-1
,1
)
END
ELSE
ISBN_10
END INTO V_ISBN_13
FROM
DUAL;
RETURN V_ISBN_13;
EXCEPTION
--< code >
END F_ISBN_CONV_13;
I think the following code should be self-explanatory. For details see the Wikipedia links.
-- https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_to_ISBN-13_conversion
create or replace function isbn10_to_13(p_isbn10 in varchar2)
return varchar2 is
v_isbn10_digits constant varchar2(9) := substr(replace(p_isbn10, '-', ''), 1, 9);
v_isbn13 varchar2(17) := '978-' || substr(p_isbn10, 1, length(p_isbn10) - 1);
v_checkdigit number;
begin
-- https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-13_check_digit_calculation
v_checkdigit :=
(1 * 9)
+ (3 * 7)
+ (1 * 8)
+ (3 * to_number(substr(v_isbn10_digits, 1, 1)))
+ (1 * to_number(substr(v_isbn10_digits, 2, 1)))
+ (3 * to_number(substr(v_isbn10_digits, 3, 1)))
+ (1 * to_number(substr(v_isbn10_digits, 4, 1)))
+ (3 * to_number(substr(v_isbn10_digits, 5, 1)))
+ (1 * to_number(substr(v_isbn10_digits, 6, 1)))
+ (3 * to_number(substr(v_isbn10_digits, 7, 1)))
+ (1 * to_number(substr(v_isbn10_digits, 8, 1)))
+ (3 * to_number(substr(v_isbn10_digits, 9, 1)))
;
v_checkdigit := 10 - mod(v_checkdigit, 10);
if v_checkdigit = 10
then
v_checkdigit := 0;
end if;
return v_isbn13 || v_checkdigit;
end;
/
Example
col isbn10 for a13
col isbn13 for a17
with isbn10(i10) as (
select '0-30-640615-x' from dual union all
select '0-07-223065-7' from dual union all
select '0-596-51446-x' from dual
)
select isbn10.i10 as isbn10, isbn10_to_13(isbn10.i10) as isbn13
from isbn10;
ISBN10 ISBN13
------------- -----------------
0-30-640615-x 978-0-30-640615-7
0-07-223065-7 978-0-07-223065-9
0-596-51446-x 978-0-596-51446-4
I have got the correct result.
Create or replace FUNCTION F_ISBN_CONV_13 (ISBN_10 IN VARCHAR2) RETURN VARCHAR2
AS
V_ISBN_13 VARCHAR2(13);
BEGIN
SELECT
CASE WHEN LENGTH(ISBN_10) = 10 THEN
CASE WHEN SUBSTR(ISBN_10,1,3) = '801' THEN
'201' ||
SUBSTR(ISBN_10,1,9) ||
SUBSTR(
(
10 -
SUBSTR(
(
(
2 +
1 +
SUBSTR(ISBN_10,2,1) +
SUBSTR(ISBN_10,4,1) +
SUBSTR(ISBN_10,6,1) +
SUBSTR(ISBN_10,8,1)
) +
(
(
0 +
SUBSTR(ISBN_10,1,1) +
SUBSTR(ISBN_10,3,1) +
SUBSTR(ISBN_10,5,1) +
SUBSTR(ISBN_10,7,1) +
SUBSTR(ISBN_10,9,1)
)
) * 3
)
,-1
,1
)
)
,-1
,1
)
ELSE
'978' ||
SUBSTR(ISBN_10,1,9) ||
SUBSTR(
(
10-
SUBSTR(
(
(
9 +
8 +
SUBSTR(ISBN_10,2,1) +
SUBSTR(ISBN_10,4,1) +
SUBSTR(ISBN_10,6,1) +
SUBSTR(ISBN_10,8,1)
) +
(
(
7 +
SUBSTR(ISBN_10,1,1) +
SUBSTR(ISBN_10,3,1) +
SUBSTR(ISBN_10,5,1) +
SUBSTR(ISBN_10,7,1) +
SUBSTR(ISBN_10,9,1)
)
) * 3
)
,-1 -- Need to change here from '1' to '-1'
,1
)
)
,-1
,1
)
END
ELSE
ISBN_10
END INTO V_ISBN_13
FROM
DUAL;
RETURN V_ISBN_13;
EXCEPTION
--< code >
END F_ISBN_CONV_13;