PostgreSQL query for Library Management System - sql

Get the member ID and name of the members to whom no more books can be issued, because they have already got as many books issued as the number for which they are entitled
Following are the schemas:
Book_Records(accession_no,isbn_no)
Book(isbn_no, author, publisher, price)
Members(member_id, member_name,max_no_books,max_no_days)
Book_Issue(member_id,accession_no,issue_date,return_date)
CREATE TABLE BOOK (ISBN_NO VARCHAR(35) PRIMARY KEY,
AUTHOR VARCHAR(35) NOT NULL,
PUBLISHER VARCHAR(35) NOT NULL,
PRICE NUMERIC(10,3));
CREATE TABLE BOOK_RECORDS(ACCESSION_NO VARCHAR(35) PRIMARY KEY,
ISBN_NO VARCHAR(35) REFERENCES BOOK(ISBN_NO));
CREATE TABLE MEMBERS(MEMBER_ID VARCHAR(35) PRIMARY KEY,
MEMBER_NAME VARCHAR(35) NOT NULL,
MAX_NO_BOOKS INT,
MAX_NO_DAYS INT);
CREATE TABLE BOOK_ISSUE(MEMBER_ID VARCHAR(35) REFERENCES MEMBERS(MEMBER_ID),
ACCESSION_NO VARCHAR(35) REFERENCES
BOOK_RECORDS(ACCESSION_NO),
ISSUE_DATE DATE NOT NULL,
RETURN_DATE DATE,
PRIMARY KEY(MEMBER_ID,ACCESSION_NO));
I tried the following query but fails.
SELECT DISTINCT member_name
FROM members AS m
JOIN (
SELECT member_id, COUNT(*) AS no_books_issued
FROM book_issue
GROUP BY member_id,accesion_no
HAVING no_books_issued >= max_no_books
) AS b ON m.member_id = b.member_id;

Presumably, a query like this gets the number of books currently issued:
SELECT member_id, COUNT(*) AS num_books
FROM book_issue
WHERE return_date IS NULL
GROUP BY member_id;
My understanding of the maximum number of books would be concurrently -- that is, only count books that have not been returned. Perhaps you have a different definition.
Then, you can use this in a JOIN, doing the comparison on the maximum outside the subquery:
SELECT member_name
FROM members m JOIN
(SELECT member_id, COUNT(*) AS num_books
FROM book_issue
WHERE return_date IS NULL
GROUP BY member_id
) b
ON b.member_id = m.member_id AND
b.num_books >= m.max_no_books;
Notes:
In a JOIN, the comparison to the outer table needs to be outside the subqueries.
No SELECT DISTINCT is needed.
The GROUP BY for counting books should be only at the member level.

Related

SQLite: Get Output From Two Tables Using Common Reference ID

I am new in SQLite and i have been working on an issue for quite a long time.
Lets say we have 2 database table say tbl_expense and tbl_category. Please find below the following table structure.
tbl_category
CREATE TABLE IF NOT EXISTS tbl_category(
category_id INTEGER PRIMARY KEY AUTOINCREMENT,
category_name VARCHAR(20) DEFAULT NULL,
category_desc VARCHAR(500) DEFAULT NULL,
category_icon VARCHAR(100) DEFAULT NULL,
category_created timestamp default CURRENT_TIMESTAMP
)
tbl_expense
CREATE TABLE IF NOT EXISTS tbl_expense(
expense_id INTEGER PRIMARY KEY AUTOINCREMENT,
expense_name VARCHAR(20) DEFAULT NULL,
expense_desc VARCHAR(500) DEFAULT NULL,
expense_type VARCHAR(20) DEFAULT NULL,
expense_amt DECIMAL(6.3) DEFAULT NULL,
expense_date TIMESTAMP DEFAULT NULL,
expense_category INTEGER DEFAULT NULL,
expense_created_date timestamp DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (expense_category) REFERENCES tbl_category(category_id)
ON DELETE SET NULL
)
Assume we have data in the tables like this below.
Expected Output:
Assure we have category_id and expense_category as common fields. How can i create an SQL Query where i can list all categories and sum of their expense amount as follows.
Please help me on this issue.
You need an INNER join of the tables and aggregation:
SELECT c.category_name Category,
SUM(e.expense_amt) Amount
FROM tbl_category c INNER JOIN tbl_expense e
ON e.expense_category = c.category_id
GROUP BY c.category_id;
If you want all categories from the table tbl_category, even those that are not present in tbl_expense, use a LEFT join and TOTAL() aggregate function:
SELECT c.category_name Category,
TOTAL(e.expense_amt) Amount
FROM tbl_category c LEFT JOIN tbl_expense e
ON e.expense_category = c.category_id
GROUP BY c.category_id;

SQL join query to library

