Oracle sql select data from table where attribute is nested table - oracle

I have a objects:
create type t_history_rec is object
(
date_from date,
current float
);
create type t_history is table of t_history_rec;
and table defined:
create table person
(
id integer primary key,
name varchar2(30),
history t_history
);
and I want to get select name, history.date_from, history.current like this:
name1 date1 current1
name1 date2 current2
name2 date3 current3
...
How to do this?

Cannot verify this, but you could try something like this:
select p.name, pp.date_from, pp.current
from person p, table(p.history) pp;

You have some errors. current is reserved
create or replace type t_history_rec is object
(
date_from date,
curr float
);
/
create type t_history is table of t_history_rec;
/
Table definition needs store as
create table person
(
id integer primary key,
name varchar2(30),
history t_history
) NESTED TABLE history STORE AS col1_tab;
insert into person (id, name, history) values (1, 'aa', t_history(t_history_rec(sysdate, 1)));
insert into person (id, name, history) values (2, 'aa', t_history(t_history_rec(sysdate, 1), t_history_rec(sysdate, 1)));
Then select is:
SELECT t1.name, t2.date_from, t2.curr FROM person t1, TABLE(t1.history) t2;

Related

How to insert comma delimited values in one column in oracle?

I have a table by the name of personal_info and it contains id,name and phone_number as columns. So the following is table structure which I want to store data.
id
name
phone_number
1
ali
03434444, 03454544, 0234334
So how to store data in phone_number column in comma delimited format and how to filter that column in where clause for example
Select * from personal_info where phone_number = 03454544 ;
And which datatype is suitable for phone_number column.
Well, the real good practice would rather be to have another table PHONE with a 1xN association (for example a PHONE_ID primary key, and ID and PHONE columns.)
You may then have the result you want with a view based on your two tables and using the LISTAGG operator : https://fr.wikibooks.org/wiki/Oracle_Database/Utilisation_de_fonctions/fonction_LISTAGG, but this will be much efficient to work with, especially if you want WHERE clauses based on your phone numbers.
Use LIKE with the delimiters:
Select *
from personal_info
where ', ' || phone_number || ', ' LIKE '%, ' || '03454544' || ', %';
However
You should consider changing your data structure to store the phone numbers in a separate table:
CREATE TABLE phone_numbers (
person_id REFERENCES personal_info (id),
phone_number VARCHAR2(12)
);
And then you can get the data using a JOIN
SELECT pi.*,
pn.phone_number
FROM personal_info pi
INNER JOIN phone_numbers pn
ON (pi.id = pn.person_id)
WHERE pn.phone_number = '03434444'
or, if you want all the phone numbers:
SELECT pi.*,
pn.phone_numbers
FROM personal_info pi
INNER JOIN (
SELECT person_id,
LISTAGG(phone_number, ', ') WITHIN GROUP (ORDER BY phone_number)
AS phone_numbers
FROM phone_numbers
GROUP BY person_id
HAVING COUNT(CASE WHEN phone_number = '03434444' THEN 1 END) > 0
) pn
ON (pi.id = pn.person_id)
db<>fiddle here
VARCHAR2 is suitable for phone numbers.
You can get the values this way:
WITH personal_info AS
(
SELECT 1 AS ID, 'Ali' AS NAME, '03434444, 03454544, 0234334' AS phone_number FROM dual
)
SELECT *
FROM (SELECT id, name, TRIM(regexp_substr(phone_number, '[^,]+', 1, LEVEL)) AS phone_number
FROM personal_info
CONNECT BY LEVEL <= LENGTH (phone_number) - LENGTH(REPLACE(phone_number, ',' )) + 1)
WHERE phone_number = '03454544';
Wrong data model, it isn't normalized. You should create a new table:
create table phones
(id_phone number constraint pk_phone primary key,
id_person number constraint fk_pho_per references person (id_person),
phone_number varchar2(30) not null
);
Then you'd store as many numbers as you want, one-by-one (row-by-row, that is).
If you want to do it your way, store it just like that:
insert into person (id, name, phone_number)
values (1, 'ali', '03434444, 03454544, 0234334');
One option of querying such data is using the instr function:
select * from person
where instr(phone_number, '03434444') > 0;
or like:
select * from person
where phone_number like '%'% || '03434444' || '%'
or split it into rows:
select * from person a
where '03434444' in (select regexp_substr(b.phone_number, '[^,]+', 1, level)
from person b
where b.id_person = a.id_person
connect by level <= regexp_count(b.phone_number, ',') + 1
)
I'd do it my way, i.e. with a new table that contains only phone numbers.

