How to sort DDL by name of the object - sorting

I want to sort the generated DDL of a database by name of the object. For example, I have the following DDL:
CREATE TABLE MyTable3 (
col1 integer,
col2 varchar(10)
);
CREATE TABLE MyTable1 (
col1 integer
);
CREATE TABLE MyTable2 (
col1 integer,
col2 varchar(10),
time timestamp
time2 timestamp
);
And I want the following output:
CREATE TABLE MyTable1 (
col1 integer
);
CREATE TABLE MyTable2 (
col1 integer,
col2 varchar(10),
time timestamp
);
CREATE TABLE MyTable3 (
col1 integer,
col2 varchar(10)
);
I have tried with awk, but I do not know to specify multiple lines: awk -F; '{print $NB}'
I found that msort could be the solution, but this package is not longer maintained.
As you can see, each element can have different quantity of lines, and I want to sort them by the first line which contains the name of the object.
What other options do I have to sort a document by multiple lines and a specific terminator (semi-colon).

Can you please try below gawk solution. The solution however assumes the tablename is in the same line as CREATE TABLE.
awk '
BEGIN {
}
{
if($0 ~ /CREATE TABLE/) {
found = match($0, /CREATE TABLE (.*) \(/, ary);
if(found != 0)
{
tablename=ary[1];
}
oneDDL=$0;
}
else if($0 ~ /;/) {
oneDDL=oneDDL"\n"$0;
arr[tablename]=oneDDL;
}
else {
oneDDL=oneDDL"\n"$0;
}
}
END {
asort(arr);
for(i in arr) {
print arr[i];
print "\n";
}
}' Input_File
Put tablename in an array arr as index with value as the text of DDL oneDDL.
Sort the array.
Then print the contents of the array.

Related

Put result of cursor into table

How i can put result rows of this cursor, into column ?
CURSOR CUR1 IS SELECT FILMS.FILM_CODE from FILMS where FILMS.ID_FILM = ID_FILM_ FOR UPDATE OF FILM_CODE;
I wanna put this rows into FILM_CODE column of table below
CREATE TABLE SESSIONF(
ID_SESSION INTEGER DEFAULT SESSION_ID_SEQ.NEXTVAL NOT NULL,
FILM_CODE INTEGER NOT NULL,
NAMEOFGENRE VARCHAR2(200) NOT NULL,
HALL_CODE INTEGER NOT NULL,
NUMBEROFFREEPLACES INTEGER NOT NULL,
COST INTEGER NOT NULL,
DATA_OF_SESSION DATE,
CONSTRAINT PK_ID_SESSION PRIMARY KEY (ID_SESSION)
)
TABLESPACE TBS_PERM_KINO;
Sorry if topic with the same issue already exist, couldn't find it.
EDIT
Procedure on update
create or replace procedure UpdateFILM(ID_FILM_ FILMS.ID_FILM%TYPE,FILM_CODE_ IN FILMS.FILM_CODE%TYPE,FILM_ IN FILMS.FILM%TYPE,GENRE_CODE_ FILMS.GENRE_CODE%TYPE,DIR_CODE_ FILMS.DIRECTOR_CODE%TYPE,YEAROFRELEAS_ FILMS.YEAROFRELEAS%TYPE)
is
varible int := 0;
varible2 int := 0;
varible3 int := 0;
varible4 int := 0;
CURSOR CUR1 IS SELECT FILMS.FILM_CODE from FILMS where FILMS.ID_FILM = ID_FILM_ FOR UPDATE OF FILM_CODE;
F_CODE SESSIONF.FILM_CODE%TYPE;
begin
select count(*) INTO VARIBLE from FILMS where FILM_CODE_ = FILMS.FILM_CODE;
select count(*) INTO VARIBLE2 from DIRECTORS where DIR_CODE_ = DIRECTORS.DIRECTOR_CODE;
IF varible != 0
THEN DBMS_OUTPUT.put_line('FILM_CODE_ erro : there is ALREADY THE SAME FILM_CODE');
ELSIF varible2 =0
THEN DBMS_OUTPUT.put_line('DIR_CODE_ ERR : there IS NO SUCH DIRECTOR_CODE');
ELSIF varible3 !=0
THEN DBMS_OUTPUT.put_line('GENRE_CODE_ ERR : there IS NO SUCH GENRE_CODE_');
ELSIF TO_DATE('12/12/1941', 'DD/MM/YYYY') > YEAROFRELEAS_
THEN DBMS_OUTPUT.put_line('YEAROFRELEAS_ erro : DATE IS LESS THEN 1941');
ELSIF TO_DATE('12/12/3000', 'DD/MM/YYYY') < YEAROFRELEAS_
THEN DBMS_OUTPUT.put_line('YEAROFRELEAS_ erro : DATE IS TO HIGH(MORE THEN 3000)');
ELSE
UPDATE FILMS SET
FILMS.ID_FILM = ID_FILM_,
FILMS.FILM_CODE = FILM_CODE_,
FILMS.FILM = FILM_,
FILMS.GENRE_CODE = GENRE_CODE_,
FILMS.DIRECTOR_CODE = DIR_CODE_,
FILMS.YEAROFRELEAS = YEAROFRELEAS_
WHERE FILMS.ID_FILM = ID_FILM_;
OPEN CUR1;
LOOP
FETCH CUR1 INTO F_CODE;
UPDATE SESSIONF SET SESSIONF.FILM_CODE=FILM_CODE_ WHERE F_CODE = SESSIONF.FILM_CODE;
DBMS_OUTPUT.put_line(F_CODE);
EXIT WHEN CUR1%NOTFOUND;
END LOOP;
CLOSE CUR1;
DBMS_OUTPUT.put_line('films update successful');
END IF;
exception
when others
then DBMS_OUTPUT.put_line(sqlerrm);
end;
CREATE sequence FILM_ID_SEQ;
CREATE TABLE FILMS (
ID_FILM INTEGER DEFAULT FILM_ID_SEQ.NEXTVAL NOT NULL,
FILM_CODE INTEGER NOT NULL,
FILM VARCHAR2(200) NOT NULL UNIQUE,
GENRE_CODE INTEGER NOT NULL,
DIRECTOR_CODE INTEGER NOT NULL,
YEAROFRELEAS DATE,
CONSTRAINT PK_ID_FILM PRIMARY KEY (ID_FILM)
)
TABLESPACE TBS_PERM_KINO;
alter table SESSIONF add constraint FK_FILM_CODE_REF_ID_FILM foreign key (FILM_CODE) references FILMS (ID_FILM) ON DELETE CASCADE;
The way you put it, you can't do that.
Why? Because table contains numerous NOT NULL columns, while cursor selects only one column: FILM_CODE. You could store that value, but what will you put into other mandatory columns?
Therefore, you'll have to either fix cursor's select statement so that it fetches additional columns, or modify table and remove not null constraints (or, possibly, set default values for those columns).
On the other hand, why would you use a cursor? Cursor is usually slow (as you'll probably use it in a loop which works row-by-row). Consider
insert into sessionf (filmcode, nameofgenre, ...)
select f.filmcode, ...
from films f
join ... on ...

Hive parse and edit array to struct field

I've a requirement in hive complex data structure which I'm new to. I've tried few things which didn't work out. I'd like to know if there is a solution or I'm looking at a dead end.
Requirement :
Table1 and Table2 are of same create syntax. I want to select all columns from table1 and insert it into table2, where few column values will be modified. For struct field also, I can make it work using named_struct.
But if table1 has array> type, then I'm not sure how to make it work.
eg.,
CREATE TABLE IF NOT EXISTS table1 (
ID INT,
XYZ array<STRUCT<X:DOUBLE, Y:DOUBLE, Z:DOUBLE>>
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '$'
MAP KEYS TERMINATED BY '#' ;
CREATE TABLE IF NOT EXISTS table2 (
ID INT,
XYZ array<STRUCT<X:DOUBLE, Y:DOUBLE, Z:DOUBLE>>
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
COLLECTION ITEMS TERMINATED BY '$'
MAP KEYS TERMINATED BY '#' ;
hive> select * from table1 ;
OK
1 [{"x":1,"y":2,"z":3},{"x":4,"y":5,"z":6},{"x":7,"y":8,"z":9}]
2 [{"x":4,"y":5,"z":6},{"x":7,"y":8,"z":9}]
How can I update a struct field in array while inserting. Let's say if structField y is 5, then I want it to be inserted as 0.
For complex type struct you can use Brickhouse UDF.Download the jar and add it in your script.
add jar hdfs://path_where_jars_are_downloaded/brickhouse-0.6.0.jar
Create a collect function.
create temporary function collect_arrayofstructs as 'brickhouse.udf.collect.CollectUDAF';
Query:Replace the y value with 0
select ID, collect_arrayofstructs(
named_struct(
"x", x,
"y", 0,
"z", z,
)) as XYZ
from table1;

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>>

Identifier is too long while loading from SQL*Loader

I have a table structure like this
CREATE TABLE acn_scr_upload_header
(
FILE_RECORD_DESCRIPTOR varchar2(5) NOT NULL,
schedule_no Number(10) NOT NULL,
upld_time_stamp Date NOT NULL,
seq_no number NOT NULL,
filename varchar2(100) ,
schedule_date_time Date
);
When I try to load my file via SQL*Loader I'm getting an error on this value in the column filename: Stock_Count_Request_01122014010101.csv. The error is:
Error on table ACN_SCR_UPLOAD_HEADER, column FILENAME.
ORA-00972: identifier is too long".
If I try to insert the same value into the table using an INSERT statement it works fine.
My data file Stock_Count_Request_01122014010101.csv looks like
FHEAD,1,12345,20141103
FDETL,7,100,W,20141231,SC100,B,N,1,5
FTAIL,8,6
and control file
LOAD DATA
INFILE '$IN_DIR/$FILENAME'
APPEND
INTO TABLE ACN_SCR_UPLOAD_HEADER
WHEN FILE_RECORD_DESCRIPTOR = 'FHEAD'
FIELDS TERMINATED BY ","
TRAILING NULLCOLS
(
FILE_RECORD_DESCRIPTOR position(1),
LINE_NO FILLER,
schedule_no ,
schedule_date_time,
upld_time_stamp sysdate,
seq_no "TJX_STOCK_COUNT_REQ_UPLD_SEQ.NEXTVAL",
FILENAME constant ""
)

XQUERY select different rows in multiple tags

I have a table in oracle
create table MOVIE
(MOVIE_ID VARCHAR2(10 BYTE),
TITLE VARCHAR2(50 BYTE),
DIRECTOR VARCHAR2(50 BYTE),
WRITER VARCHAR2(50 BYTE),
GENRE VARCHAR2(50 BYTE),
RELEASE_DATE DATE,
RUNTIME NUMBER,
REVIEWS XMLTYPE);
REVIEW IS OF XML TYPE
Each Reviews has multiple tags of REVIEW(MORE THAN ONE TAG WITH A TAG)
I Have 25 such Reviews with multiple Review Tag inside each of them
I want the ids of repeating tag in different rows
I have written the following query
SELECT
XMLQuery(
'for $i in distinct-values (/Reviews/REVIEW/ID)
return data($i)'
PASSING REVIEWS RETURNING CONTENT) ID
FROM MOVIE;
The above query is giving me the output as
M17 M18 M19 if there are inside the same REVIEW tag.
I am getting all the three in a single row
I want them in 3 different rows.
M17
M18
M19
Any idea whats wrong with the query.
XMLTable() join with MOVIE table must work for 11g :
select
m.movie_id,
id_list.review_id
from
movie m,
XMLTable(
'for $i in distinct-values($param/Reviews/REVIEW/ID) return $i'
passing m.reviews as "param"
columns review_id varchar2(4000) path '//ID'
) id_list
But in case of 10g it goes harder, because such construction always get value for REVIEWS field from first selected record.
Tricks with multisets won't work and produce same results (got values from first record).
I found only solution for 10g by aggregating all results by XMLAgg() into one record and then build new dataset from that record with XMLTable().
select
movie_id,
review_id
from
XMLTable(
'
for $movie in $big_root/full_list/movie_entry,
$review_id in $movie/ID
return <row><movie_id>{data($movie/#movie_id)}</movie_id><review_id>{$id}</review_id></row>
'
passing
(
select
XMLElement("full_list",
XMLAgg(
XMLElement("movie_entry",
XMLAttributes(m.movie_id as "movie_id"),
XMLQuery(
'for $i in distinct-values($param/Reviews/REVIEW/ID) return $i'
passing by value m.reviews as "param"
returning content
)
)
)
)
from
movie m
)
as "big_root"
columns
movie_id varchar2(4000) path '//row/movie_id',
review_id varchar2(4000) path '//row/review_id'
)
Sorry, I can't test now this query but hope it's enough to give you idea about what it looks like.
P.S. If anyone can explain such behavior of Oracle 10g in case of joining with XMLTable() constructed from field it would be nice :)

Resources