I have these tables,
CREATE TABLE Book
(
ISBN CHAR(05)NOT NULL,
BKName VARCHAR(20)NOT NULL,
Author VARCHAR(20)NOT NULL,
Price NUMERIC(02)NOT NULL,
CONSTRAINT Book_PK PRIMARY KEY (ISBN)
);
CREATE TABLE Location
(
LoID CHAR(05)NOT NULL,
CityName VARCHAR(15)NOT NULL,
Stoke CHAR(05)NOT NULL,
CONSTRAINT Location_PK PRIMARY KEY (LoID)
);
CREATE TABLE Customer
(
CuID CHAR(05)NOT NULL,
CusName VARCHAR(20)NOT NULL,
RegiDate DATE NOT NULL,
Gender VARCHAR(06)NOT NULL,
TeleNum CHAR(12)NOT NULL,
Address VARCHAR(30)NOT NULL,
CONSTRAINT Customer_PK PRIMARY KEY (CuID)
);
CREATE TABLE BookCopy
(
CopyID CHAR(05)NOT NULL,
ISBN CHAR(05)NOT NULL,
LoID CHAR(05)NOT NULL,
CONSTRAINT pk_BookCopy PRIMARY KEY (CopyID),
CONSTRAINT fk_BookCopy_ISBN_FK FOREIGN KEY (ISBN) REFERENCES Book(ISBN),
CONSTRAINT fk_BookCopy_LoID_FK FOREIGN KEY (LoID) REFERENCES Location(LoID)
);
CREATE TABLE BorrowRecord
(
BrrDate DATE NOT NULL,
RetDate DATE NOT NULL,
BrFee NUMBER(05) NOT NULL,
Cus_Review NUMERIC(02)NOT NULL,
CopyID CHAR(05)NOT NULL,
CuID CHAR(05) NOT NULL,
CONSTRAINT pk_BorrowRecord PRIMARY KEY (CopyID, CuID),
CONSTRAINT fk_BorrowRecord_CopyID_FK FOREIGN KEY (CopyID) REFERENCES BookCopy(CopyID) ,
CONSTRAINT fk_BorrowRecord_CuID_FK FOREIGN KEY (CuID) REFERENCES Customer(CuID) );
This is the task: "write and test a query to list the customer ID and name of every Customer along with the books that they have hired within the past 200 days. Include starting date, ending date, and location name for those hirings. All customer details (ID and name) should be included in the output, whether or not they have actually borrowed any books."
I write a query to list the customer ID and name of every Customer along with the books that they have borrowed within the past 200 days. Include starting date, ending date, and location name for those hirings. This the query for it.
SELECT
BorrowRecord.CuID, Customer.CusName, Book.ISBN, Book.BkName,
BorrowRecord.BrrDate, BorrowRecord.RetDate, Location.CityName
FROM
Book
LEFT JOIN
BookCopy ON Book.ISBN = BookCopy.ISBN
LEFT JOIN
BorrowRecord ON BookCopy.CopyID = BorrowRecord.CopyID
LEFT JOIN
Customer ON BorrowRecord.CuID = Customer.CuID
LEFT JOIN
Location ON Location.LoID = BookCopy.LoID
WHERE
BorrowRecord.BrrDate >= sysdate - 200 ;
But I also need to get all customer details (ID and name) that should be included in the output, whether or not they have actually borrowed any books. How can I do it?
If You want to see all customers independently whether they have borrowed a book or not, it's important that the first LEFT JOIN is based on customers table. In Your script, You start with Book, then join to BorrowRecord and only then have The Customer on the right side of the join. Another point is the WHERE -Condition that excludes all entries of Customer that borrowed a book outside of the 200-days-range. This meand that all records of BorrowRecord are shown (that match to the previous join) but only the customers that are found in a link to BorrowRecords from the past 200 days.
Try the following:
SELECT BorrowRecord.CuID, Customer.CusName, Book.ISBN, Book.BkName,
BorrowRecord.BrrDate,BorrowRecord.RetDate, Location.CityName
FROM Customer
LEFT JOIN BorrowRecord ON BorrowRecord.CuID = Customer.CuID
LEFT JOIN BookCopy ON BorrowRecord.CopyID = BookCopy.CopyID
LEFT JOIN Book ON BookCopy.ISBN= Book.ISBN
LEFT JOIN Location ON Location.LoID = BookCopy.LoID
WHERE ISNULL(BorrowRecord.BrrDate,'') >=sysdate-200 ;

Select a product that is on all interventions