Convert String List to Number in Oracle DB

I am saving table ids as foreign key into another table using Oracle Apex Shuttle field like(3:4:5). Now I want to use these IDS in sql query using IN Clause. I have replaced : with , using replace function but it shows
no data found
message.
The following query works fine when I use static values.
select * from table where day_id IN(3,4,5)
But when I try to use
select * from table where id IN(Select id from table2)
it shows no data found.
From what i understand you have a list like 1:2:3:4 that you want to use in a IN clause; you can transform the list into separated values like this:
select regexp_substr('1:2:3:4','[^:]+', 1, level) as list from dual
connect by regexp_substr('1:2:3:4', '[^:]+', 1, level) is not null;
This will return:
List
1
2
3
4
Then you can simply add it to your query like this:
SELECT *
FROM TABLE
WHERE day_id IN
(SELECT regexp_substr('1:2:3:4','[^:]+', 1, level) AS list
FROM dual
CONNECT BY regexp_substr('1:2:3:4', '[^:]+', 1, level) IS NOT NULL
);
Can you try below statement. It has working as you expected.
create table table1 (id number, name varchar2(20));
alter table table1 add constraints pri_cons primary key(id);
create table table2 (id number, name varchar2(20));
alter table table2 add constraints ref_cons FOREIGN KEY(id) REFERENCES table1 (id);
begin
insert into table1 values (1,'Bala');
insert into table1 values (2,'Sathish');
insert into table1 values (3,'Subbu');
insert into table2 values (1,'Nalini');
insert into table2 values (2,'Sangeetha');
insert into table2 values (3,'Rubini');
end;
/
select * from table1 where id IN (Select id from table2);

Return all null values between two dates

I have the following query and I need it to return all the null values between those two dates.
select cust_first_name
from customers
join orders using(customer_id)
where order_date between (to_date('01-01-2007','DD-MM-YYYY'))
and (to_date('31-12-2008','DD-MM-YYYY'));
Sounds like what you want is customers with no orders within the given date range. The join you are using finds the opposite of that.
You could do this with an outer join, in which case you need to apply the date filter prior to the join. It's probably easier and more readable to use a NOT IN or NOT EXISTS subquery:
select cust_first_name
from customers
WHERE customers.customer_id NOT IN (
SELECT orders.customer_id from orders
where order_date between (to_date('01-01-2007','DD-MM-YYYY'))
and (to_date('31-12-2008','DD-MM-YYYY'))
)
Here is an example of how to do what you want.
The key part is doing a left join on your orders table, and then simply doing a not between date1 and date2
declare #customers table (
id int identity(1,1),
first_name nvarchar(50),
last_name nvarchar(50)
)
declare #orders table (
id int identity(1,1),
customer_id int,
order_date datetime
)
insert into #customers(first_name, last_name) values ('bob', 'gates')
insert into #customers(first_name, last_name) values ('cyril', 'smith')
insert into #customers(first_name, last_name) values ('harry', 'potter')
insert into #orders(customer_id, order_date) values (1, '2007-02-01')
insert into #orders(customer_id, order_date) values (2, '2015-02-15')
insert into #orders(customer_id, order_date) values (3, '2008-02-15')
select
customers.id
,customers.first_name
,customers.last_name
from #customers customers
left join #orders orders on orders.customer_id = customers.id
where orders.id is null
or orders.order_date not between ('2007-01-01') and ('2008-12-31')
group by
customers.id
,customers.first_name
,customers.last_name;

