Inserting XML data into Oracle table - sql

I have a table that contains XML of HUGECLOB data type, I need to extract CLOB data as XML and get some specific XML tag value to insert it into another table.
I used dbms_lob to get XML and the following is my code to insert XML into another table.
create or replace procedure xml_into_table(l_xml in xmltype)
as
begin
insert into emp( EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPT)
SELECT * FROM xmltable('employees' passing l_xml
columns EMPNO NUMBER PATH ' /employee/empno',
ENAME VARCHAR2 PATH '/employee/ename',
JOB VARCHAR2 PATH '/employee/job',
HIREDATE DATE PATH '/employee/hiredate');
END;
/
Error(7,56): PL/SQL: ORA-00906: missing left parenthesis.
Can some one please guide me, what is the right way for achieving this.

The VARCHAR2 data type needs a size and you are missing the columns MGR, SAL, COMM and DEPT so SELECT * will only get 4 columns and not the 8 you have named in the INSERT.
create or replace procedure xml_into_table(l_xml in xmltype)
as
begin
insert into emp( EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPT)
SELECT empno,
ename,
job,
NULL,
hiredate,
NULL,
NULL,
NULL
FROM xmltable(
'employees'
passing l_xml
columns
EMPNO NUMBER PATH ' /employee/empno',
ENAME VARCHAR2(200) PATH '/employee/ename',
JOB VARCHAR2(200) PATH '/employee/job',
HIREDATE DATE PATH '/employee/hiredate'
);
END;
/

Related

please find the solution of this problem. ( in PL SQL ) --------

I'm doing an assignment and the last question states that I call the procedure from question 2 and function from question 3 and then put them in an insert clause(question 4).
Write a PL/SQL Code for an anonymous block to do the following (in package):
a) Get the doctor name for a given doctor id (read from keyboard)
using a function [FunGetDoctorName].
b) Get the department name for a given department id (read from
keyboard) using a procedure [ProGetepartmentName].
c) Insert the doctor name and department name (which you got from the
function and
procedure) by including serial number and current date into the
visitings table.
put the answer in ( Package)
this is my table codes:
CREATE TABLE DEPT(
DeptNo NUMBER PRIMARY KEY,
DeptName VARCHAR2(30) NOT NULL);
CREATE TABLE DOCTORS(
DoctorID NUMBER PRIMARY KEY,
DoctorNAME VARCHAR2(30) NOT NULL,
DeptNo NUMBER REFERENCES DEPT(DEPTNO),
Salary NUMBER NOT NULL);
CREATE TABLE VISITINGS(
SlNo NUMBER PRIMARY KEY,
DoctorName VARCHAR2(30),
DepartmentName VARCHAR2(30),
VisitDate DATE);
INSERT INTO DEPT VALUES(10,'ENT');
INSERT INTO DEPT VALUES(20,'Orthopedic');
INSERT INTO DEPT VALUES(30,'Cardiology');
INSERT INTO DEPT VALUES(40,'Neurology');
INSERT INTO DOCTORS VALUES(101,'Abheer',20,2550);
INSERT INTO DOCTORS VALUES(102,'Zuwaina',10,2175);
INSERT INTO DOCTORS VALUES(103,'Sara',30,1985);
INSERT INTO DOCTORS VALUES(104,'Fatma',20,2200);
INSERT INTO DOCTORS VALUES(105,'Laila',10,2600);
INSERT INTO VISITINGS VALUES(1,'Sara','Cardiology','10-Nov-19');
INSERT INTO VISITINGS VALUES(2,'Abheer','Orthopedic','11-Nov-19');
My function
create or replace function FunGetDoctorName(Docid number) return varchar2 is
docname DOCTORS.DoctorName%type;
Begin
select DoctorName into docname from DOCTORS where DoctorID = Docid;
return docname;
End ;
/
My procedure
create or replace procedure ProGetDepartmentName is
depname dept.DeptName%type;
Begin
select DeptName into depname from dept where DeptNo =10;
dbms_output.put_line(depname);
End ;
/
here is the problem:
Create or replace package pkg1 is
Function FunGetDoctorName(Docid Number) return varchar2 ;
procedure ProGetDepartmentName(DeptNo NUMBER);
end pkg1;
/
CREATE OR REPLACE PACKAGE BODY pkg1 AS
FUNCTION FunGetDoctorName(Docid Number)
RETURN varchar2 IS
docname DOCTORS.DoctorName%type;
BEGIN
select DoctorName into docname from DOCTORS where DoctorID = Docid;
return docname ;
END;
PROCEDURE ProGetDepartmentName(DeptNo NUMBER) IS
depname dept.DeptName%type;
BEGIN
Select DeptName into depname from dept where DeptNo=10;
dbms_output.put_line(depname) ;
END;
END pkg1 ;
/
declare
ProGetDepartmentName
(:DeptNo in dept.DeptNO%type,
depname in dept.DeptName%type)
FunGetDoctorName
(:Docid in DOCTORS.DoctorID%type ,
docname in DOCTORS.DoctorName%type);
docname varchar2(30);
depname varchar2(30);
Docid number;
serial number;
is
Begin
dbms_output.put_line('Department Name: '||depname);
select count(slno) into serial from visitings;
serial :=serial+1;
insert into visitings(slno,doctorname,departmentname,visitdate) values(serial,docname,depname,sysdate);
End;
/
I keep getting errors :
SP2-0552: Bind variable "DOCID" not declared.
First of all, your procedure must have one in and one out parameter so that you can pass deptno and get deptname as the output.
procedure ProGetDepartmentName(p_depnum number,P_depname out varchar)
is
Begin
select DeptName into P_depname from dept where DeptNo = p_depnum;
dbms_output.put_line(p_depnum);
End ;
/
In your pl/sql block, you can use substitution variable to take an input from keyboard as follows:
declare
V_DeptNo dept.DeptNO%type := &dept_no
V_deptname in dept.DeptName%type;
V_Docid in DOCTORS.DoctorID%type := &doc_id;
is
Begin
Pkg1.ProGetDepartmentName(v_deptno, v_deptname);
dbms_output.put_line('Department Name: '|| v_deptname);
insert into visitings(slno,doctorname,departmentname,visitdate)
values((select count(slno) + 1 from visitings),FunGetDoctorName(v_docid),v_deptname,sysdate);
End;
/
Note:
Instead of fetching count from table and adding one into it for slno, you should use the sequence.
In procedure and function, use exception block to handle no row found or multiple record found or any other issues gracefully.
While inserting in to table, you should also use exceprion block to handle issues gracefully. (In your case it is needed because of the count(slno) + 1 logic as it can assign same number to different sessions executing simentaneously which my lead to primary key violation)

