ORACLE SQL - Count - sql

I have the following schema in Oracle DB:
create table DVD (
dvdID char(25) not null,
datePurchased DATE not null,
filmID char(25) not null,
PRIMARY KEY (dvdID),
FOREIGN KEY (filmID) REFERENCES Film(filmID)
);
create table MonthlyStatement(
customerID char(25) not null,
dvdID char(25) not null,
dateHired DATE not null,
dateReturned DATE,
PRIMARY KEY (dvdID, customerID, dateHired),
FOREIGN KEY (customerID) REFERENCES Customer(customerID),
FOREIGN KEY (dvdID) REFERENCES DVD(dvdID)
);
insert into MonthlyStatement values ('0001','0005','06-oct-2015',null);
insert into MonthlyStatement values ('0001','0006','06-oct-2015','11-oct-2015');
insert into MonthlyStatement values ('0002','0002','02-sep-2015','12-sep-2015');
insert into MonthlyStatement values ('0002','0003','02-sep-2015','12-sep-2015');
insert into MonthlyStatement values ('0003','0018','06-oct-2015','12-oct-2015');
insert into MonthlyStatement values ('0004','0041','02-oct-2015','09-oct-2015');
I have the following description to make a query for:
List all DVDs that were hired in October 2015 (including those that were not returned in October). For each DVD, list its unique number and the number of times it was hired. Sort the DVDs in ascending order of DVD numbers.
How do I solve this?

Try like this
select * from DVD
inner join MonthlyStatement on DVD.dvdID =MonthlyStatement.dvdID
where to_char(MonthlyStatement.dateHired,'Mon-YYYY')='Oct-2015'
order by DVD.dvdID
COUNT
select DVD.dvdID,DVD.datePurchased,DVD.filmID,Count(MonthlyStatement.dateHired) from DVD
inner join MonthlyStatement on DVD.dvdID =MonthlyStatement.dvdID
where to_char(MonthlyStatement.dateHired,'Mon-YYYY')='Oct-2015'
group by DVD.dvdID,DVD.datePurchased,DVD.filmID
order by DVD.dvdID

There are multiple issues.
'06-oct-2015'
Firstly, '06-oct-2015' is not a DATE, it is a string. Both are different. You must always use TO_DATE to explicitly convert a literal into DATE with proper FORMAT MODEL.
TO_DATE is NLS dependent. So, you need to take care of the NLS parameters at individual statement level. You could do it at session too.
TO_DATE('06-oct-2015','dd-mon-yyyy','nls_date_language=american')
When dealing with only date element, i.e. without time element, I prefer the ANSI Date literal which follows a fixed format YYYY-MM-DD and therefore it is NLS independent:
DATE '2015-10-06'
dvdID char(25)
The CHAR datatype stores fixed-length character strings. String values will be space-padded before being stored on disk which is an inefficient way. It is much more efficient to use the VARCHAR2 data type when storing variable-length strings.
List all DVDs that were hired in October 2015 (including those that were not returned in October).
It is a simple join of the two tables, and a filter predicate on the dateHired column:
where to_char(MonthlyStatement.dateHired,'Mon-YYYY','nls_date_language=american')='Oct-2015'
Remember, using TO_CHAR would suppress any regular index on the column. Either use a function-based index or better use a date_range condition for better performance which will use the regular index.

Related

How do I insert a subquery with multiple results into multiple rows?

