How to insert a new row of values into a table and continue with my CTE (snowflake) - insert

I have CTE that looks like:
WITH COLS AS (
SELECT VALUE AS COL FROM ET1 LIMIT 1
),
RAW_COLS_ORDER AS (
SELECT TRY_CAST(SUBSTR(KEY, 2) AS NUMBER) AS COL_POS, VALUE --remove the c from the column aftersplitting the json
FROM (
SELECT KEY, VALUE::TEXT AS value
FROM COLS, TABLE(FLATTEN (INPUT => COLS.COL))
)
ORDER BY COL_POS ASC
),
RAW_POS AS (
SELECT (COL_POS + 3) AS COL_POSITION, VALUE
FROM RAW_COLS_ORDER
)
SELECT * FROM RAW_POS;
I want to insert a new row into my temporary table RAW_COLS_ORDERwhich has two columns "COL_POS" and "VALUE" with the value FOR COL_POS being 125 and the value for VALUE being "name". I am not sure how to add a new row to the RAW_COLS_ORDER table and continue on with creating the RAW_POS table using the previous tables. Is there a way I can do this without breaking the CTE? Would I have to use a UNION? (Also I have more temp tables building on the RAW_POS table)

Related

PL/SQL: I have problem updating a table with data from another table

First table ROOMDB:
roomnumber
rentalbalance
N327
0
Second table RENTALINVOICE:
invoicedate
roomnumber
totaldue
11/26/2021
N327
2,200.00
My update code:
UPDATE ROOMDB
SET
RENTALBALANCE = (SELECT TOTALDUE
FROM RENTALINVOICE
WHERE RENTALINVOICE.ROOMNUMBER=ROOMDB.ROOMNUMBER
AND INVOICEDATE=SYSDATE) ;
I need to update the totaldue column in ROOMDB with data from RENTALINVOICE though it successfully enters 2,200 to the totaldue column, AT THE SAME TIME IT ALSO WIPES OUT THE REST OF THE RECORDS on this column in ROOMDB.
Everytime I update it, it erases the rest of the records except the roomnumber I specified. Please help.
You basically seem to also updates rows in table roomdb where there is no row in table rentalinvoice and therefore the column rentalbalance will be set to null.
Have a look a following example:
drop table a;
create table a (id number, cost number);
insert into a values (1, 1);
insert into a values (2, 2);
drop table b;
create table b (id number, cost number);
insert into b values (1, 100);
-- updates all rows in a and sets cost to null whenen there is no row in b
update a set cost = (select cost from b where a.id = b.id);
select * from a;
-- only updaes rows in a where there is a row in b
update a set cost = id;
update a set cost = (select cost from b where a.id = b.id) where exists (select 1 from b where a.id = b.id);
select * from a;
When you execute an update command like this Oracle will update all the table rows. For every row Select command will execute with these row values. If the result of select in the update does not find any record will return null. In this situation the RENTALBALANCE column will set null too.
(SELECT TOTALDUE
FROM RENTALINVOICE
where WHERE RENTALINVOICE.ROOMNUMBER = ROOMDB.ROOMNUMBER
AND INVOICEDATE = SYSDATE)

oracle, adding a new line to a nested table

I have these three object
create or replace
type type_client
( num int ,
username varchar(30),
balance int,
ta table_achat,
ref_admin ref type_admin,
member function get_prix_achat_total return int );
create or replace
type table_achat as table of achat ;
create or replace
type achat as object ( num_item int , qte int
);
create table table_client OF type_client ;
suppose in an entry of table_client .. we have a nested table like this :
(num_item,qte) : (1 , 5),(2 , 3)
what I want is the nested table be like this (for example):
(num_item,qte) : (1 , 5),(2 , 3)(3 , 44)
What I mean is, how to add a new line to an already created nested table while keeping existing entries? ..
We can use the MULTISET UNION operator to create a new set from two sets. In your case one of those sets is your existing set and the second set is the set of new entries.
Here is a demo based on a simplified version of your set-up:
declare
nt table_achat;
begin
nt := table_achat(achat(1 , 5),achat(2 , 3));
dbms_output.put_line(nt.count());
nt := nt multiset union table_achat(achat(3 , 44));
dbms_output.put_line(nt.count());
end;
/
Given a table T42 with a column COL_NT which is a nested table of your table_achat type you could insert a new entry in the nested table like this:
insert into the
(select col_nt from t42 where id = 1)
values (achat(3,44));
irrelevant from the question, which i couldn't and didn't try to understand, you can not combine insert + select + values statements as you did before. Perhaps you may prefer among below ones :
insert into the -- if table has one string column
(select ta from table_client where username=user);
OR
insert into the -- if table has two numeric columns
values (3,44);