How do I quickly load a complex collection with nested tables in PL/SQL

Let's say I have a collection that contains nested tables:
CREATE TYPE address_type AS OBJECT (
address_code VARCHAR2(1),
address VARCHAR2(30),
city VARCHAR2(30),
state VARCHAR2(3),
zip VARCHAR2(10));
CREATE TYPE addresses_type AS TABLE OF address_type;
-- You can see here that the person may have multiple addresses (addrs)
CREATE TYPE person_type AS OBJECT (
personID NUMBER,
name VARCHAR2(30),
birthdate DATE,
gender VARCHAR2(1),
addrs addresses_type);
CREATE TYPE people_type as TABLE OF person_type;
If I had a PLSQL block and I wanted to create and load an object of people with their address from the tables below, what is the easiest way to do this? Would I have to perform multiple queries?
DECLARE
the_people people_type;
BEGIN
-- want to Query and load "the_people" with everybody in the tables below:
..
END;
Tables: Foreign key is PERSON_ID
PERSON
------
PERSON_ID
NAME
BIRTHDATE
GENDER
ADDRESSES
---------
PERSON_ID
ADDRESS_CODE
ADDRESS
CITY
STATE
ZIP
You can do it in one query:
CREATE TABLE person (
person_ID NUMBER,
name VARCHAR2(30),
birthdate DATE,
gender VARCHAR2(1)
);
CREATE TABLE addresses (
person_id NUMBER,
address_code VARCHAR2(1),
address VARCHAR2(30),
city VARCHAR2(30),
state VARCHAR2(3),
zip VARCHAR2(10)
);
INSERT INTO person VALUES (1, 'Brown', SYSDATE, 'M');
INSERT INTO person VALUES (2, 'Smith', SYSDATE, 'M');
INSERT INTO addresses VALUES (1, 'A', 'B', 'C', 'D', '1');
INSERT INTO addresses VALUES (1, 'A', 'BB', 'CC', 'DD', '1');
INSERT INTO addresses VALUES (2, 'B', 'E', 'F', 'G', '1');
COMMIT;
DECLARE
the_people people_type;
BEGIN
SELECT
person_type(
person_id,
name,
birthdate,
gender,
(SELECT CAST(MULTISET (
SELECT
address_code,
address,
city,
state,
zip
FROM addresses
WHERE person_id = p.person_id) AS addresses_type
)
FROM dual
)
)
BULK COLLECT INTO the_people
FROM
person p
;
dbms_output.put_line(the_people.COUNT);
dbms_output.put_line(the_people(1).name);
dbms_output.put_line(the_people(1).addrs(1).address);
dbms_output.put_line(the_people(1).addrs(2).address);
dbms_output.put_line(the_people(2).name);
dbms_output.put_line(the_people(2).addrs(1).address);
END;
Sample output produced by the block to test if the solution works:
2
Brown
B
BB
Smith
E

select values from table and create oracle objects

i want to insert values to oracle Object type by selecting values from other table
And the tables and insert statement looks like this.
CREATE TYPE Test_obj AS OBJECT (
attr1 VARCHAR2(20),
attr2 VARCHAR2(20),
attr3 VARCHAR2(25) );
/
CREATE TABLE resultrow_obj (
resultrow Test_obj ,
RESULTTABLEID NUMBER(20,0),
ROWNUMBER NUMBER(20,0) );
/
INSERT INTO resultrow_obj VALUES (
Test_obj (select col1,col2,col3 from Table2 where rownum<=1),
1,123 );
/
You've got it nearly right:
SQL> INSERT INTO resultrow_obj
2 VALUES((SELECT Test_obj('A', 'B', 'C')
3 FROM dual WHERE rownum <= 1),
4 1, 123);
1 row inserted

Resources