Data manipulation in APEX 20 oracle - oracle

Currently I am performing dynamic action (executing server side code) where I am selecting the values from two different tables (XYZ & ABC) performing calculation and inserting into another table (ABC_TEMP) and creating a report view out of that in apex(v20)
Below is what I am performing.
BEGIN
INSERT INTO ABC_TEMP (
A1, --> VARCHAR2(4000)
B1, --> VARCHAR2(4000)
C1, --> NUMBER
D1, --> NUMBER
E1, --> NUMBER
F, --> NUMBER
G1, --> NUMBER
H3, --> NUMBER
I3, --> NUMBER
J, --> NUMBER
K, --> NUMBER
L, --> NUMBER
timestamp -->timestamp(6)
)
VALUES (
:A_SELECT,
:B_SELECT,
:C_SELECT,
(SELECT D2 FROM XYZ WHERE B2 = :B_SELECT AND C2 = :C_SELECT),
(SELECT E2 FROM XYZ WHERE B2 = :B_SELECT AND C2 = :C_SELECT),
(SELECT SUM(D2 + E2) FROM XYZ WHERE B2 = :B_SELECT AND C2 = :C_SELECT),
(SELECT G2 FROM XYZ WHERE B2 = :B_SELECT AND C2 = :B_SELECT),
(SELECT H2 FROM ABC WHERE A2 = :A_SELECT AND P2 = 'mock1' AND SE = 'mock2' AND Q2 = 'val1'),
(SELECT H2 FROM ABC WHERE A2 = :A_SELECT AND P2 = 'mock1' AND SE = 'mock2' AND Q2 = 'val2'),
(:J), --> This value is derived from `ABC_TEMP` table only by dividing I3 BY F
(:K), --> This value is derived from `ABC_TEMP` table only by dividing H3 BY G1
(:L), --> this value is derived from low of J & K column
(CURRENT_TIMESTAMP)
);
END;
My question is how do I set the values of column J,K,L in the same query as it involves selecting from the same table and performing calculation on top of it where I am inserting data.
if this is not possible what can be other approach out here.

Literally copy/paste those columns' source (select statements) and divide them:
values
(:A_SELECT,
...
-- for J, literally copy/paste I3 / F
(SELECT H2 FROM ABC WHERE A2 = :A_SELECT AND P2 = 'mock1' AND SE = 'mock2' AND Q2 = 'val2') /
(SELECT SUM(D2 + E2) FROM XYZ WHERE B2 = :B_SELECT AND C2 = :C_SELECT)
-- the same goes for other columns
);
Does it work? Sure:
SQL> select (select sal from emp where rownum = 1) /
2 (select empno from emp where rownum = 1) as j
3 from dual;
J
----------
,108562899
SQL>
Is it optimized? Of course not, you'll be using the same query twice (once for the "original" column and once for "derived" one).
Can you optimize it? Maybe. Try to create bunch of CTEs (one for each subquery you used) and then re-use it for derived columns.
On the other hand, why would you store such a value into the table? That's redundant. Omit (drop) columns J, K and L from the table and compute their value whenever needed, e.g.
select a1,
c1,
i3 / f as J --> this
from abc_temp
where ...
Or, you could even create a view using the same select (I posted above) and select values from a view.

Related

How to update data by select random row value from another table