Oracle, merge tables, insert missing values while increasing id

I have two tables, one with values (FACT table), that I'm trying to merge one column into a key/value table (FACT_ATTRIBUTE table). The key is a number, and the value is a varchar2. The FACT_ATTRIBUTE table already has some entries in it. I am trying to write a package procedure that merges in new entries. We are trying to do away with triggers and sequences. I have a bit of SQL that selects entries not already in the table, but I am struggling with how to create the index key value. The key should just be one greater than the current max.
For example, say the FACT_ATTRIBUTE table already has entries up to key 5. A new entry "value 6" comes in. The insert for the key/value would be (6, "value 6") into FACT_ATTRIBUTE.
Here is where I am at:
INSERT INTO FACT_ATTRIBUTE (
KEY, VALUE
)
VALUES(
(SELECT (MAX(KEY) + 1) FROM FACT_ATTRIBUTE),
(SELECT DISTINCT ENTRY
FROM FACT fact_table
WHERE NOT EXISTS (
SELECT 1 FROM FACT_ATTRIBUTE fa
WHERE fa.VALUE = fact_table.ENTRY
))
);
The problem is obvious, the inner select grabs multiple elements, while the insert is single value. One constraint is that it cannot crash on null (if there are no new values). Is there a good way to accomplish this? My SQL skills are not the sharpest. Thanks in advance for any help!
One approach that might solve your problem is converting your insert statement from values to select. Try this -
INSERT INTO FACT_ATTRIBUTE (
KEY, VALUE
)
SELECT max(key) over (partition by value) + 1 as key_max, f.entry
FROM (
SELECT f.entry, fa.value
FROM fact_table f
LEFT OUTER JOIN fact_attribute fa
ON f.entry = fa.value)
WHERE fa.value is null;
It might need a little syntax polish cause I haven't had a server to check this on, but the gist seems right to me - using a left outer join to query all of the entries not existing in FACT_ATTRIBUTE and attaching the current maximum value in the table + 1.
This is the final solution that got me to what I needed.
DECLARE
max_id NUMBER;
BEGIN
--If no value, start with 1
SELECT NVL(max(fa.FACT_ATTRIBUTE), 1)
INTO max_id
FROM FACT_ATTRIBUTE fa;
INSERT INTO FACT_ATTRIBUTE (KEY, VALUE)
SELECT max_id + ROWNUM, DATA
FROM (
SELECT DISTINCT f.DATA
FROM FACT f
WHERE NOT EXISTS (
SELECT 1
FROM FACT_ATTRIBUTE fa
WHERE fa.VALUE = f.DATA
)
AND f.DATA IS NOT NULL
);
END;

Cursor for loop using a selection instead of a table ( Oracle )

