Using joins in complex queries - sql

I have three tables customer_cars, bookings, and replaced_parts ad below:
CREATE TABLE customer_cars(
pk_car_id NUMBER(11) NOT NULL,
car_plate_number VARCHAR2(15) NOT NULL
);
CREATE TABLE bookings(
pk_booking_id NUMBER(11),
fk_car_id NUMBER(11),
);
CREATE TABLE replaced_parts(
pk_parts_id VARCHAR2(25),
fk_booking_id NUMBER(11),
replaced_parts parts_varray_type
);
CREATE OR REPLACE TYPE parts_type AS OBJECT (
name VARCHAR2(25),
price NUMBER(10),
);
/
CREATE TYPE parts_varray_type AS
VARRAY(40) OF parts_type;
/
I am trying to get parts name from parts_varray_type of a car. All i have is car_plate_number. Using this plate number i want to find pk_car_id in customer_cars and then that pk_car_if id should match with fk_car_id in bookings to find bookings_id. Then the found booking id should match with fk_booking_id in replaced_parts to get the parts_name.
INSERT INTO customer_cars (pk_car_id, car_plate_number)
VALUES(200000,'5651L');
INSERT INTO bookings(pk_booking_id, fk_car_id)
VALUES(700000,200000);
INSERT INTO replaced_parts (pk_parts_id, fk_booking_id, replaced_parts)
VALUES(700000,600000,
parts_varray_type(
parts_type('CLUTCH', 2000)));
Above is the insert statements. Now using plate number '5651L' i want to display clutch , 2000 from parts parray type.
Something like:
SELECT..
FROM..(Usings joins or any other methods)
WHERE pk_car_id = '5651L';
It should display name and price from parts varray type.

Related

No row selected

SQL> create table artwork
2 (
artwork_id number(7) NOT NULL,
barcode char(20),
title char(20),
description char(50),
PRIMARY KEY (artwork_id)
);
Table created.
SQL> select * from artwork;
no rows selected
I created the table but it showing me this error dont know. Why table it not showing?
I would expect the create to look like this:
create table artwork (
artwork_id number primary key,
barcode char(20),
title varchar2(20),
description varchar2(50)
);
Notes:
There is no need to have number(7). You can specify the length, but it is not necessary.
For title and description you definitely want varchar2(). There is no reason to store trailing spaces at the end of a name.
That may be the same for barcode, but because it might always be exactly 20 characters or trailing spaces might be significant, you might leave it as char().
The primary key constraint can be expressed in-line. There is no need for a separate declaration.
You probably simply want something like
create table artwork
(
artwork_id number(7) NOT NULL,
barcode varchar2(20),
title varchar2(20),
description varchar2(50),
PRIMARY KEY (artwork_id)
);
insert into artwork values (0, 'barcode', 'fancytitle', 'somedescription');
insert into artwork values (1, 'barcode1', 'fancytitle1', 'somedescription1');
select * from artwork;
This creates a table "ARTWORK", inserts 2 rows in it and then selects all rows currently in the table.
An empty table contains no data, with the create table-statement you only define the bucket of data, you have to fill the bucket as well with items.
I'd also recommend a auto increment column (oracle 12c) or a trigger/sequence to increment the id automatically. But that's something to read later :)

Can I use a PL/SQL trigger to check category and concat to a incremental number based on category?