In my table i don't have a column but i want to use in where condition is it possible or not

Suppose i have two database having same table name but columns name(empno,employee_no) are different so, i want to use single query in both of the table query is given below but i want in a single query.
In where condition i have mention there two different column is it possible or not to write in a single query.
select ename
from emp
where empno = '1234'---- in 1st databse
select ename
from emp
where employee_no = '5678' ---- in 2nd database
I want to execute a single query in both database which have two different column of empno and employee_no.
Can anyone please help with same.
One simple method is:
Create view in both the database with same name and same alias for empno and employee_no.
--In first db
CREATE VIEW MY_TAB_V AS
SELECT EMPNO AS ENO,
...
FROM MY_TAB;
--In second db
CREATE VIEW MY_TAB_V AS
SELECT EMPLOYEE_NO AS ENO,
...
FROM MY_TAB;
Now, you will be able to execute following query in both the databases:
Select * from MY_TAB_V where ENO=1234;
Create a simple view so that you will be able to even update the tables using that view.
Cheers!!
It is possible to have a dynamic SQL statement that queries different columns depending on what is available, by combining DBMS_XMLGEN.GETXML with the data dictionary. However, this solution is weird, slow, and buggy, and should be a last resort. It's usually better to put this level of dynamicism in an application or a PL/SQL block.
--Conditional select on EMP depending on which column exists.
--
--Convert XML to regular values.
select extractvalue(xml, '/ROWSET/ROW/ENAME') empname
from
(
--Convert to XMLType.
--(This is nontrivial because NULL must be handled oddly.)
select
case when xml is null then
xmltype('<?xml version="1.0"?><ROWSET><ROW><ENAME></ENAME></ROW></ROWSET>')
else xmltype(xml)
end xml
from
(
--Get dynamic result as XML.
select dbms_xmlgen.getxml('select ename from emp where '||column_name||' = 1234') xml
from dba_tab_columns
where owner = user
and table_name = 'EMP'
and column_name in ('EMPNO', 'EMPLOYEE_NO')
)
);
Use these commands to test the statement:
drop table emp;
create table emp(ename varchar2(100), empno number);
insert into emp values ('asdf', 1234);
commit;
<run the above SELECT>
drop table emp;
create table emp(ename varchar2(100), employee_no number);
insert into emp values ('qwer', 1234);
commit;
<run the above SELECT>

getting error in below code

I am getting missing parenthesis error in below for REPLACE function
declare
file_name varchar2(10):= 'emp.csv';
begin
execute immediate 'CREATE TABLE emp_external
(
EMPNO NUMBER(4),
emp_name varchar2(100),
HIREDATE DATE
)
ORGANIZATION EXTERNAL
(TYPE ORACLE_LOADER
DEFAULT DIRECTORY import
ACCESS PARAMETERS
(RECORDS DELIMITED BY NEWLINE
LOAD WHEN
(HIREDATE != BLANKS )
fields terminated by '''||','||'''
( EMPNO,
replace(emp_name,'''||'"'||','||''||'''),
HIREDATE DATE '||'yyyymmdd'||'
)
)
LOCATION ('''||file_name||''')
)
REJECT LIMIT UNLIMITED';
end;
when i am querying the external table .its giving me the error "EMP_NAME" is bad identifier
I'm not used to plsql but don't you miss a comma ?
EMPNO NUMBER(4),
emp_name varchar2(100),<------ Here ?
HIREDATE DATE
)