I'm writing a procedure to fill up a child table from a parent table. The child table however has more fields than the parent table ( as it should be ). I've conjured a cursor which point to a selection, which is essentially a join of multiple tables.
Here's the code I got so far :
CREATE OR REPLACE PROCEDURE Pop_occ_lezione
AS
x Lezione%rowtype;
CURSOR cc IS
WITH y as(
SELECT Codice_corso,
nome_modulo,
Data_inizio_ed_modulo diem,
Giorno_lezione,
ora_inizio_lezione o_i,
ora_fine_lezione o_f,
anno,
id_cdl,
nome_sede,
locazione_modulo loc
FROM lezione
join ( select id_cdl, anno, codice_corso from corso ) using (codice_corso)
join ( select codice_corso, locazione_modulo from modulo ) using (codice_corso)
join ( select nome_sede, id_cdl from cdl ) using (id_cdl)
WHERE
case
when extract (month from Data_inizio_ed_modulo) < 9 then extract (year from Data_inizio_ed_modulo) - 1
else extract (year from Data_inizio_ed_modulo)
end = extract (year from sysdate+365)
)
SELECT *
FROM y
WHERE sem_check(y.diem,sysdate+365) = 1;
--
BEGIN
FETCH cc into x;
EXIT when cc%NOTFOUND;
INSERT INTO Occr_lezione
VALUES (
x.Codice_corso,
x.Nome_modulo,
x.diem,x.giorno_lezione,
x.Ora_inizio_lezione,
to_date(to_char(next_day(sysdate,x.Giorno_lezione),'DD-MM-YYYY') || to_char(x.Ora_inizio_lezione,' hh24:mi'),'dd-mm-yyyy hh24:mi'),
to_date(to_char(next_day(sysdate,x.Giorno_lezione),'DD-MM-YYYY') || to_char(x.Ora_fine_lezione,' hh24:mi'),'dd-mm-yyyy hh24:mi'),
x.nome_sede,
0,
x.loc
);
END LOOP;
END;
/
But of course it won't work, because the variable x has the type of my initial table row, which has less columns then my selection. Unfortunately As far as I know a rowtype variable is needed to cycle trough a cursor, in order to fetch data from it. Can you see the contradiction? How can I change the code? Is there a certain type of variable which can be crafted to reflect a row from my query result? Or maybe a way to cycle trough the data in the cursor without using a support variable? Or maybe something entirely different? Please let me know.
Ok, so as suggested I tried something like this:
INSERT INTO Occr_lezione(
Codice_corso,
Nome_modulo,
Data_inizio_ed_modulo,
Giorno_lezione,
Ora_inizio_lezione,
Ora_fine_lezione,
Anno,
Id_cdl,
Nome_sede,
Locazione_modulo
)
WITH y as(
SELECT Codice_corso,
Nome_modulo,
Data_inizio_ed_modulo,
Giorno_lezione,
Ora_inizio_lezione,
Ora_fine_lezione,
Anno,
Id_cdl,
Nome_sede,
Locazione_modulo
FROM Lezione
join ( select Id_cdl, Anno, Codice_corso from Corso ) using (codice_corso)
join ( select Codice_corso, Locazione_modulo from Modulo ) using (Codice_corso)
join ( select Nome_sede, Id_cdl from Cdl ) using (id_cdl)
WHERE
case
when extract (month from Data_inizio_ed_modulo) < 9 then extract (year from Data_inizio_ed_modulo) - 1
else extract (year from Data_inizio_ed_modulo)
end = extract (year from sysdate+365)
)
SELECT *
FROM y
WHERE sem_check(y.Data_inizio_ed_modulo,sysdate+365) = 1;
END;
/
But it says PL/SQL: ORA-00904: "LOCAZIONE_MODULO": invalid identifier
which isn't true, because the query return a table in which such column is present... am I missing something?
The code is compiled with no errors, it occurs when I try to fire the procedure.
In the table Occr_lezione as you can see:
CREATE TABLE Occr_lezione (
Codice_corso varchar2(20) NOT NULL,
Nome_modulo varchar2(50) NOT NULL,
Data_inizio_ed_modulo date NOT NULL,
Giorno_lezione number(1) NOT NULL,
Ora_inizio_lezione date NOT NULL,
Data_inizio_occr_lezione date,
Data_fine_occr_lezione date NOT NULL,
Nome_sede varchar2(30) NOT NULL,
Num_aula varchar2(3) NOT NULL,
Tipo_aula varchar2(20) NOT NULL,
--
CONSTRAINT fk_Occr_lezione_lezione FOREIGN KEY (Codice_corso,Nome_modulo,Data_inizio_ed_modulo,Giorno_lezione,Ora_inizio_lezione) REFERENCES Lezione(Codice_corso,Nome_modulo,Data_inizio_ed_modulo,Giorno_lezione,Ora_inizio_lezione) ON DELETE CASCADE,
CONSTRAINT fk_Occr_lezione_aula FOREIGN KEY (Nome_sede,Num_aula,Tipo_aula) REFERENCES Aula(Nome_sede,Num_aula,Tipo_aula) ON DELETE SET NULL,
CONSTRAINT pk_Occr_lezione PRIMARY KEY (Codice_corso,Nome_modulo,Data_inizio_ed_modulo,Giorno_lezione,Ora_inizio_lezione,Data_inizio_occr_lezione),
CHECK ( trunc(Data_inizio_occr_lezione) = trunc(Data_fine_occr_lezione) ), -- data inizio = data fine // prenotazione giornaliera
CHECK ( Data_inizio_occr_lezione < Data_fine_occr_lezione ) -- ora inizio < ora fine // coerenza temporale
there is not a column named Locazione_modulo, however the last column Tipo_aula as the same type and size of Locazione modulo :
CREATE TABLE Modulo (
Codice_corso varchar2(20) NOT NULL,
Nome_modulo varchar2(50),
Locazione_modulo varchar2(20) NOT NULL,
--
CONSTRAINT fk_Modulo_Corso FOREIGN KEY(Codice_corso) REFERENCES Corso(Codice_corso) ON DELETE CASCADE,
CONSTRAINT pk_Modulo PRIMARY KEY(Codice_corso,Nome_modulo),
CHECK (Locazione_modulo IN ('Aula','Laboratorio','Conferenze'))
);
So it should be irrelevant, right?
If you really want to use explicit cursors, you can declare x to be of type cc%rowtype
CREATE OR REPLACE PROCEDURE Pop_occ_lezione
AS
CURSOR cc IS ...
x cc%rowtype;
...
Unless you are using explicit cursors because you want to be able to explicitly fetch the data into local collections that you can leverage later on in your procedure, code using implicit cursors tends to be preferrable. That eliminates the need to FETCH and CLOSE the cursor or to write an EXIT condition and it implicitly does a bulk fetch to minimize context shifts.
BEGIN
FOR x IN cc
LOOP
INSERT INTO Occr_lezione ...
END LOOP;
END;
Of course, in either case, I would hope that you'd choose more meaningful names for your local variables-- x and cc don't tell you anything about what the variables are doing.
If all you are doing is taking data from one set of tables and inserting it into another table, it would be more efficient to write a single INSERT statement rather than coding a PL/SQL loop.
INSERT INTO Occr_lezione( <<column list>> )
SELECT <<column list>>
FROM <<tables you are joining together in the cursor definition>>
WHERE <<conditions from your cursor definition>>

How to populate column data in one table based on an id match from another table (using the data from the matched table)

In Oracle I have two tables. Both are populated with data and have a timestamp column.
One table has that column filled with data, the other table doesn't. But I need to get the data from the table that does into the column of the other table based on a match of another column.
Each has 'code' so the timestamp from the one table should only be put in the timestamp of the other table where the codes match.
I've tried cursors etc, but it seems like I'm missing something.
Any suggestions?
It sounds like you want a correlated update. This will update every row of destinationTable with the timestamp_col from sourceTable where there is a match on the code column.
UPDATE destinationTable d
SET timestamp_col = (SELECT s.timestamp_col
FROM sourceTable s
WHERE s.code = d.code )
WHERE EXISTS( SELECT 1
FROM sourceTable s
WHERE s.code = d.code )
Just for completeness, I think I would have done something like this (untested), if the destination has a primary key or unique column:
UPDATE (
SELECT d.primary_key AS pk, d.timestamp_col AS dest_col, MAX(s.timestamp_col) AS src_col
FROM dest d
JOIN src s ON d.code = s.code
GROUP BY pk, dest_col
) j
SET j.dest_col = j.src_col

Resources