SQL check value in current table - mysql

I've got this situation: a set of hotel that has to deal with bookings. Each client can choose a room of the given hotel, from a date START_DATE to a date END_DATE. I want to check in the table BOOKING if it's possible to book from the date START_DATE to END_DATE because there's no other booking in that period.
Here's the code:
CREATE TABLE HOTEL(
Name varchar(30) PRIMARY KEY,
City varchar(30)
);
CREATE TABLE ROOM(
HotelName varchar(30) REFERENCES HOTEL (Name),
RoomNumber int(11),
PRIMARY KEY(HotelName , RoomNumber )
);
CREATE TABLE CLIENT(
ClientCode char(16) PRIMARY KEY
);
CREATE TABLE BOOKING(
HotelName varchar(30)
RoomNumber int(11),
ClientCode char(16) REFERENCES CLIENT(ClientCode ),
StartDate date,
EndDate date,
PRIMARY KEY(HotelName , NumeroStanza, CodiceCliente, StartDate, EndDate),
FOREIGN KEY (HotelName , RoomNumber ) REFERENCES ROOM(HotelName , RoomNumber ),
CHECK (????)
);
How can I say: CHECK if given START_DATE < END_DATE, then START_DATE not between A and B, then END_DATE not between A and B, for every interval of date A and B already in the table?
The dialet is MySql
Many thanks

Related

Filter customer will come again with SQL based on week