Underscore value in Varchar2 type column

Is the character underscore ( '_' ) acceptable (insertable) in varchar2 type column?
There is a value that needs to be inserted into a varchar2 column of one of my tables, but the value contains an underscore, like 'DOC_OTHER'
The value does not get inserted into the varchar2 column, whereas other values which do not contain an underscore character in their values get easily inserted (as usual).
I'm unable to understand this unusual behavior. Suggest!!
Edit:
Since the value is being picked up from a web service response xml, this is how its done.
The sql code is fine. All other values are getting retrieved, plus there is nothing wrong with the path as well.
Looping through the response:
begin
for p in (
select * from
---- some xmlnamespaces of the response ----
columns
"DocData" varchar2(240) path 'path to DocData in response'
,"RepID" varchar2(200) path 'path to RepID in response'
,"DocInit" varchar2(400) path 'path to DocInit in response'
)
loop
begin
insert into pooling_info
(session_id, user_id, DocData, RepID, DocInit)
values(
p_session, p_user, p."DocData", p."RepID", p."DocInit"
);
end;
end loop;
end;
If the value of DocData does not contain an underscore character, it is inserted in the table, this is strange but if the data contains an underscore, the value is not inserted!
It does not throw any error. The surrounding values are inserted except for this (DocData) which contains an underscore
There is nothing out of the ordinary about adding an '_' character(s) to a VARCHAR2 column.
As others have pointed out, the '_' character is a wildcard so it does have a special meaning when used with a LIKE condition.
More than likely, I suspect the problem you are experiencing is either a size issue (e.g. you are trying to place something too large for the VARCHAR2 that you are modifying) or a constraint issue.
Here is an example of modifying a column using the example schema, SCOTT.
SCOTT#dev>
1 CREATE table EMP3 as
2 (SELECT *
3* FROM emp)
SCOTT#dev> /
Table created.
SCOTT#dev> select empno, ename from emp3 where empno = 7369;
EMPNO ENAME
========== ==========
7369 SMITH
1 row selected.
SCOTT#dev> DESC emp3;
Name Null? Type
-------------------------
EMPNO NOT NULL NUMBER (4)
ENAME VARCHAR 2(10)
JOB VARCHAR 2(9)
MGR NUMBER (4)
HIREDATE DATE
SAL NUMBER (7,2)
COMM NUMBER (7,2)
DEPTNO NUMBER (2)
SCOTT#dev> UPDATE emp3
2 SET ename = ename || '_BOB'
3 WHERE empno = 7369
4 ;
1 row updated.
SCOTT#dev> select ename
2 from
3 emp3 where empno = 7369;
ENAME
==========
SMITH_BOB

Is it possible to convert a varchar2 column to a user defined type?

I have a type declared as
TYPE "TABLE_TYPE" AS TABLE OF varchar2(4000)
How can i convert a column i am selecting in a query to return that type.
For example
Select cast(to_char(sysdate) as TABLE_TYPE) from dual
Returns an ORA-00932: inconsistent datatypes: expected - got CHAR error. Is there a way to convert a column which is a varchar2 to be of the user defined type?
If you really want to return a collection with a single element, you would just need to call the type's constructor
SQL> create type table_type as table of varchar2(100);
2 /
Type created.
SQL> select table_type( to_char( sysdate ))
2 from dual;
TABLE_TYPE(TO_CHAR(SYSDATE))
-----------------------------------------------------------------------------
TABLE_TYPE('14-FEB-13')
Normally, though, when you are creating a collection, the intent is to populate it with multiple elements by running a query that returns multiple rows. For that, you would want to do something like
DECLARE
l_strs table_type;
BEGIN
SELECT ename
BULK COLLECT INTO l_strs
FROM emp;
<<l_strs now contains 1 element for each row in the EMP table>>
END;
Use cast + multiset
select cast(multiset(
select to_char(sysdate-level, 'YYYYMMDD')
from dual
connect by level <= 10
) as t_vchar_tab)
from dual;
Union causing an ORA-01790: expression must have same datatype as corresponding expression
CREATE OR REPLACE TYPE varchar2_ntt AS TABLE OF VARCHAR2(4000);
/
SELECT deptno
, CAST(COLLECT(ename) AS varchar2_ntt) AS emps
FROM scott.emp
GROUP BY deptno
/
select table_type(to_char(sysdate)) from dual;