I want to add the results of a query into a table. There are multiple values, being inserted into multiple rows that are currently NULLS.
I have the following tables:
CREATE TABLE CAR (
CarID INT NOT NULL PRIMARY KEY,
Make VARCHAR (30) NOT NULL,
Model VARCHAR (30) NOT NULL,
Type VARCHAR (30) NOT NULL,
YearModel INT NOT NULL,
Price VARCHAR (100) NOT NULL,
);
CREATE TABLE [TRANSACTION] (
tID INT NOT NULL PRIMARY KEY,
cID INT NOT NULL FOREIGN KEY REFERENCES CUSTOMER(CID),
CarID INT NOT NULL FOREIGN KEY REFERENCES CAR(CARID),
eID INT NOT NULL FOREIGN KEY REFERENCES EMPLOYEE(EID),
tDate DATE,
PickupDate DATE NOT NULL,
ReturnDate DATE NOT NULL
);
I then had to add a new column:
ALTER TABLE [TRANSACTION]
ADD Amount_Due int;
The following code gives me the results I need:
SELECT Price*DATEDIFF(DAY,PickupDate, ReturnDate)
FROM [TRANSACTION], CAR
WHERE [TRANSACTION].CarID = CAR.CarID
But I don't know how to insert all of the data into my Amount_Due column.
I have tried to use INSERT INTO, but it's telling me I have a syntax error near Amount_Due.
INSERT INTO [TRANSACTION] Amount_Due
SELECT Price*DATEDIFF(DAY,PickupDate, ReturnDate)
FROM CAR, [TRANSACTION]
WHERE CAR.CarID = [TRANSACTION].CarID
I have played around with INSERT INTO and UPDATE and I cannot wrap my head around what I'm doing wrong, or what I am missing.
I'm using SQL SMS 2018
Thank you for any help.
You are not inserting data you are updating existing rows, so you need to update:
update t set
t.Amount_Due = c.Price * DateDiff(day, c.PickupDate, c.ReturnDate)
from [transaction] t
join car c on c.carId=t.carId
Notes
Always use proper join syntax, avoid adding tables separated by
commas.
Also always alias your tables with meaningful short
aliases for readability.
Avoid using reserved words for objects eg
transaction - if your table contains more than 1 row then call it
transactions and avoid the need to always have to use [] to avoid
ambiguity.
SSMS is not SQL Server, SSMS is just an application used to access SQL Server. Use select ##version if you ever need to know your SQL Server version.

ORA-01858 FOR BEGINNER

CREATE TABLE Pizza
(
pizza_id DECIMAL(12) NOT NULL PRIMARY KEY,
name VARCHAR(32) NOT NULL,
date_available DATE NOT NULL,
price DECIMAL(4,2) NOT NULL
);
CREATE TABLE Topping
(
topping_id DECIMAL(12) NOT NULL,
topping_name VARCHAR(64) NOT NULL,
pizza_id DECIMAL(12)
);
ALTER TABLE Topping
ADD CONSTRAINT topping_pk PRIMARY KEY(topping_id);
ALTER TABLE Topping
ADD CONSTRAINT Topping_pizza_fk
FOREIGN KEY(pizza_id) REFERENCES Pizza(pizza_id);
INSERT INTO pizza (pizza_id, name, date_available, price)
VALUES (1, 'Plain', CAST('27-Feb-2021' AS DATE), 6);
Error:
ORA-01858: a non-numeric character was found where a numeric was expected
I cannot figure out which part is wrong, I'm just a beginner for SQL, it seems related with date, can someone help me?
This works for me: SQL Fiddle. Don't use CAST to convert strings to dates. That's the only thing that looks off about your example. It may be using a different default date format than your string. Instead use TO_DATE( '27-Feb-2021', 'DD-Mon-YYYY') which converts a string to a date, or DATE '2021-02-27', which is a date literal and only takes the yyyy-mm-dd format.
Additionally, I'd suggest using NUMBER instead of DECIMAL just because it's more standard in the Oracle world. And always use VARCHAR2 instead of VARCHAR, which is officially discouraged.

I have come across an error in SQL and cannot fix this foreign key error. See desc for more information