Lets saying my data is
CREATE TABLE memberdata
(
CustomerID CHAR(7) PRIMARY KEY not null,
CustomerName VARCHAR(255),
CustomerGender VARCHAR(20),
)
SELECT * FROM memberdata
insert into memberdata(CustomerID,CustomerName,CustomerGender)
values('C001','Alan','Male'),('C002','Lana','Female'),('C003','Aan','Male'),
('C004','Nala','Female');
And for the content:
CREATE TABLE TrTransaktion(
TransID CHAR(7) PRIMARY KEY NOT NULL,
CustomerID CHAR (7) FOREIGN KEY REFERENCES memberdata (CustomerID) ON UPDATE CASCADE ON DELETE SET NULL,
Sales INT,
TransDate date,
)
SELECT * FROM TrTransaktion
insert into TrTransaktion(TransID,CustomerID,Sales,TransDate)
values('TR001','C001',34,'2022-09-03'),('TR002','C002',23,'2022-09-02'),('TR003','C003',132,'2022-09-03'),
('TR004','C004',95,'2022-09-02'),('TR005','C002',68,'2022-09-08'),('TR006','C001',54,'2022-09-05'),
('TR007','C002',34,'2022-09-11'),('TR008','C002',98,'2022-09-23'),('TR009','C004',34,'2022-09-19'),
('TR010','C001',30,'2022-09-18'),('TR011','C003',34,'2022-09-26');
Last i Add weeks:
ALTER TABLE TrTransaktion ADD Weeks int;
UPDATE TrTransaktion SET Weeks = datepart(week, TransDate);
I would to find who come by based (week 36).if the customers come to week 37 they will not appear in other week (38, 39, 40)
hope the result will show about:
week 37 = CS002 CS001, week 38 = -, week 39 = CS004, week 40 = CS003
(can be modified but that's the point)

Error Code: 1136. Column count doesn't match value count at row 1

-- This is my table
CREATE TABLE Payment (
Payment_id BIGINT NOT NULL primary key,
Ord_id BIGINT NOT NULL,
FOREIGN KEY (Ord_id)
REFERENCES Ord(Ord_id)
ON DELETE NO ACTION,
Bank_id int not null,
FOREIGN KEY (Bank_id)
REFERENCES Bank(Bank_id),
card_id varchar(16),
cvv varchar(3),
expired_date date not null,
total_price decimal(11,2),
payment_date datetime
)ENGINE = InnoDB;
and this is some datas
INSERT INTO Payment (Payment_id,
Ord_id ,
Bank_id ,
card_id ,
cvv ,
expired_date,
total_price ,
payment_date)
VALUES
(1,1,1,'3998181978445452','854','2023-10-16','350000','2019-10-16 16-45-10'),
(2,2,2,'3994191845663215','125','2022-10-16','840000','2019-10-16 17-45-10'),
(3,3,3,'3998181978446666','814','2021-10-16','1260000','2019-10-16 18-30-10'),
(4,4,1,'3998181978446666','814','2024-10-17','600000','2019-10-17 11-25-10'),
(5,5,2,'3998181978446666','814','2023-10-17','200000','2019-10-17 12-24-14'),
(6,6,3,'3998181978446666','814','2020-10-17','200000''2019-10-17 15-12-17'),
(7,7,1,'3998181978446666','814','2021-10-17','280000','2019-10-17 15-41-12');
but its not working and the error message is "1136"
You are missing a comma at line 6;
(6,6,3,'3998181978446666','814','2020-10-17','200000' #HERE# '2019-10-17 15-12-17')

Altering a Table to Add a Column thats Value is set using a UPDATE JOIN Query

Im trying to create a Column thats Value is defined through anUPDATE JOIN SET statement. The exact question that im trying to answer actually is
"Add to a relational table EMPLOYEE information about the total number of orders handled by each employee. Note, that if an employee handled no orders then for such employee the total number of orders must be set to zero. Enforce the appropriate consistency constraints on a relational table EMPLOYEE. "
ALTER TABLE EMPLOYEE
ADD TOTALNUMBER VARCHAR(40) NOT NULL;
UPDATE EMPLOYEE E JOIN ORDERS O ON(E.EMPLOYEE_ID = O.EMPLOYEE_ID)
SET E.TOTALNUMBER = E.EMPLOYEE_ID + O.ORDER_ID;
UPDATE EMPLOYEE
SET TOTALNUMBER = 0
WHERE TOTALNUMBER IS NULL;
tables being used
CREATE TABLE EMPLOYEE
(
EMPLOYEE_ID DECIMAL(9) NOT NULL,
LASTNAME VARCHAR(20) NOT NULL,
FIRSTNAME VARCHAR(10) NOT NULL,
TITLE VARCHAR(30),
TITLE_OF_COURTESY VARCHAR(25),
BIRTHDATE DATE,
HIREDATE DATE,
ADDRESS VARCHAR(60),
CITY VARCHAR(15),
REGION VARCHAR(15),
POSTAL_CODE VARCHAR(10),
COUNTRY VARCHAR(15),
HOME_PHONE VARCHAR(24),
EXTENSION VARCHAR(4),
PHOTO VARCHAR(255),
NOTES VARCHAR(2000),
REPORTS_TO DECIMAL(9),
CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMPLOYEE_ID)
);
CREATE TABLE ORDERS
(
ORDER_ID DECIMAL(9) NOT NULL,
CUSTOMER_CODE VARCHAR(5) NOT NULL,
EMPLOYEE_ID DECIMAL(9) NOT NULL,
ORDER_DATE DATE NOT NULL,
REQUIRED_DATE DATE,
SHIPPED_DATE DATE,
SHIP_VIA VARCHAR(40),
FREIGHT DECIMAL(10,2) DEFAULT 0,
SHIP_NAME VARCHAR(40),
SHIP_ADDRESS VARCHAR(60),
SHIP_CITY VARCHAR(15),
SHIP_REGION VARCHAR(15),
SHIP_POSTAL_CODE VARCHAR(10),
SHIP_COUNTRY VARCHAR(15),
CONSTRAINT PK_ORDERS PRIMARY KEY (ORDER_ID),
CONSTRAINT FK_CUSTOMER_CODE FOREIGN KEY (CUSTOMER_CODE) REFERENCES CUSTOMER(CUSTOMER_CODE),
CONSTRAINT FK_EMPLOYEE_ID FOREIGN KEY (EMPLOYEE_ID) REFERENCES EMPLOYEE(EMPLOYEE_ID),
CONSTRAINT FK_SHIP_VIA FOREIGN KEY (SHIP_VIA) REFERENCES SHIPPER(COMPANY_NAME)
);
Im unsure of what the exact result should be but i recieve a total of 9 rows with values ranging between 252 to 296. It doesnt seem to odd that an employee would deal with this many Orders but it seems to be too small of a list.
I don't recommend your current approach, and the best way to determine the number of orders per employees is to just aggregate and join, without storing this number in the actual employee table. That being said, if you want to proceed this way, then consider using this update query:
UPDATE EMPLOYEE e
LEFT JOIN
(
SELECT EMPLOYEE_ID, COUNT(*) AS num_orders
FROM ORDERS
GROUP BY EMPLOYEE_ID
) o
ON e.EMPLOYEE_ID = o.EMPLOYEE_ID
SET TOTALNUMBER = COALESCE(o.num_orders, 0);
Or, you could use:
SET TOTALNUMBER = o.num_orders;
and then use your second update to zero-out the employee totals which had no orders at all:
UPDATE EMPLOYEE
SET TOTALNUMBER = 0
WHERE TOTALNUMBER IS NULL;
But note that this would require that the TOTALNUMBER columns is not nullable. So you would need to remove the NOT NULL constraint.

Using count in a Subquery

Im currently learning about sub querys in mysql and just want to clarify if im on the right track. The below code does bring a result but im unsure if im doing it correctly. The question is
"Find a code and company name of all customers who submitted at least one order in April 1997 using an IN statement ."
SELECT CUSTOMER_CODE, COMPANY_NAME
FROM CUSTOMER
WHERE CUSTOMER_CODE IN (SELECT CUSTOMER_CODE
FROM ORDERS
WHERE ORDER_DATE BETWEEN '1997-04-01' AND '1997-04-30'
GROUP BY CUSTOMER_CODE )
I went through the values that are inserted into the tables and it just doesnt seem to be correct even though a result is produced.
(Side note, is using a EXIST clause the same as a IN clause, but instead of WHERE CUSTOMER_CODE IN it is WHERE EXISTS ?
I tried this
SELECT CUSTOMER_CODE, COMPANY_NAME
FROM CUSTOMER
WHERE NOT EXISTS (SELECT CUSTOMER_CODE
FROM ORDERS
WHERE ORDER_DATE BETWEEN '1997-04-01' AND '1997-04-30'
GROUP BY CUSTOMER_CODE );
these are the two talbes im using
CREATE TABLE CUSTOMER
(
CUSTOMER_CODE VARCHAR(5) NOT NULL,
COMPANY_NAME VARCHAR(40) NOT NULL,
CONTACT_NAME VARCHAR(30),
CONTACT_TITLE VARCHAR(30),
ADDRESS VARCHAR(60),
CITY VARCHAR(15),
REGION VARCHAR(15),
POSTAL_CODE VARCHAR(10),
COUNTRY VARCHAR(15),
PHONE VARCHAR(24),
FAX VARCHAR(24),
CONSTRAINT PK_CUSTOMER PRIMARY KEY (CUSTOMER_CODE)
);
CREATE TABLE ORDERS
(
ORDER_ID DECIMAL(9) NOT NULL,
CUSTOMER_CODE VARCHAR(5) NOT NULL,
EMPLOYEE_ID DECIMAL(9) NOT NULL,
ORDER_DATE DATE NOT NULL,
REQUIRED_DATE DATE,
SHIPPED_DATE DATE,
SHIP_VIA VARCHAR(40),
FREIGHT DECIMAL(10,2) DEFAULT 0,
SHIP_NAME VARCHAR(40),
SHIP_ADDRESS VARCHAR(60),
SHIP_CITY VARCHAR(15),
SHIP_REGION VARCHAR(15),
SHIP_POSTAL_CODE VARCHAR(10),
SHIP_COUNTRY VARCHAR(15),
CONSTRAINT PK_ORDERS PRIMARY KEY (ORDER_ID),
CONSTRAINT FK_CUSTOMER_CODE FOREIGN KEY (CUSTOMER_CODE) REFERENCES CUSTOMER(CUSTOMER_CODE),
CONSTRAINT FK_EMPLOYEE_ID FOREIGN KEY (EMPLOYEE_ID) REFERENCES EMPLOYEE(EMPLOYEE_ID),
CONSTRAINT FK_SHIP_VIA FOREIGN KEY (SHIP_VIA) REFERENCES SHIPPER(COMPANY_NAME)
);
but i recieve an empty set
Thankyou all for your time
instead of a IN clause you could use a INNER JOIN based on the same subquery ..
usually this perform better that a In clause
SELECT CUSTOMER_CODE, COMPANY_NAME
FROM CUSTOMER
INNER JOIN (
SELECT DISTINCT CUSTOMER_CODE
FROM ORDERS
WHERE ORDER_DATE BETWEEN '1997-04-01' AND '1997-04-30'
) t on t.CUSTOMER_CODE = CUSTOMER.CUSTOMER_CODE
You should not use group by for when you don't use aggregation function (this don't work by default in most recent version of mysql)
use DISTINCT if you need only distinct result
You must use EXISTS instead of NOT EXISTS:
SELECT c.CUSTOMER_CODE, c.COMPANY_NAME
FROM CUSTOMER c
WHERE EXISTS (
SELECT CUSTOMER_CODE FROM ORDERS
WHERE
CUSTOMER_CODE = c.CUSTOMER_CODE
AND
ORDER_DATE BETWEEN '1997-04-01' AND '1997-04-30'
);
You can also check about the ORDER_DATE with this:
YEAR(ORDER_DATE) = 1997 AND MONTH(ORDER_DATE) = 4
You can also do it with IN:
SELECT CUSTOMER_CODE, COMPANY_NAME
FROM CUSTOMER
WHERE CUSTOMER_CODE IN (
SELECT CUSTOMER_CODE FROM ORDERS
WHERE YEAR(ORDER_DATE) = 1997 AND MONTH(ORDER_DATE) = 4
);
If you want to find the total number of all customers who submitted no orders:
SELECT COUNT(DISTINCT c.CUSTOMER_CODE) AS COUNTER
FROM CUSTOMER c
WHERE NOT EXISTS (
SELECT CUSTOMER_CODE FROM ORDERS
WHERE CUSTOMER_CODE = c.CUSTOMER_CODE
)

How do I extract results after joining multiple tables in the following schema?

I've used the following commands for creating the tables.
CREATE TABLE Customer(
custid int NOT NULL AUTO_INCREMENT,
fname varchar(30) NOT NULL,
lname varchar(30) NOT NULL,
mno varchar(10),
password varchar(30),
PRIMARY KEY (custid)
);
CREATE TABLE Employee(
empid int NOT NULL,
fname varchar(30) NOT NULL,
lname varchar(30) NOT NULL,
mno varchar(10),
password varchar(30),
PRIMARY KEY (empid)
);
CREATE TABLE Address(
id int NOT NULL,
street varchar(30),
doorno varchar(30),
city varchar(30),
statee varchar(30),
zip varchar(5),
county varchar(30) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Customer (custid)
);
CREATE TABLE EmpAddress(
id int NOT NULL,
street varchar(30),
doorno varchar(30),
city varchar(30),
statee varchar(30),
zip varchar(5),
county varchar(30) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Employee (empid)
);
CREATE TABLE Service(
serviceid int NOT NULL,
serviceType varchar(30),
amount int,
PRIMARY KEY (serviceid)
);
CREATE TABLE Booking(
bookingid int NOT NULL AUTO_INCREMENT,
empid int NOT NULL,
custid int NOT NULL,
serviceid int NOT NULL,
PRIMARY KEY (bookingid),
FOREIGN KEY (empid) REFERENCES Employee (empid),
FOREIGN KEY (custid) REFERENCES Customer (custid),
FOREIGN KEY (serviceid) REFERENCES Service (serviceid)
);
CREATE TABLE Availability(
empid int NOT NULL,
datee date NOT NULL,
startTime int NOT NULL,
PRIMARY KEY (empid, datee, startTime),
FOREIGN KEY (empid) REFERENCES Employee (empid)
);
CREATE TABLE Transactions(
bookingid int NOT NULL,
paymentMethod varchar(20),
serviceid int,
amount int,
PRIMARY KEY (bookingid),
FOREIGN KEY (bookingid) REFERENCES Booking (bookingid),
FOREIGN KEY (serviceid) REFERENCES Service (serviceid)
);
I am trying to write a query that returns the bookingid, firstName, lastName, street, door no, zip code, serviceType, date and startTime GIVEN empid.
It is essentially a join of 5 tables and I'd implemented the query as:
SELECT B.bookingid, C.fname, C.lname, AD.street,
AD.doorno, AD.zip,S.serviceType, A.datee, A.startTime
FROM booking as B, availability as A, customer as C,
address as AD, Service as S
WHERE
B.empid=501 AND B.custid=C.custid
AND C.custid=AD.id
AND B.serviceid=S.serviceid AND B.empid=A.empid;
The REQUIRED results should have been:
BookingID fname lname street doorno zipcode serviceType date starttime
1 X Y ABC 33 5335 Clean 2015-05-20 9
2 P Q NMO 55 8294 Shift 2015-06-11 11
But the results give me the cross product of tables:
BookingID fname lname street doorno zipcode serviceType date starttime
1 X Y ABC 33 5335 Clean 2015-05-20 9
1 X Y ABC 33 5335 Shift 2015-06-11 11
2 P Q NMO 55 8294 Clean 2015-05-20 9
2 P Q NMO 55 8294 Shift 2015-06-11 11
Please let me know what is wrong with my query.
The primary key for Availability is currently (empid, datee, startTime), yet the JOIN is done on just on Booking.empid - it is possible there is more than one availability row per Employee.
I believe you will need to add a timestamp to Booking and interpolate on date during the join to Availability:
CREATE TABLE Booking(
-- ...
bookingDate datetime NOT NULL,
-- ...
);
I would also suggest that you add and end datetime bounds to the Availability, and store Date and Time as one (otherwise you will need to continually add the time back in):
CREATE TABLE Availability(
-- ...
startDateTime datetime NOT NULL,
endDateTime datetime NOT NULL,
PRIMARY KEY (empid, startDateTime), -- Put some rules to prevent overlap
);
The query then interpolates Booking to Availability on Date and Time:
SELECT B.bookingid, C.fname, C.lname, AD.street, AD.doorno, AD.zip,
S.serviceType, A.startDateTime
FROM
booking as B
INNER JOIN customer as C
ON B.custid=C.custid
INNER JOIN availability as A
ON B.empid=A.empid AND b.bookingDate BETWEEN A.startDateTime AND A.endDateTime
INNER JOIN address as AD
ON C.custid=AD.id
INNER JOIN Service as S
ON B.serviceid=S.serviceid
WHERE
B.empid=501;
I've also adjusted the join to use JOIN ON rather than doing the join in the WHERE.
This would address the duplicated availability data. However, I can't see how ServiceType would be different for the same booking.
You can use DISTINCT to eliminate duplicate records. Also always try to use explicit joins.
SELECT DISTINCT B.bookingid, C.fname, C.lname, AD.street,
AD.doorno, AD.zip,S.serviceType, A.datee, A.startTime
FROM booking as B
INNER JOIN availability as A ON B.empid = A.empid
INNER JOIN customer as C ON B.custid = C.custid
INNER JOIN address as AD ON C.custid = AD.id
INNER JOIN Service as S ON B.serviceid = S.serviceid
WHERE B.empid = 501