I got a productID - P0001KTC and P0001DR.
If product category is kitchen, I will assign a productID - PROD001KTC, else if the category is dining room, then the productID should be PROD001DR.
Is it possible to write a sequence inside a trigger to check the product category and assign an id as mentioned above?
if there is another living room category product inserted then the id will be PROD001LR.
Kitchen - PROD001KTC,PROD002KTC...
Dining Room - PROD001DR,PROD002DR....
Living Room - PROD001LR,PROD002LR...
P0001KTC is the sort of smart key users love and developers hate. But the customer is king, so here we are.
The customer's requirement is to increment the numeric element within the product category, so that the same number is used for different categories: P0001KTC , P0001DR , P0002KTC, P0001LR, P0002LR, etc. A monotonically increasing sequence cannot do this.
The best implementation is a code control table, that is a table to manage the assigned numbers. Such an approach entails pessimistic locking, which serializes access to a Product Category (e.g. KTC). Presumably the users won't be creating new Products very often, so the scaling implications aren't severe.
Working PoC
Here's our reference table:
create table product_categories (
product_category_code varchar2(3) not null
, category_description varchar2(30) not null
, constraint product_categories_pk primary key (product_category_code)
)
/
create table product_ids (
product_category_code varchar2(3) not null
, last_number number(38) default 0 not null
, constraint product_ids_pk primary key (product_category_code)
, constraint product_ids_categories_fk foreign key (product_category_code)
references product_categories (product_category_code)
) organization index
/
May these two tables could be one table, but this implementation offers greater flexibility. Let's create our Product Categories:
insert all
into product_categories (product_category_code, category_description)
values (cd, descr)
into product_ids (product_category_code)
values (cd)
select * from
( select 'KTC' as cd, 'Kitchen' as descr from dual union all
select 'LR' as cd, 'Living Room' as descr from dual union all
select 'DR' as cd, 'Dining Room' as descr from dual )
/
Here's the target table:
create table products (
product_id varchar2(10) not null
, product_category_code varchar2(3) not null
, product_description varchar2(30) not null
, constraint products_pk primary key (product_id)
, constraint products_fk foreign key (product_category_code)
references product_categories (product_category_code)
)
/
This function is where the magic happens. The function formats the new Product ID. It does this by taking out a pre-emptive lock on the row for the assigned Category. These locks are retained for the length of the transaction i.e. until the locking session commits or rolls back. So if there are two users creating Kitchen Products one will be left hanging on the other: this is why we generally try to avoid serializing table access in multi-user environments.
create or replace function get_product_id
( p_category_code in product_categories.product_category_code%type)
return products.product_id%type
is
cursor lcur (p_code varchar2)is
select last_number + 1
from product_ids
where product_category_code = p_code
for update of last_number;
next_number product_ids.last_number%type;
return_value products.product_id%type;
begin
open lcur( p_category_code);
fetch lcur into next_number;
if next_number > 999 then
raise_application_error (-20000
, 'No more numbers available for ' || p_category_code);
else
return_value := 'PROD' || lpad(next_number, 3, '0') || p_category_code;
end if;
update product_ids t
set t.last_number = next_number
where current of lcur;
close lcur;
return return_value;
end get_product_id;
/
And here's the trigger:
create or replace trigger products_ins_trg
before insert on products
for each row
begin
:new.product_id := get_product_id (:new.product_category_code);
end;
/
Obviously, we could put the function code in the trigger body but it's good practice to keep business logic out of triggers.
Lastly, here's some test data...
insert into products ( product_category_code, product_description)
values ('KTC', 'Refrigerator')
/
insert into products ( product_category_code, product_description)
values ('DR', 'Dining table')
/
insert into products ( product_category_code, product_description)
values ('KTC', 'Microwave oven')
/
insert into products ( product_category_code, product_description)
values ('DR', 'Dining chair')
/
insert into products ( product_category_code, product_description)
values ('DR', 'Hostess trolley')
/
insert into products ( product_category_code, product_description)
values ('LR', 'Sofa')
/
And, lo!
SQL> select * from products
2 /
PRODUCT_ID PRO PRODUCT_DESCRIPTION
---------- --- ------------------------------
PROD001KTC KTC Refrigerator
PROD001DR DR Dining table
PROD002KTC KTC Microwave oven
PROD002DR DR Dining chair
PROD003DR DR Hostess trolley
PROD001LR LR Sofa
6 rows selected.
SQL>
Note that modelling the smart key as a single column is a bad idea. It is better to build it as a composite key, say unique (product_category, product_number), where product_number is generated from the code control table above. We still need the product_id for display purposes, but it should be derived from the underlying columns. This is easy using virtual columns, like this:
create table products (
product_id varchar2(10)
generated always as 'PROD' || to_char(product_no,'FM003') || product_category_code;
, product_category_code varchar2(3) not null
, product_no number not null
, product_description varchar2(30) not null
, constraint products_pk primary key (product_id)
, constraint products_uk unique (product_category_code, product_no)
, constraint products_fk foreign key (product_category_code)
references product_categories (product_category_code)
)
/
The image shows a different format for productid than what you write in the question. I will assume you want the "PROD" prefix as in the image, and that you can deal with changing those characters in the solution below, if needed.
Also, you write twice the same number (001) in the question, yet in the image, and in the comments you provided, you indicate the numbering should increment always. So this solution will have an always incrementing number.
Proposed Solution
You should store the incremental number separately, and have that as the real id.
The formatted productID could then be a derived column. Since Oracle 11g R1 you can create virtual columns in a table, so you don't really need a trigger for that:
Here is an example script, which creates the table and the sequence:
create table products (
id number not null,
category varchar2(100),
productid as (
'PROD'||
to_char(id, 'FM000') ||
case category when 'Kitchen' then 'KTC'
when 'LivingRoom' then 'LR'
else '???'
end ) virtual,
constraint pk_product_id primary key (id),
);
-- create sequence for inserting incremental id value
create sequence product_seq start with 1 increment by 1;
You insert data like this, without specifying values for the virtual productid column:
-- Insert data
insert into products (id, category) values (product_seq.nextval, 'Kitchen');
insert into products (id, category) values (product_seq.nextval, 'LivingRoom');
And when you select data from the table:
select * from products
You get:
ID | CATEGORY | PRODUCTID
---+------------+-----------
1 | Kitchen | PROD001KTC
2 | LivingRoom | PROD002LR
Note that you'll get into trouble if your id surpasses 999, as then the 3-digit format will not work any more. Oracle will then generate ### for the to_char result, so you'll run into duplicate productid values soon.
If you have many more categories than those two (Kitchen & LivingRoom), then you should not extend the earlier mentioned case statement with those values. Instead you should create a reference table for it (let's call it categories), with values like this:
Code | Name
-----+---------------
KTC | Kitchen
LR | Living Room
... | ...
Once you have that table, where Code should be unique, you can just store the code in the products table, not the description:
create table products (
id number not null,
category_code varchar2(10),
productid as (
'PROD'||
to_char(id, 'FM000') ||
category_code) virtual,
constraint pk_product_id primary key (id),
constraint fk_product_category foreign key (category_code)
references catgories(code)
);
You would insert values like this:
insert into products (id, category_code) values (product_seq.nextval, 'KTC');
insert into products (id, category_code) values (product_seq.nextval, 'LR');
And when you want to select data from the table with the category names included:
select product.productid, categories.name
from products
inner join categories on product.category_code = categories.code

Creating a view between two tables in SQL

I'm having trouble creating a view between two tables, as I'm quite new to SQL. I need to create a view which will show which employees have carried out work as consultants within the past 14 days. The result of the view should also display this kind of layout:
14 day consultancy report
-----------------------------------------------
Employee Helvin Paul worked for 6 hours for factory ltd chargeable £351
The two tables I assume you will need to join together are the Employee table and also the Consultancy table. I will show both below as I have them in a text file from when I was creating these tables:
create table Funtom_employee
(
emp_ID Number(3) primary key,
Emp_firstname varchar2(50) not null,
Emp_surname varchar2(50),
Emp_department Number(2) constraint FK_funtom_dept references
funtom_department,
emp_street varchar2(50),
emp_town varchar2(50),
emp_district varchar2(50),
Emp_grade Number(3) default 4 constraint chk_emp_grd check (Emp_grade between 1 and 9),
Emp_site varchar2(30) default 'LONDON',
constraint FK_funtom_grade funtom_grade references funtom_department
);
create table Funtom_consultancy
(
consultancy_ID Number(3) primary key,
Consultancy_emp Number(3) constraint cns_emp references funtom_employee,
Consultancy_hours Number(4,2) constraint consultancy_check check (Consultancy_hours > 1),
Consultancy_client Number(3) references funtom_customer,
Consultancy_date DATE,
Consultancy_activity Number(3) references funtom_activity
);
Thanks to anyone that can help with this create view and for your time
A view can be created using the CREATE VIEW statement. An example based on your data is listed below.
CREATE VIEW consultancy_report as
select
Funtom_employee.Emp_firstname,
Funtom_consultancy.Consultancy_date,
from
Funtom_employee
join Funtom_consultancy
on Funtom_employee.emp_id = Funtom_consultancy.Consultancy_emp
You can add whatever other fields you need from either table in the select clause of the query. I've demonstrated one field from both tables.
If you want output explicitly as listed in your sample, you will need to concatenate several fields together as one string. Since this feels like a homework question, I will leave that as an exercise for you.

ORA-00936: missing expression error when inserting values

I spend lot of time searching where i made the mistake but i was unable to find it when its going to insert the last record there is a error message showing "ORA-00936: missing expression" How to solve this please help me
create type pearson_types as object(
name varchar2(50),
sysID char(6)
)NOT FINAL;
create type doctor_types under pearson_types(
regNo char(10),
specialization varchar2(25)
)
create table doctor of doctor_types(
regNo primary key
)
create type hospVisits_types as object(
hosChg float,
vDate varchar2(20),
refDoc REF doctor_types,
docChg float
)
create type hospvisits_tbl_types as table of hospVisits_types
create type phone_arr as VARRAY(3) of char(10)
create type patient_types under pearson_types
(
id char(10),
dob varchar(20),
phone phone_arr,
hospVisits hospvisits_tbl_types
)
create table patients of patient_types(
id primary key
)nested table hospVisits store as Hospital_tables
alter table Hospital_tables add scope for (refDoc) is doctor
insert into doctor values ('Dr.k.perera','D001','1223441234','Gynecologist');
insert into doctor values ('Dr.p.weerasingha','D002','1234421131','Dermatalogist');
insert into doctor values ('Prof .S. Fernando','D003','2342111322','Pediatrician');
insert into doctor values ('Dr.k.Sathgunanathan','D004','2344114344','Pediatrician');
insert into patients values('Sampath Weerasingha','P001','732821122V','23-JAN-73',phone_arr('0332124222'),hospvisits_tbl_types(hospVisits_types(50.00,'24-MAY-06',select ref (a) from doctor a where a.regNo='1223441234',500.00)))
Add parentheses to SELECT statements inside a SQL statement:
insert into patients values(
'Sampath Weerasingha','P001','732821122V','23-JAN-73',phone_arr('0332124222'),
hospvisits_tbl_types(hospVisits_types(50.00,'24-MAY-06',
( -- ADD ME
select ref (a) from doctor a where a.regNo='1223441234'
) -- ADD ME
,500.00))
);

How to CREATE TABLE with disjoint relationship in SQL

I am trying to create a table using a disjoint subtype relationship.
For example, if the Supertype is furniture, and I have 3 Subtypes of furniture: chair, couch, and table.
Then:
CREATE TABLE Furniture
(order_num NUMBER(15), desc VARCHAR2(20), type VARCHAR2(10));
How do I make an option to pick type of chair, couch or table?
You can use REFERENCES in the CREATE TABLE.
CREATE TABLE Furniture_SubTypes
(
sub_type VARCHAR(10) PRIMARY KEY
);
INSERT INTO Furniture_SubTypes VALUES ('Chair');
INSERT INTO Furniture_SubTypes VALUES ('Couch');
INSERT INTO Furniture_SubTypes VALUES ('Table');
CREATE TABLE Furniture
(
order_num NUMBER,
description VARCHAR(20),
sub_type REFERENCES Furniture_SubTypes(sub_type)
);
Use a check constraint:
CREATE TABLE Furniture (
order_num NUMBER(15),
description VARCHAR2(20),
type VARCHAR2(10),
check (type in ('chair', 'couch', 'table'))
);
Note that desc is a poor choice for a column name, because it is a keyword in SQL (used for order by).