I have three tables A, B, C, and I want to randomly take a row from the col_b column of the table B then update it to the table A. Table C is the subtable of Table B, which is used to filter the data of Table B.
Here is my sql statement:
update a a
set a.col_a_b =
(select t.col_b
from (select a1.col_a, b1.col_b, a1.rn_var
-- the number 6 is because I only have 6 rows of data,
-- and the real situation should be the total number of conditions in table b
from (select a0.col_a, TRUNC(dbms_random.value(1, 6)) rn_var
from a a0) a1
left join (select b.col_b, rownum rn
from b b
where exists (select 1
from c c
where b.id = c.col_b_id
and c.col_c = 'c1')) b1
on a1.rn_var = b1.rn) t
where t.col_a = a.col_a);
I found a strange phenomenon:
If I remove a1.rn_var (line from (select a1.col_a, b1.col_b, a1.rn_var), it doesn't work as my expected
On the basis of the above, if I replace exists with left join (or join), the result is the same
If I reomve both a1.rn_var and exists, it will work fine.
I know there may be a better way to implement it, but who can tell me why?
Update:
Actually, it is caused by this sql:
select a1.col_a, b1.col_b -- remove a1.rn_var
from (select a0.col_a, TRUNC(dbms_random.value(1, 6)) rn_var from a a0) a1
left join (select b.col_b, rownum rn
from b b
where exists (select 1
from c c
where b.id = c.col_b_id
and c.col_c = 'c1')) b1
on a1.rn_var = b1.rn
-- this is for better display of results
where a1.col_a = 'a1';
In the above sql, I may get multiple rows of data or column b1.col_b is empty, as shown below:
a1 b1
a1 b2
a1 b4
------------------------------------------------
a1 -- here is null
In addition, each value of column a1.col_a is the same, I mean, if value a1 has multiple rows, then value a2 (and so on) has the same result, like this:
a1 b2
a1 b4
a1 b5
a2 b2
a2 b4
a2 b5
...
You can use a random number and order by that random number to get random records.
I prefer using the following technique:
UPDATE A A
SET
A.COL_A_B = (
SELECT
COL_B
FROM
(
SELECT
COL_B,
TRUNC(DBMS_RANDOM.VALUE(1, COUNT(1) OVER())) RANDOM_NUMBER --GENERATES RANDOM NUMBER
FROM
(
SELECT DISTINCT
B.COL_B -- FETCHING DISTINCT RESULT
FROM
B B
-- EXISTS IS CONVERTED INTO JOIN
JOIN C C ON ( B.ID = C.COL_B_ID
AND C.COL_C = 'c1' )
)
ORDER BY
RANDOM_NUMBER -- ORDERING IS DONE BY RANDOM NUMBER
FETCH FIRST ROWS ONLY -- FETCHING ONLY FIRST ROW FROM ORDERED RECORDS
)
)
Cheers!!

Query in Oracle for running sum

I need to pull the result set with sum of the previous record and current record.
Logic
My table is having one key column C1 and a numeric column C2. I need a result like below example. I need 3 columns as the out put out which 1 columns is with running sum. First two columns are same as source with the thrid columns but
The first record of C3 = first record C2.
Second record C3 = "First Record C2 + Second Record C2";
Third record C3 = "First Record C2 + Second Record C2 + Thrid Record C2"
and it should continue for all the records.
Ex.
I have one source table like
C1 C2
---------
a 1
b 2
c 3
I Need output like below
C1 C2 C3
-------------
a 1 1
b 2 3
c 3 6
select c1, c2, sum(c2) over (order by c2) c3
from table_name

Oracle: how to flash back a specific column?

How do I flash back a specific column for all rows in a table?
For example, given this table:
select * from t as of scn 1201789714628;
a b
- -
x 1
y 2
z 3
select * from t;
a b
- -
x 4
y 5
z 6
I can flash back a column in a specific row as follows:
update t set b = (select b from t as of scn 1201789714628 where a='x') where a='x';
select * from t;
a b
- -
x 1
y 5
z 6
but I can't figure out the syntax to set b to its previous value this for all rows.
update t t1 set b = (select b from t as of scn 1201789714628) t2 where t1.a = t2.a;
Error at Command Line:11 Column:60
SQL Error: ORA-00933: SQL command not properly ended
You may try this:
update t t1
set b = (select b from (select a, b from t as of scn 1201789714628) t2
where t1.a = t2.a);
P.S. I'd recommend to copy your snapshot in a temporary table if you're not going to update it right now (it can dissapear very soon).

Generate List for label with barcode printing from tablem with number quantity of rows

I try to generate list of products for printing labels, but all of my attempt fail (with connect by level)!
My table:
CREATE TABLE LABELS
(
PRODUCT VARCHAR2(8 BYTE),
Q_ROWS NUMBER
);
Information in the table:
INSERT INTO LABELS (PRODUCT, Q_ROWS) VALUES('D', 3);
INSERT INTO LABELS (PRODUCT, Q_ROWS) VALUES('A', 1);
INSERT INTO LABELS (PRODUCT, Q_ROWS) VALUES('C', 4);
INSERT INTO LABELS (PRODUCT, Q_ROWS) VALUES('B', 2);
Expected Result in a oracle select
PRODUCT
A
B
B
C
C
C
C
D
D
D
Results: (1 row for A, 2 rows for B, 4 rows to C and 3 rows to D)
Can someone help me?
Use LEVEL to get a "table" that counts from 1 to the maximum number of rows:
SELECT LEVEL AS LabelNum
FROM DUAL
CONNECT BY LEVEL <= (SELECT MAX(Q_Rows) FROM Labels)
This will give you the following table:
LabelNum
--------
1
2
3
4
Next, join this to your LABELS table where LabelNum <= Q_Rows. Here's the whole query:
WITH Mult AS (
SELECT LEVEL AS LabelNum
FROM DUAL
CONNECT BY LEVEL <= (SELECT MAX(Q_Rows) FROM Labels)
)
SELECT Product
FROM Labels
INNER JOIN Mult ON LabelNum <= Q_Rows
ORDER BY Product, LabelNum
There's a working SQLFiddle here.
Finally, good job including the create/populate scripts :)
Another approach, using model clause:
select product
from labels
model
partition by (product)
dimension by (1 as indx)
measures(q_rows)
rules(
q_rows[for indx from 1 to q_rows[1] increment 1] = q_rows[1]
)
order by product
result:
PRODUCT
----------
A
B
B
C
C
C
C
D
D
D
SQLFiddle Demo

