Select queries joins or group by - oracle

I have 3 tables and I want to make a select statement and show patient first name and bill status and method how he paid and the amount he paid, but I am having a hard time trying to make that query.
```` Create table patient (
```` Patient_ID Number(9) primary key,
```` First_name varchar2(15),
```` Last_name varchar2(10),
```` Contact number(10),
```` City varchar2(20),
```` Doctor_ID Number(9) references Doctor(Doctor_ID));
This is the payment table
````Payment_ID Number(9) primary key,
````Amount Number(10),
````Pyt_Date Date,
````Method varchar2(15),
````PatientID Number(9) references Patient(Patient_ID));
This is the bill table
````Bill_ID Number(9) primary key,
````Status char(10),
````Amount_paid varchar(30),
````Amount_NotPaid varchar(30),
````PatientID Number(9) references Patient(Patient_ID));
This is the query I wrote but it's not working
```` select p.First_name "Patient", Status, method, Amount_paid
```` from patient p and payment on bill
```` where p.Firstname = status, method = amount_paid
```` group by p.First_name, status, method, amount_paid;

The query you wrote is not syntactically valid. You wrote:
select p.First_name "Patient", Status, method, Amount_paid
from patient p and payment on bill
where p.Firstname = status, method = amount_paid
group by p.First_name, status, method, amount_paid
You've got an AND in the FROM clause where it's not allowed, and you're missing an AND in the WHERE clause where it's needed:
select p.First_name "Patient", b.Status, b.method, b.Amount_paid
from patient p,
bill b
where p.Firstname = b.status AND
b.method = b.amount_paid
group by p.First_name, b.status, b.method, b.amount_paid
But I really doubt that's going to do what you want as I doubt very much that the billing method will match the amount paid, or that the patient's first name will match the billing status.
Perhaps what you meant was
SELECT p.FIRST_NAME, b.STATUS, y.METHOD, b.AMOUNT_PAID
FROM PATIENT p
INNER JOIN BILL b
ON b.PATIENTID = p.PATIENT_ID
INNER JOIN PAYMENT y
ON y.PATIENTID = p.PATIENT_ID
It would help if you'd edit your question to include example data for each table, and the results you'd expect from the sample data. Thanks.

Related

Oracle : It give a error in a dynamic view

