I know how to run normal select query.
Class.forName("oracle.jdbc.driver.OracleDriver");
String url = "jdbc:oracle:thin:#xxx";
String uname = "";
String passwd = "";
Connection conn = DriverManager.getConnection(url, uname, passwd);
Statement stmt = conn.createStatement();
String sql = "select * from table_name";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println();
}
But how to run query like sql = "describe table_name" ?
describe is a SQL*Plus command; although it works elsewhere (such as in SQL Developer or TOAD), it is not a "standard" command so I don't think you can use it the way you wanted.
Therefore, as you already know how to run a "normal" query, do it again, but this time by fetching data from user_tab_columns which contains data you need. For example:
SQL> SELECT column_name, data_type, data_precision, data_length, nullable
2 from user_tab_columns
3 where table_name = 'TEMP';
COLUMN_NAME DATA_TYPE DATA_PRECISION DATA_LENGTH N
--------------- --------------- -------------- ----------- -
ID NUMBER 22 Y
ENAME VARCHAR2 10 Y
JOB VARCHAR2 15 Y
DEPT NUMBER 22 Y
HIREDATE DATE 7 Y
LOC VARCHAR2 10 Y
6 rows selected.
which can be compared to
SQL> describe temp
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
ENAME VARCHAR2(10)
JOB VARCHAR2(15)
DEPT NUMBER
HIREDATE DATE
LOC VARCHAR2(10)
SQL>
As of comments: there's that nice view named dictionary you can query and find some useful information, i.e. a system view which then lets you find another information. Here's how:
SQL> select * from dictionary
2 where lower(table_name) like '%user%' and lower(comments) like '%comment%';
TABLE_NAME COMMENTS
------------------------- --------------------------------------------------
USER_COL_COMMENTS Comments on columns of user's tables and views
USER_INDEXTYPE_COMMENTS Comments for user-defined indextypes
USER_MVIEW_COMMENTS Comments on materialized views owned by the user
USER_OPERATOR_COMMENTS Comments for user-defined operators
USER_TAB_COMMENTS Comments on the tables and views owned by the user
OK; it is user_tab_comments and user_col_comments I need. So let's add some comments to the temp table:
SQL> comment on table temp is 'Sample table for Stack Overflow';
Comment created.
SQL> comment on column temp.ename is 'Employee''s name';
Comment created.
Result:
SQL> select * from user_tab_comments where table_name = 'TEMP';
TABLE_NAME TABLE_TYPE COMMENTS
------------------------- ----------- --------------------------------------------------
TEMP TABLE Sample table for Stack Overflow
SQL> select * from user_col_comments where table_name = 'TEMP';
TABLE_NAME COLUMN_NAME COMMENTS
------------------------- --------------- --------------------------------------------------
TEMP ID
TEMP ENAME Employee's name
TEMP JOB
TEMP DEPT
TEMP HIREDATE
TEMP LOC
6 rows selected.
SQL>
I have a column "Names" in the "Employee" table that has following values. The values either contain only single name (first, last, username) or Multiple names separated with semicolon (;). I need to search the values from that table either by first name or last name or username.
I have created a procedure but it is fetching only 1st,4th,5th records. Please let me know how to retrieve 2nd and 3rd records as well.
Firstname and lastname can be given by user with minimum of 2 characters length.
Username is given entire.
Employee:
ID Name Title
1 Andrea Warbutton (awr01) Manager
2 Claire Taylor (cta02);Mark Kites (mak03);Anitha Rooney (anr06) HOD;Supervisor;Business
3 Dave Rites (dar12);Jessica Simpson (jesi10) Lead;Analyst
4 Nick Ken (nik56) Product (Local,Regional)
5 Claire Pilkington (cpt09) Sales Owner
Code:
Create or replace empl (pm_firstname varchar2(100),
pm_lastname varchar2(100),
pm_username varchar2(100))
BEGIN
Select * from Employee
where Upper(Name) like Upper(pm_firstname ||'%'||) -- this will fetch 1st,4th,5th record
OR Upper(SUBSTR(Name, INSTR(Name),' '+1)) like Upper(pm_lastname ||'%'||) -- this will fetch 1st,4th,5th record
OR upper(REGEXP_SUBSTR(Name,'\((.+)\)',1,1,NULL,1)) = Upper(pm_username); -- -- this will fetch 1st,4th,5th record
END;
End empl ;
Please let me know how to retrieve 2nd and 3rd records as well.
Desired Output:
When searched with firstname = "Andrea", the output is below
ID Name Title
1 Andrea Warbutton (awr01) Manager
When searched with firstname = "Claire", the output is below
ID Name Title
2 Claire Taylor (cta02) HOD
5 Claire Pilkington (cpt09) Sales Owner
When searched with lastname = "Simps", the output is below
ID Name Title
3 Jessica Simpson (jesi10) Analyst
When searched with username = "mak03", the output is below
ID Name Title
2 Mark Kites (mak03) Supervisor
When searched with username = "nik56", the output is below
ID Name Title
4 Nick Ken (nik56) Product (Local,Regional)
with
x as (select id, name, '"'||replace(name, ';', '","')||'"' xml from employee),
n as (select id, name, column_value as cv from x, xmltable(xml))
select id,
trim(regexp_substr(cv, '(\S*)(\s)')) fname,
trim(regexp_substr(cv, '(\S*)(\s)', 1, 2)) lname,
regexp_substr(cv, '\((.+)\)', 1, 1, NULL, 1) uname
from n
Your task would be much easier if you normalize these data. Above query outputs:
ID FNAME LNAME UNAME
1 Andrea Warbutton awr01
2 Claire Taylor cta02
2 Mark Kites mak03
2 Anitha Rooney anr06
3 Dave Rites dar12
3 Jessica Simpson jesi10
4 Nick Ken nik56
5 Claire Pilkington cpt09
demo
Now you can search first, last, usernames however you want. First expression finds first word, then second and word between brackets.
Edit:
I posted the table structure with just ID and Name columns. However, I
have Titles column also in the same format separated with (semicolon).
In this case, How can I Normalize Titles as well along with Names
This query worked for provided examples:
with
x as (select id, name, '"'||replace(name, ';', '","')||'"' xmln,
'"'||replace(title, ';', '","')||'"' xmlt
from employee),
n1 as (select id, trim(xn.column_value) nm, rownum rn from x, xmltable(xmln) xn),
n2 as (select id, trim(xt.column_value) tt, rownum rn from x, xmltable(xmlt) xt)
select id, trim(regexp_substr(nm, '(\S*)(\s)')) fname,
trim(regexp_substr(nm, '(\S*)(\s)', 1, 2)) lname,
regexp_substr(nm, '\((.+)\)', 1, 1, NULL, 1) uname,
tt title
from n1 join n2 using (id, rn)
dbfiddle demo
Be careful however, because we cannot write ideal query. If you have entries like Benicio Del Toro, Mary Jo Catlett, Jean Claude Van Damme, it's impossible to write correct regexp. Sometimes second word is part of lastname, sometimes it is firstname, middlename etc.
The proper way is to modify table structure, divide rows, check results and put correct values in correct name columns. Now you have lists which are hard to search and every method may return wrong results.
No need for PL/SQL.
SQL> with temp as
2 (select id,
3 regexp_substr(name, '[^;]+', 1, column_value) name
4 from employee cross join
5 table(cast(multiset(select level from dual
6 connect by level <= regexp_count(name, ';') + 1
7 ) as sys.odcinumberlist))
8 )
9 select id, name
10 from temp
11 where instr(name, '&search_for_name') > 0;
Enter value for search_for_name: Claire
ID NAME
---------- ------------------------------
2 Claire Taylor (cta02)
5 Claire Pilkington (cpt09)
SQL> /
Enter value for search_for_name: mak03
ID NAME
---------- ------------------------------
2 Mark Kites (mak03)
SQL>
What does it do?
temp CTE splits semi-colon separated values into rows
final query uses a simple instr function which detects whether "rows" (extracted previously) contain value you're looking for
If it must be a function, that code can be reused. As you didn't say what exactly (which datatype, I mean) you want to return, I returned a string.
SQL> create or replace function f_search (par_what in varchar2)
2 return sys.odcivarchar2list
3 is
4 retval sys.odcivarchar2list;
5 begin
6 with temp as
7 (select id,
8 regexp_substr(name, '[^;]+', 1, column_value) name
9 from employee cross join
10 table(cast(multiset(select level from dual
11 connect by level <= regexp_count(name, ';') + 1
12 ) as sys.odcinumberlist))
13 )
14 select id ||' - '|| name
15 bulk collect into retval
16 from temp
17 where instr(name, par_what) > 0;
18
19 return retval;
20 end;
21 /
Function created.
SQL> select * from table(f_search('Andrea'));
COLUMN_VALUE
--------------------------------------------------------------------------------
1 - Andrea Warbutton (awr01)
SQL> select * from table(f_search('Claire'));
COLUMN_VALUE
--------------------------------------------------------------------------------
2 - Claire Taylor (cta02)
5 - Claire Pilkington (cpt09)
SQL>
I'm working with PL/SQL Developer.
I'm trying to update values in a column(existing table).
The values used to populate rows should be auto incremented. The starting value is the maximum value that already exist in such field.
An example, I have the following table
ORDER_ID T_NAME T_PRICE
20 CAR 50
NULL VAN 100
NULL BIKE 10
NULL BOAT 300
After running the query I would expect the table to look like:
ORDER_ID T_NAME T_PRICE
20 CAR 50
21 VAN 100
22 BIKE 10
23 BOAT 300
The query I created so far is:
DECLARE
temp_order_id number;
BEGIN
:temp_order_id = SELECT ISNULL(MAX((ORDER_ID)),0) + 1 FROM SALES_ACC;
update SALES_ACC
set (ORDER_ID) = :temp_order_id , :temp_order_id = :temp_order_id + 1
where (ORDER_ID) is null;
END;
Oracle doesn't like assigning a value from select statement to the temp_order_id variable.
Does anyone has any idea how to fix it?
You don't need pl/sql for this - you can do it in a single update statement - eg:
create table test1 as
select 20 order_id, 'CAR' t_name, 50 t_price from dual union all
select null order_id, 'VAN' t_name, 100 t_price from dual union all
select null order_id, 'BIKE' t_name, 10 t_price from dual union all
select null order_id, 'BOAT' t_name, 300 t_price from dual;
update test1
set order_id = (select max(order_id) from test1) + rownum
where order_id is null;
commit;
select * from test1
order by 1;
ORDER_ID T_NAME T_PRICE
---------- ------ ----------
20 CAR 50
21 VAN 100
22 BIKE 10
23 BOAT 300
drop table test1;
As a side note, it sounds like order_id is something that should really be the primary key of the table - if you had that, then you wouldn't be allowed to add a row without a value. Plus, you would also need a sequence that you would then use when inserting data into the table - e.g.:
insert into test1 (order_id, t_name, t_price)
values (test1_seq.nextval, 'TRIKE', 30);
ORACLE's recomended way for this is either:
Create a sequence and a trigger on the table to assign order_id as soon as row is being inserted
or, for Oracle 12c, you can have an IDENTITY column
See How to create id with AUTO_INCREMENT on Oracle?, both approaches are described there.
Within the DECLARE ... BEGIN ... END; section you are in PL/SQL syntax. That is not equal to the SQL syntax. Within PL/SQL syntax you should make use of the so called select into statement.
SELECT ISNULL(MAX((ORDER_ID)),0) + 1
into :temp_order_id
FROM SALES_ACC
I am newbie to Oracle but have worked on mysql previously. We have migrated the database from mysql to oracle and want help in this scenario.
I have table in the oracle 10g which is in the following format:
student_id student_key student_value
---------- ----------- -------------
1 name john
2 name bill
1 age 28
2 age 26
2 result pass
now i want to create a pivot on it so i use the following query:
select student_id, decode(student_key, 'name', student_Value, null) as studentName
from student_table
the output comes as
student_id studentName
---------- -----------
1 john
1 null
2 bill
2 null
2 null
Oracle 11 has specialized PIVOT functionality (a nice introduction is here), but 10g doesn't. Here's how to do it in 10g:
SELECT
student_id,
MAX(CASE WHEN student_key = 'name' THEN student_value END) AS StudentName,
MAX(CASE WHEN student_key = 'age' THEN student_value END) AS Age,
MAX(CASE WHEN student_key = 'result' THEN student_value END) AS Result
FROM myTable
GROUP BY student_id
As with the Oracle PIVOT command, you need to know the number of output columns ahead of time.
Also note that MAX is used because we're rolling rows up to columns, which means we have to group, which means we need an aggregate function, so why not MAX? If you use MIN instead of MAX you'll get the same results.
I'm very new to oracle sql and programming and I need some help with one of my first projects. I'm working with this table schema:
Column Data Type Length Precision Scale Nullable
EMPLOYEE_ID NUMBER 22 6 0 No
START_DATE DATE 7 - - No
END_DATE DATE 7 - - No
JOB_ID VARCHAR2 10 - - No
DEPARTMENT_ID NUMBER 22 4 0 Yes
I want to display all employees who have never changed their jobs, not even once(employees not listed in the above table) This table is labeled job_history. How would I go about doing this? I'm not sure on how to get this started.
select * from employees
where employee_id not in ( select employee_id from job_history)
/
You can use a left join and check for a null employee_id on the job_history table.
select * from employees
left join job_history
on job_history.employee_id = employees.employee_id
where job_history.employee_id is NULL
Fairly often an execution plan is better for
select * from employees e where not exists
(select 1 from job_history jh.employee_id = e.employee_id)
than "not in ()".
And if the tables have the same structure the best result will with
select * from employees
minus
select * from job_history