I have been receiving the error code 1452, i am trying to add keys to a table to keep data unqiue and useable in other tables. i have created the tables and can use the information already entered but i want to make the databases properly so i am trying to use the keys. please refer to the code below.
CREATE TABLE CUSTOMERS (
CustID varchar(50) NOT NULL,
Client_Name varchar(50) NOT NULL,
Client_Address varchar(80) NOT NULL,
PRIMARY KEY (CustID)
);
CREATE TABLE ORDERS (
Order_ID VARCHAR(10) NOT NULL,
Client_NameID varchar(50) NOT NULL,
Dates varchar(10) NOT NULL,
PRIMARY KEY (Order_ID),
FOREIGN KEY (Client_NameID) REFERENCES CUSTOMERS(CustID)
);
SELECT * FROM CUSTOMERS;
SELECT * FROM ORDERS;
DESCRIBE Orders; /*Used to display the Table*/
ALTER TABLE ORDERS ADD Dates VARCHAR(10); /*Used to add columns into the table*/
ALTER TABLE ORDERS DROP COLUMN Date; /*Used to remove column from the table*/
INSERT INTO CUSTOMERS (CustID, Client_Name, Client_Address) VALUES
('168', 'Coventry Building Services', 'Units 2-4, Binley Industrial Estate, CV3 2WL'), /*Used to insert values into the columns*/
('527', 'Allied Construction LTD', '34, Lythalls La Industrial Estate, NG18 5AH'),
('169', 'Ricoh Builds Ltd', 'Unit 12, Stoneleigh Park, CV8 2UV'),
('32', 'British Embassy in Tehran', '198 Ferdowski Avenue Tehran 11316-91144 Iran');
INSERT INTO ORDERS (Order_ID, Client_NameID, Dates) VALUES
('CON-2237', 'Coventry Building Services', '2014-12-14'),
('CON-3664', 'Allied Construction LTD', '2015-01-16'),
('CON-2356', 'Ricoh Builds Ltd', '2015-02-12'),
('CON-1234', 'British Embassy in Tehran', '2015-04-16');
DELETE FROM ORDERS WHERE Client_Name='Coventry Building Services'; /*Used to delete specific
data from the specific row and column wherever applicable*/
DROP TABLE CUSTOMERS;
DROP TABLE ORDERS;
Below are the tables im trying to work with, all of them will pretty much have a key that links them together if necessary
The CustomerS Table which only includes a Primary Key
The Orders Table which includes a Primary and Foreign key
The problem is with the inserts into table orders. Your foreign key on Client_NameIDreferencesCUSTOMERS(CustID), but you are giving the CUSTOMERS(Client_Name) instead.
You probably want:
INSERT INTO ORDERS (Order_ID, Client_NameID, Dates) VALUES
('CON-2237', 'CON-2237', '2014-12-14');
('CON-3664', 'CON-3664', '2015-01-16');
('CON-2356', 'CON-2356', '2015-02-12');
('CON-1234', 'CON-1234', '2015-04-16');
Notes:
You can perform all inserts in a single query by passing several tuples of values, as shown above
Don't store dates as strings; instead, use the date datatype, which exists for that purpose. I changed the query so it uses proper date literals, which would fit in a date column
it is unclear why you want to use the same value for the primary key of customers and orders - to me, this makes things harder to follow. I would recommend just using auto-incremented primary keys

ORA-00984 Column not allowed here with date in oracle SQL

Im inserting values into this table
CREATE TABLE Flight (
FlightNumber char(7) primary key,
ArrivalAirportCode char(6) references Airport (Airport_code),
DepartureAirportCode char(6) references Airport (Airport_code),
AircraftNumber varchar2(25) references Aircraft (AircraftNumber),
ArrivalDate date,
ArrivalTime Varchar2(5),
DepartureDate date,
DepartureTime varchar2(5)
);
and here are the values Im inserting into it
INSERT INTO FLIGHT values
('CA3048',
'LHR',
'EDI',
'N859E',
'14-NOV-2014',
'22:15',
'14-NOV-2014',
'20:15');
And I get the column not allowed here error for the 2nd date I insert, but not the first one. I've tried putting quotes around the date but I just get another error.
'14-NOV-2014'
Why are you inserting a string in a DATE column? '14-NOV-2014' is a STRING and NOT a DATE. You should not depend on implicit data type conversion.
Always, convert the string into a DATE explicitly using TO_DATE and proper format mask.
For example,
TO_DATE('14-NOV-2014','DD-MON-YYYY')
One more thing,
DepartureTime varchar2(5)
Makes no sense. You already have a DATE column, a DATE would have the time element too.
No need of a separate time column. A DATE has both date and time elements stored in 7 bytes.
Oracle stores DATE in total of 7 bytes. Each byte in it stores values for an element of the DATE as follows:
Byte Description
---- ------------------------------------------------
1 Century value but before storing it add 100 to it
2 Year and 100 is added to it before storing
3 Month
4 Day of the month
5 Hours but add 1 before storing it
6 Minutes but add 1 before storing it
7 Seconds but add 1 before storing it
All you need to do is just have 2 DATE columns:
CREATE TABLE Flight (
FlightNumber char(7) primary key,
ArrivalAirportCode char(6) references Airport (Airport_code),
DepartureAirportCode char(6) references Airport (Airport_code),
AircraftNumber varchar2(25) references Aircraft (AircraftNumber),
ArrivalDate date,
DepartureDate date
);
And then insert the values as:
INSERT INTO FLIGHT values
('CA3048',
'LHR',
'EDI',
'N859E',
TO_DATE('14-NOV-2014 22:15:00','DD-MON-YYYY HH24:MI:SS'),
TO_DATE('14-NOV-2014 20:15:00','DD-MON-YYYY HH24:MI:SS')
);
Update
As mentioned in the comments by #GriffeyDog and #a_horse_with_no_name.
Alternatively, you could also the ANSI literal instead, for example:
timestamp '2014-11-14 22:15'