Similar queries have way different execution times

I had the following query:
SELECT nvl(sum(adjust1),0)
FROM (
SELECT
ManyOperationsOnFieldX adjust1,
a, b, c, d, e
FROM (
SELECT
a, b, c, d, e,
SubStr(balance, INSTR(balance, '[&&2~', 1, 1)) X
FROM
table
WHERE
a >= To_Date('&&1','YYYYMMDD')
AND a < To_Date('&&1','YYYYMMDD')+1
)
)
WHERE
b LIKE ...
AND e IS NULL
AND adjust1>0
AND (b NOT IN ('...','...','...'))
OR (b = '... AND c <> NULL)
I tried to change it to this:
SELECT nvl(sum(adjust1),0)
FROM (
SELECT
ManyOperationsOnFieldX adjust1
FROM (
SELECT
SubStr(balance, INSTR(balance, '[&&2~', 1, 1)) X
FROM
table
WHERE
a >= To_Date('&&1','YYYYMMDD')
AND a < To_Date('&&1','YYYYMMDD')+1
AND b LIKE '..'
AND e IS NULL
AND (b NOT IN ('..','..','..'))
OR (b='..' AND c <> NULL)
)
)
WHERE
adjust1>0
Mi intention was to have all the filtering in the innermost query, and only give to the outer ones the field X which is the one I have to operate a lot. However, the firts (original) query takes a couple of seconds to execute, while the second one won't even finish. I waited for almost 20 minutes and still I wouldn't get the answer.
Is there an obvious reason for this to happen that I might be overlooking?
These are the plans for each of them:
SELECT STATEMENT optimizer=all_rows (cost = 973 Card = 1 bytes = 288)
SORT (aggregate)
PARTITION RANGE (single) (cost=973 Card = 3 bytes = 864)
TABLE ACCESS (full) OF "table" #3 TABLE Optimizer = analyzed(cost=973 Card = 3 bytes=564)
SELECT STATEMENT optimizer=all_rows (cost = 750.354 Card = 1 bytes = 288)
SORT (aggregate)
PARTITION RANGE (ALL) (cost=759.354 Cart = 64.339 bytes = 18.529.632)
TABLE ACCESS (full) OF "table" #3 TABLE Optimizer = analyzed(cost=750.354 Card = 64.339 bytes=18.529.632)
Your two queries are not identical.
the logical operator AND is evaluated before the operator OR:
SQL> WITH data AS
2 (SELECT rownum id
3 FROM dual
4 CONNECT BY level <= 10)
5 SELECT *
6 FROM data
7 WHERE id = 2
8 AND id = 3
9 OR id = 5;
ID
----------
5
So your first query means: Give me the big SUM over this partition when the data is this way.
Your second query means: give me the big SUM over (this partition when the data is this way) or (when the data is this other way [no partition elimination hence big full scan])
Be careful when mixing the logical operators AND and OR. My advice would be to use brackets so as to avoid any confusion.
It is all about your OR... Try this:
SELECT nvl(sum(adjust1),0)
FROM (
SELECT
ManyOperationsOnFieldX adjust1
FROM (
SELECT
SubStr(balance, INSTR(balance, '[&&2~', 1, 1)) X
FROM
table
WHERE
a >= To_Date('&&1','YYYYMMDD')
AND a < To_Date('&&1','YYYYMMDD')+1
AND (
b LIKE '..'
AND e IS NULL
AND (b NOT IN ('..','..','..'))
OR (b='..' AND c <> NULL)
)
)
)
WHERE
adjust1>0
Because you have the OR inline with the rest of your AND statements with no parenthesis, the 2nd version isn't limiting the data checked to just the rows that fall in the date filter. For more info, see the documentation of Condition Precedence

Resources