I have two table one is employee and one is department. I am creating the dynamic view that will rank all departments by salary. The view should pull information from Department and Employee, sum the salary by department, and rank the department by salary.
CREATE TABLE DEPARTMENT
(DEPARTMENT_ID NUMBER PRIMARY KEY,
DEPARTMENT_NAME VARCHAR(30) NOT NULL
);
CREATE TABLE JOBS
(JOB_ID NUMBER PRIMARY KEY,
JOB_TITLE VARCHAR(35) NOT NULL,
MIN_SALARY DECIMAL NOT NULL,
MAX_SALARY DECIMAL NOT NULL
);
CREATE TABLE EMPLOYEES
(EMPLOYEE_ID NUMBER PRIMARY KEY,
FIRST_NAME VARCHAR(20) NOT NULL,
LAST_NAME VARCHAR(25) NOT NULL,
EMAIL VARCHAR(25) NOT NULL,
PHONE_NUMBER VARCHAR(20) NOT NULL,
HIRE_DATE DATE NOT NULL,
JOB_ID NUMBER NOT NULL,
SALARY DECIMAL NOT NULL,
DEPARTMENT_ID NUMBER NOT NULL,
CONSTRAINT emp_job_fk FOREIGN KEY(JOB_ID) REFERENCES JOBS(JOB_ID),
CONSTRAINT emp_department_fk FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENT(DEPARTMENT_ID)
);
INSERT INTO DEPARTMENT (DEPARTMENT_ID,DEPARTMENT_NAME)
VALUES(1,'IT');
INSERT INTO DEPARTMENT (DEPARTMENT_ID,DEPARTMENT_NAME)
VALUES(2,'Sales');
INSERT INTO JOBS (JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES (1,'IT Administrator',250000.00,50000.00);
INSERT INTO JOBS (JOB_ID,JOB_TITLE,MIN_SALARY,MAX_SALARY)
VALUES (2,'Salesman',200000.00,40000.00);
Here is I create so far but it give me a error
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 4 Column: 9
Here is my code
select department_id,department_name,total_salary
from(
select department_id,department_name, SALARY, count(*) as total_salary from(
select dep.department_id , dep.department_name ,emp.SALARY,
DENSE_RANK() OVER (PARTITION BY department_name ORDER BY salary)
from departments dep
inner join employees emp on dep.DEPARTMENT_ID = emp.DEPARTMENT_ID
)
GROUP BY SALARY)
Your query needs to join EMPLOYEES (to get the salaries) to DEPARTMENT (to get the DEPARTMENT_NAME). Calculate the total salary for each department by summing the employee salaries, not counting them. The GROUP BY needs to include the non-aggregated columns.
Then you need to rank the departments by the total salary per department. This query ranks the departments with highest salary = 1. It uses a left join to cater for departments with no employees.
select department_id
, department_name
, total_salary
, rank() over (order by total_salary desc) as dept_rank
from (
select d.department_id
, d.department_name
, sum(e.SALARY) as total_salary
from department d
left join employees e
on e.department_id = d.department_id
group by d.department_id
, d.department_name
)
/

SQL Oracle Select, Count, and Inner Join

Having issues creating a query that displays the customerID, customerFirName, and customerZip from the customers table, based on when the customer has purchased more than one vehicle within the sales table. Here are the table creations:
CREATE TABLE CUSTOMERS
(customerID INT PRIMARY KEY,
customerFirName VARCHAR(20) NOT NULL,
customerLasName VARCHAR(20) NOT NULL,
customerMiName VARCHAR(1) NOT NULL,
customerStreet VARCHAR(40) NOT NULL,
customerState VARCHAR(15) NOT NULL,
customerCity VARCHAR(20) NOT NULL,
customerZip VARCHAR(15) NOT NULL);
CREATE TABLE SALES
(saleID INT PRIMARY KEY,
grossSalePrice DECIMAL(9,2),
vehicleStatus VARCHAR(10) NOT NULL CHECK (lower(vehicleStatus) IN ('available', 'sold', 'pending')),
saleDate DATE,
saleMileage INT,
customerID INT,
salespersonID INT,
vehicleVIN VARCHAR(25),
CONSTRAINT SALES_FK1 FOREIGN KEY (customerID) REFERENCES CUSTOMERS(customerID);
Here is the desired output:
customerID customerFirName customerZip Number_of_Sales
1 Bob 12345 2
2 Jim 94949 3
3 Tom 99330 4
Here is what I've tried....I'm having issues creating a single SELECT statement that has an inner join to combine the SALES.customerID field on the CUSTOMERS.customerID field. Where am I going wrong? Thanks!
SELECT CUSTOMERS.customerFirName, CUSTOMERS.CustomerID, CUSTOMERS.customerZip, COUNT(SALES.customerID)
FROM CUSTOMERS
INNER JOIN SALES ON CUSTOMERS.customerID=SALES.customerID
GROUP BY SALES.customerID
HAVING COUNT(SALES.customerID) > 1;
AND
SELECT COUNT (CUSTOMERS.customerID), customerFullName, customerZip
FROM CUSTOMERS
INNER JOIN SALES ON CUSTOMERS.customerID=SALES.customerID
GROUP BY SALES.customerID
HAVING COUNT(SALES.customerID) > 1;
I guess the issus is on group by field.
SELECT CUSTOMERS.customerFirName, CUSTOMERS.CustomerID, CUSTOMERS.customerZip,
COUNT(SALES.customerID)
FROM CUSTOMERS
INNER JOIN SALES ON CUSTOMERS.customerID=SALES.customerID
GROUP BY CUSTOMERS.customerFirName, CUSTOMERS.CustomerID, CUSTOMERS.customerZip
HAVING COUNT(SALES.customerID) > 1;
Maybe just do a count in a sub select:
select * from
(SELECT CUSTOMERS.customerFirName, CUSTOMERS.CustomerID, CUSTOMERS.customerZip, COUNT(*) num_sales
FROM CUSTOMERS
INNER JOIN SALES ON CUSTOMERS.customerID=SALES.customerID
GROUP BY CUSTOMERS.customerFirName, CUSTOMERS.CustomerID, CUSTOMERS.customerZip)
where num_sales > 1;

How to implement this trigger on Oracle SQL?

I have found an exercise in the SQL book I study, which is not solved and I can not solve it.
The goal is to implement a trigger that avoids overlapping contracts. If a customer with a current contract signs a new one, the end date of the previous one will be one day before the new start date.
Tables given are:
CREATE TABLE CLIENTS (
clientId VARCHAR2(15),
DNI VARCHAR2(9),
name VARCHAR2(100) NOT NULL,
surname VARCHAR2(100) NOT NULL,
sec_surname VARCHAR2(100),
eMail VARCHAR2(100) NOT NULL,
phoneN NUMBER(12),
birthdate DATE,
CONSTRAINT PK_CLIENTS PRIMARY KEY (clientId),
CONSTRAINT UK1_CLIENTS UNIQUE (DNI),
CONSTRAINT UK2_CLIENTS UNIQUE (eMail),
CONSTRAINT UK3_CLIENTS UNIQUE (phoneN),
);
CREATE TABLE contracts(
contractId VARCHAR2(10),
clientId VARCHAR2(15),
startdate DATE NOT NULL,
enddate DATE,
contract_type VARCHAR2(50),
address VARCHAR2(100) NOT NULL,
town VARCHAR2(100) NOT NULL,
ZIPcode VARCHAR2(8) NOT NULL,
country VARCHAR2(100) NOT NULL,
CONSTRAINT PK_contracts PRIMARY KEY (contractId),
CONSTRAINT FK_contracts1 FOREIGN KEY (clientId) REFERENCES CLIENTS
);
Any suggestions?
I agree with the posted comments that it helps to have some specifics about what is failing in the prior attempts, and I would also recommend not using a TRIGGER at all for this kind of thing.
But as this is for a study exercise, here are some examples that might be a starting place.
I've modified your tables to disallow NULL PRIMARY KEYs in these examples.
To get started, create the tables:
CREATE TABLE CLIENTS (
CLIENTID VARCHAR2(15) NOT NULL,
DNI VARCHAR2(9),
NAME VARCHAR2(100) NOT NULL,
SURNAME VARCHAR2(100) NOT NULL,
SEC_SURNAME VARCHAR2(100),
EMAIL VARCHAR2(100) NOT NULL,
PHONEN NUMBER(12),
BIRTHDATE DATE,
CONSTRAINT PK_CLIENTS PRIMARY KEY (CLIENTID),
CONSTRAINT UK1_CLIENTS UNIQUE (DNI),
CONSTRAINT UK2_CLIENTS UNIQUE (EMAIL),
CONSTRAINT UK3_CLIENTS UNIQUE (PHONEN)
);
CREATE TABLE CONTRACTS (
CONTRACTID VARCHAR2(10) NOT NULL,
CLIENTID VARCHAR2(15) NOT NULL,
STARTDATE DATE NOT NULL,
ENDDATE DATE,
CONTRACT_TYPE VARCHAR2(50),
ADDRESS VARCHAR2(100) NOT NULL,
TOWN VARCHAR2(100) NOT NULL,
ZIPCODE VARCHAR2(8) NOT NULL,
COUNTRY VARCHAR2(100) NOT NULL,
CONSTRAINT PK_CONTRACTS PRIMARY KEY (CONTRACTID),
CONSTRAINT FK_CONTRACTS1 FOREIGN KEY (CLIENTID) REFERENCES CLIENTS
);
Then, create the first CLIENTs:
INSERT INTO CLIENTS VALUES (1,NULL,'Frodo','Baggins',NULL,'the.real.frodo#adventure.com',NULL,NULL);
INSERT INTO CLIENTS VALUES (2,NULL,'Chewbacca','UNKNOWN',NULL,'chewio.#kashyyyk.org',NULL,NULL);
COMMIT;
Then create a TRIGGER. In this first example, the TRIGGER is an AFTER STATEMENT type.
It is simple but inefficient since it evaluates every CLIENT after each INSERT statement.
Against a large data set, or in the face of multiple TRIGGERs, this could be a problem.
This TRIGGER will check for the prior contract and will set its ENDDATE to one day before the new contract, if it is null or after the start of the new contract.
CREATE OR REPLACE TRIGGER CONTRACT_ENDDATE_ADJUSTER
AFTER INSERT ON CONTRACTS
BEGIN
MERGE INTO CONTRACTS
USING (
SELECT CONTRACTID,
CANDIDATE_ENDDATE AS ENDDATE
FROM
(SELECT CONTRACTS.CONTRACTID,
(TRUNC(LEAD(STARTDATE) OVER (PARTITION BY CLIENTID ORDER BY STARTDATE ASC) - 1)) AS CANDIDATE_ENDDATE,
DENSE_RANK() OVER (PARTITION BY CLIENTID ORDER BY STARTDATE DESC) AS CONTRACT_ORDER
FROM CONTRACTS)
WHERE CONTRACT_ORDER = 2) CANDIDATE_CONTRACT
ON (CONTRACTS.CONTRACTID = CANDIDATE_CONTRACT.CONTRACTID)
WHEN MATCHED THEN UPDATE SET CONTRACTS.ENDDATE = CANDIDATE_CONTRACT.ENDDATE
WHERE CONTRACTS.ENDDATE IS NULL OR CONTRACTS.ENDDATE > CANDIDATE_CONTRACT.ENDDATE;
END;
/
Then, test it out.
Add the initial contracts. No enddate changes expected, as these are the first. Frodo's contract here has an end-date already set.
INSERT INTO CONTRACTS VALUES('Break-Ring',1,TO_DATE('19560511','YYYYMMDD'), TO_DATE('19851014','YYYYMMDD'), NULL, 'No 1', 'Doom Mountain', 'MORD', 'Middle-Earth');
INSERT INTO CONTRACTS VALUES('SaveGalaxy',2,TO_DATE('19770615','YYYYMMDD'), NULL, NULL, 'No 75', 'Rwookrrorro', 'RWKR', 'Kashyyyk');
SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 14-OCT-85
SaveGalaxy 2 15-JUN-77
Then add new contracts.
Frodo's new contract starts before the end of his existing contract, so the enddate will be adjusted.
Chewie's initial contract had no ENDDATE, so it will be adjusted as well.
INSERT INTO CONTRACTS VALUES('GoBackHome',1,TO_DATE('19570219','YYYYMMDD'), NULL, NULL, 'No 13', 'Hobbiton', 'HBTN', 'Middle-Earth');
INSERT INTO CONTRACTS VALUES('DefendHoth',2,TO_DATE('19801115','YYYYMMDD'), NULL, NULL, 'Meteor Crater', 'Ice Ridge', 'METEO', 'Hoth');
SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 18-FEB-57
GoBackHome 1 19-FEB-57
SaveGalaxy 2 15-JUN-77 14-NOV-80
DefendHoth 2 15-NOV-80
And as other contracts are signed, the pattern continues:
INSERT INTO CONTRACTS VALUES('GoWedding',2,TO_DATE('19830309','YYYYMMDD'), NULL, NULL, 'Main Hall', 'Grand Palace', 'ALLNC', 'Coruscant');
INSERT INTO CONTRACTS VALUES('Gardening',1,TO_DATE('19570503','YYYYMMDD'), NULL, NULL, 'No 13', 'Hobbiton', 'HBTN', 'Middle-Earth');
SELECT CONTRACTID, CLIENTID, STARTDATE, ENDDATE FROM CONTRACTS ORDER BY CLIENTID ASC, STARTDATE ASC;
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 18-FEB-57
GoBackHome 1 19-FEB-57 02-MAY-57
Gardening 1 03-MAY-57
SaveGalaxy 2 15-JUN-77 14-NOV-80
DefendHoth 2 15-NOV-80 08-MAR-83
GoWedding 2 09-MAR-83
To stabilize the workload on this query, a COMPOUND TRIGGER may be used instead. This second example achieves the same result as the first, but only interrogates the CONTRACTs of CLIENTs that have changed:
First, ROLLBACK;
Then, create a type to be used by the TRIGGER:
CREATE OR REPLACE TYPE NUMBER_LIST IS TABLE OF NUMBER;
/
Then create the COMPOUND TRIGGER:
CREATE OR REPLACE TRIGGER CONTRACT_ENDDATE_ADJUSTER
FOR INSERT ON CONTRACTS
COMPOUND TRIGGER
V_CLIENTS NUMBER_LIST;
BEFORE STATEMENT
IS
BEGIN
V_CLIENTS:= NUMBER_LIST();
END BEFORE STATEMENT;
AFTER EACH ROW
IS
BEGIN
V_CLIENTS.EXTEND();
V_CLIENTS(V_CLIENTS.COUNT) := :NEW.CLIENTID;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
MERGE INTO CONTRACTS
USING (
SELECT CONTRACTID,
CANDIDATE_ENDDATE AS ENDDATE
FROM
(SELECT CONTRACTS.CONTRACTID,
(TRUNC(LEAD(STARTDATE) OVER (PARTITION BY CLIENTID ORDER BY STARTDATE ASC) - 1)) AS CANDIDATE_ENDDATE,
DENSE_RANK() OVER (PARTITION BY CLIENTID ORDER BY STARTDATE DESC) AS CONTRACT_ORDER
FROM CONTRACTS
WHERE CONTRACTS.CLIENTID IN (SELECT * FROM TABLE(V_CLIENTS)))
WHERE CONTRACT_ORDER = 2) CANDIDATE_CONTRACT
ON (CONTRACTS.CONTRACTID = CANDIDATE_CONTRACT.CONTRACTID)
WHEN MATCHED THEN UPDATE SET CONTRACTS.ENDDATE = CANDIDATE_CONTRACT.ENDDATE
WHERE CONTRACTS.ENDDATE IS NULL OR CONTRACTS.ENDDATE > CANDIDATE_CONTRACT.ENDDATE;
END AFTER STATEMENT;
END CONTRACT_ENDDATE_ADJUSTER;
/
After repeating the above inserts, the result is the same:
CONTRACTID CLIENTID STARTDATE ENDDATE
Break-Ring 1 11-MAY-56 18-FEB-57
GoBackHome 1 19-FEB-57 02-MAY-57
Gardening 1 03-MAY-57
SaveGalaxy 2 15-JUN-77 14-NOV-80
DefendHoth 2 15-NOV-80 08-MAR-83
GoWedding 2 09-MAR-83

Trying to collect data from multiple tables with logic aritmethics

I am trying to collect data from multiple tables with logic aritmethics like: OR AND NOT UNION INTERSECT.
I have 3 tables called: Customers, Flights, Booking.
My aim is to get all the passportno from the customers table which took a flight more than once.
Thnaks for helpers.
Use group by and having clauses. The having limits those rows that are count>1
Schema
create table bookings
(
id int auto_increment primary key,
passportno int not null,
flightnumber int not null,
`day` date not null,
row varchar(10) not null,
seat varchar(10) not null
);
insert bookings(passportno,flightnumber,`day`,row,seat) values (1,2,'2005-01-01',1,1); -- Joe
insert bookings(passportno,flightnumber,`day`,row,seat) values (1,3,'2005-02-01',1,1); -- Joe
insert bookings(passportno,flightnumber,`day`,row,seat) values (2,3,'2005-02-01',2,2); -- Sally
create table customers
(
passportno int primary key,
name varchar(100) not null,
address varchar(100) not null,
phone varchar(20) not null
);
insert customers(passportno,name,address,phone) values (1,'Joe','addr','ph');
insert customers(passportno,name,address,phone) values (2,'Sally','addr','ph');
Query and results
select c.passportno
from customers c
join bookings b
on c.passportno=b.passportno
group by c.passportno
having count(b.id)>1;
+------------+
| passportno |
+------------+
| 1 |
+------------+
Mysql manual page entitled MySQL Handling of GROUP BY
If I understand the question the query should be something like
SELECT c.PASSPORTNO
FROM CUSTOMERS c
WHERE c.PASSPORTNO IN (SELECT DISTINCT PASSPORTNO
FROM (SELECT PASSPORTNO, FLIGHTNUMBER, COUNT(*)
FROM BOOKINGS
GROUP BY PASSPORTNO, FLIGHTNUMBER
HAVING COUNT(*) > 1)
Best of luck.

Date difference between first and last book per each author

I would create this table.
create table Books
(
book_id number PRIMARY KEY,
Title number,
yearpub DATE,
author_id number
)
create table Authors
(
author_id number,
book_id number
)
create table Author_name
(
author_id number,
first_name varchar(10),
last_name varchar(10)
)
I have no Oracle installed now but I wanna select
Date difference (number of years) between first and last book per each author.
I think there should be some aggregate function.
SELECT authors.author_id,
max(name.first_name||' '||name.last_name) as full_name,
max(to_char(yearpub,'yyyy')) - min(to_char(yearpub,'yyyy')) as years
from author_name name, books,authors
where
authors.author_id = name.author_id and
authors.author_id = books.author_id and
authors.book_id = books.book_id
group by authors.author_id

Resources