PL/SQL function that returns a value from a table after a check

I am new to php and sql and I am building a little game to learn a little bit more of the latter.
This is my simple database of three tables:
-- *********** SIMPLE MONSTERS DATABASE
CREATE TABLE monsters (
monster_id VARCHAR(20),
haunt_spawn_point VARCHAR(5) NOT NULL,
monster_name VARCHAR(30) NOT NULL,
level_str VARCHAR(10) NOT NULL,
creation_date DATE NOT NULL,
CONSTRAINT monster_id_pk PRIMARY KEY (monster_id)
);
-- ****************************************
CREATE TABLE spawntypes (
spawn_point VARCHAR(5),
special_tresures VARCHAR (5) NOT NULL,
maximum_monsters NUMBER NOT NULL,
unitary_experience NUMBER NOT NULL,
CONSTRAINT spawn_point_pk PRIMARY KEY (spawn_point)
);
-- ****************************************
CREATE TABLE fights (
fight_id NUMBER,
my_monster_id VARCHAR(20),
foe_spawn_point VARCHAR(5),
foe_monster_id VARCHAR(20) NOT NULL,
fight_start TIMESTAMP NOT NULL,
fight_end TIMESTAMP NOT NULL,
total_experience NUMBER NOT NULL
loot_type NUMBER NOT NULL,
CONSTRAINT my_monster_id_fk FOREIGN KEY (my_monster_id)
REFERENCES monsters (monster_id),
CONSTRAINT foe_spawn_point_fk FOREIGN KEY (foe_spawn_point)
REFERENCES spawntypes (spawn_point),
CONSTRAINT fight_id_pk PRIMARY KEY (fight_id)
);
Given this data how can I easily carry out this two tasks:
1) I would like to create a pl/sql function that passing only a fight_id as a parameter and given the foe_spawn_point (inside the fight table) return the unitary_experience that is related to this spawn point referencing the spawntypes table, how can I do it? :-/ [f(x)]
In order to calculate the total experience earned from a fight (unitary_experience * fight_length) I have created a function that given a particular fight will subtract the fight_end with the fight_start so now I know how long the fight lasted. [f(y)]
2) is it possible to use this two functions (multiply the result that they returns) during the database population task?
INSERT INTO fights VALUES(.... , f(x) * f(y), 'loot A');
in order to populate all the total_experience entries inside the fights table?
thank you for your help
In SQL, you don't generally talk about building functions to do things. The building blocks of SQL are queries, views, and stored procedures (most SQL dialects do have functions, but that is not the place to start).
So, given a variable with $FIGHTID you would fetch the unitary experience with a simple query that uses the join operation:
select unitary_experience
from fight f join
spawnTypes st
on st.spawn_point = f.foe_spawn_point
where fightid = $FIGHTID
If you have a series of values to insert, along with a function, I would recommend using the select form of insert:
insert into fights(<list of columns, total_experience)
select <list of values>,
($FIGHT_END - $FIGHT_START) * (select unitary_experience from spawnTypes where spawnType ='$SPAWN_POINT)
One comment about the tables. It is a good idea for all the ids in the table to be integers that are auto-incremented. In Oracle you do this by creating a sequence (and it is simpler in most other databases).