Hello my question is simple for some of yours ^^
I've a table product, reference, and intervention. When there is an intervention the table reference make the link between products that we need for the interventions and the intervention.
I would like to know how to do to search products that have made part of all interventions.
This are my tables :
--TABLE products
create table products (
reference char(5) not null check ( reference like 'DT___'),
designation char(50) not null,
price numeric (9,2) not null,
primary key(reference) );
-- TABLE interventions
create table interventions (
nointerv integer not null ,
dateinterv date not null,
nameresponsable char(30) not null,
nameinterv char(30) not null,
time float not null check ( temps !=0 AND temps between 0 and 8),
nocustomers integer not null ,
nofact integer not null ,
primary key( nointerv),
foreign key( noclient) references customers,
foreign key (nofacture) references facts
);
-- TABLE replacements
create table replacements (
reference char(5) not null check ( reference like 'DT%'),
nointerv integer not null,
qtereplaced smallint,
primary key ( reference, nointerv ),
foreign key (reference) references products,
foreign key(nointerv) references interventions(nointerv)
);
--EDIT :
This is a select from my replacement table
We can see in this picture that the product DT802 is used in every interventions
Thanks ;)
This will show 1 line intervention - products. Is this you are expecting for?
select interventions.nointerv, products.reference
from interventions
inner join replacements on interventions.nointerv = replacements.nointerv
inner join products on replacements.reference = products.reference;
This one?
select products.reference, products.designation
from interventions
inner join replacements on interventions.nointerv = replacements.nointerv
inner join products on replacements.reference = products.reference
group by products.reference, products.designation
having count(*) = (select count(*) from interventions);
Your question is hard to follow. If I interpret it as all nointerv in replacements whose reference contains all products, then:
select nointerv
from replacements r
group by nointerv
having count(distinct reference) = (select count(*) from products);

JOIN ON SQL syntax

I am taking my first database class and need some info on what I need to change for my script to process. Currently I have 2 tables, an "orders" table and a "customers" table and this is how they are coded.
CREATE TABLE customers (
customer_id INT ,
customer_first_name VARCHAR(20),
customer_last_name VARCHAR(20) NOT NULL,
customer_address VARCHAR(50) NOT NULL,
customer_city VARCHAR(20) NOT NULL,
customer_state CHAR(2) NOT NULL,
customer_zip CHAR(5) NOT NULL,
customer_phone CHAR(10) NOT NULL,
customer_fax CHAR(10),
CONSTRAINT customers_pk
PRIMARY KEY (customer_id)
);
CREATE TABLE order (
order_id INT NOT NULL,
customer_id INT NOT NULL,
order_date DATE NOT NULL,
shipped_date DATE,
employee_id INT,
CONSTRAINT orders_pk
PRIMARY KEY (order_id),
CONSTRAINT orders_fk_customers
FOREIGN KEY (customer_id) REFERENCES customers (customer_id),
CONSTRAINT orders_fk_employees
FOREIGN KEY (employee_id) REFERENCES employees (employee_id)
);
My script to join these two tables together is as follows:
SELECT or.order_id, or.order_date, or.customer_city,
cu.customer_first_name, cu.customer_last_name
FROM orders or INNER JOIN customers cu
ON or.customer_first_name = cu.customer_first_name
AND or.customer_last_name = cu.customer_last_name;
Now obviously, I know it is incorrect and may have multiple errors, so be gentle. I would love to know what I can do to make it work. Please advise.
Two things:
Don't use or as an alias. That's a reserved word.
Join by the foreign key.
The query should look like:
SELECT o.order_id, o.order_date, cu.customer_city,
cu.customer_first_name, cu.customer_last_name
FROM orders o
INNER JOIN customers cu
on o.customer_id = cu.customer_id
You can join your tables on the ID numbers, and you won't have to worry about what happens when multiple people have the same name.
Use this instead:
FROM orders ord INNER JOIN customers cu
ON ord.order_id = cu.customer_id
Your select statement can remain as it is. I also re-aliased according to the comment from Error_2646.
Using a field that is a primary key in one of your tables is also better practice than using non-key fields, when possible.

Oracle Sql 3 tables with count condition and equal condition

CREATE TABLE CUSTOMER (
CUSID VARCHAR(25) NOT NULL,
CNAME VARCHAR(50),
CONSTRAINT CUSTOMER_PKEY PRIMARY KEY (CUSID),
);
CREATE TABLE SHOP (
SHOPID VARCHAR(10) NOT NULL,
ADDRESS VARCHAR(25),
CONSTRAINT SHOP_PKEY PRIMARY KEY (SHOPID),
);
CREATE TABLE VISIT (
CUSID VARCHAR(25) NOT NULL,
SHOPID VARCHAR(10) NOT NULL,
VDATE DATE NOT NULL,
CONSTRAINT VISIT_PKEY PRIMARY KEY (CUSID, SHOPID, VDATE),
CONSTRAINT VISIT_FKEY1 FOREIGN KEY (CUSID) REFERENCES CUSTOMER(CUSID),
CONSTRAINT VISIT_FKEY2 FOREIGN KEY (SHOPID) REFERENCES SHOP(SHOPID)
);
how to find the address of shops that have been visited at least 2 times by customer with name 'john'??
SELECT ADDRESS FROM SHOP NATURAL JOIN VISIT WHERE CUSID IN (SELECT CUSID FROM CUSTOMER WHERE CNAME = 'john' GROUP BY CUSID HAVING COUNT(CUSID) > 2);
i have tried many kinds of joins, it seems that after i put count and equal condition in together,my results will be 0 rows.
SELECT DISTINCT s.address
FROM shop s
JOIN visit v ON s.shopid = v.shopid
JOIN customer c ON v.customerid = c.customerid
WHERE c.cname = 'John'
GROUP BY
s.address
, c.customerid
HAVING COUNT(*) > 1