Compare commits

...

10 Commits

34 changed files with 893 additions and 10 deletions
+4
View File
@@ -1,2 +1,6 @@
# MySQL Workbench project backup files # MySQL Workbench project backup files
*.mwb.bak *.mwb.bak
# Python
.ipynb_checkpoints
__pycache__
+7 -7
View File
@@ -19,7 +19,7 @@ USE `LittleLemonDB` ;
-- Table `LittleLemonDB`.`Addresses` -- Table `LittleLemonDB`.`Addresses`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Addresses` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Addresses` (
`AddressID` INT NOT NULL, `AddressID` INT NOT NULL AUTO_INCREMENT,
`Street` VARCHAR(255) NOT NULL, `Street` VARCHAR(255) NOT NULL,
`PostalCode` VARCHAR(12) NOT NULL, `PostalCode` VARCHAR(12) NOT NULL,
`City` VARCHAR(255) NOT NULL, `City` VARCHAR(255) NOT NULL,
@@ -32,7 +32,7 @@ ENGINE = InnoDB;
-- Table `LittleLemonDB`.`Customers` -- Table `LittleLemonDB`.`Customers`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Customers` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Customers` (
`CustomerID` INT NOT NULL, `CustomerID` INT NOT NULL AUTO_INCREMENT,
`FirstName` VARCHAR(255) NOT NULL, `FirstName` VARCHAR(255) NOT NULL,
`LastName` VARCHAR(255) NOT NULL, `LastName` VARCHAR(255) NOT NULL,
`PhoneNumber` VARCHAR(45) NOT NULL, `PhoneNumber` VARCHAR(45) NOT NULL,
@@ -52,7 +52,7 @@ ENGINE = InnoDB;
-- Table `LittleLemonDB`.`Employees` -- Table `LittleLemonDB`.`Employees`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Employees` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Employees` (
`EmployeeID` INT NOT NULL, `EmployeeID` INT NOT NULL AUTO_INCREMENT,
`FirstName` VARCHAR(255) NOT NULL, `FirstName` VARCHAR(255) NOT NULL,
`LastName` VARCHAR(255) NOT NULL, `LastName` VARCHAR(255) NOT NULL,
`PhoneNumber` VARCHAR(45) NOT NULL, `PhoneNumber` VARCHAR(45) NOT NULL,
@@ -74,7 +74,7 @@ ENGINE = InnoDB;
-- Table `LittleLemonDB`.`Bookings` -- Table `LittleLemonDB`.`Bookings`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Bookings` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Bookings` (
`BookingID` INT NOT NULL, `BookingID` INT NOT NULL AUTO_INCREMENT,
`Reserved` DATETIME NOT NULL, `Reserved` DATETIME NOT NULL,
`TableNumber` INT NOT NULL, `TableNumber` INT NOT NULL,
`CustomerID` INT NOT NULL, `CustomerID` INT NOT NULL,
@@ -99,7 +99,7 @@ ENGINE = InnoDB;
-- Table `LittleLemonDB`.`MenuItems` -- Table `LittleLemonDB`.`MenuItems`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`MenuItems` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`MenuItems` (
`MenuItemID` INT NOT NULL, `MenuItemID` INT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(255) NOT NULL, `Name` VARCHAR(255) NOT NULL,
`Category` VARCHAR(255) NOT NULL, `Category` VARCHAR(255) NOT NULL,
`Price` DECIMAL(6,2) NOT NULL, `Price` DECIMAL(6,2) NOT NULL,
@@ -112,7 +112,7 @@ ENGINE = InnoDB;
-- Table `LittleLemonDB`.`Orders` -- Table `LittleLemonDB`.`Orders`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Orders` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`Orders` (
`OrderID` INT NOT NULL, `OrderID` INT NOT NULL AUTO_INCREMENT,
`Started` DATETIME NOT NULL, `Started` DATETIME NOT NULL,
`Finished` DATETIME NULL, `Finished` DATETIME NULL,
`BillAmount` DECIMAL(10,2) NULL, `BillAmount` DECIMAL(10,2) NULL,
@@ -131,7 +131,7 @@ ENGINE = InnoDB;
-- Table `LittleLemonDB`.`OrderItems` -- Table `LittleLemonDB`.`OrderItems`
-- ----------------------------------------------------- -- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`OrderItems` ( CREATE TABLE IF NOT EXISTS `LittleLemonDB`.`OrderItems` (
`OrderItemID` INT NOT NULL, `OrderItemID` INT NOT NULL AUTO_INCREMENT,
`Ordered` DATETIME NOT NULL, `Ordered` DATETIME NOT NULL,
`Delivered` DATETIME NULL, `Delivered` DATETIME NULL,
`DeliveryStatus` VARCHAR(45) NOT NULL, `DeliveryStatus` VARCHAR(45) NOT NULL,
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

+3 -3
View File
@@ -2,11 +2,11 @@ name: capstone-project
channels: channels:
- conda-forge - conda-forge
dependencies: dependencies:
- pip
- python=3.13 - python=3.13
- pynvim - pip
- pytest - jupyter
- mysql-connector-python - mysql-connector-python
- pynvim
- pip: - pip:
- ruff - ruff
- basedpyright - basedpyright
+216
View File
@@ -0,0 +1,216 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "3228e84e-083c-48f6-9913-9d96e2fd0a2a",
"metadata": {},
"source": [
"# Promotional campaign"
]
},
{
"cell_type": "markdown",
"id": "71a559ef-75a7-4aca-86aa-10629e047222",
"metadata": {},
"source": [
"## Imports"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "8fe32f7f-09b3-4d9a-af26-4146c500bf44",
"metadata": {},
"outputs": [],
"source": [
"from decimal import Decimal\n",
"from mysql.connector import CMySQLConnection, Error, connect\n",
"from mysql.connector.cursor_cext import CMySQLCursor"
]
},
{
"cell_type": "markdown",
"id": "70da0c3b-ae18-4b60-a7eb-1c0c75c3677a",
"metadata": {},
"source": [
"## Task 1"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ac95c33d-3ead-4dab-b007-4f20d37f7386",
"metadata": {},
"outputs": [],
"source": [
"connection = connect(\n",
" user=\"tobias\",\n",
" unix_socket=\"/run/mysqld/mysqld.sock\",\n",
" database=\"LittleLemonDB\",\n",
" use_pure=False,\n",
" autocommit=True,\n",
")\n",
"assert isinstance(connection, CMySQLConnection)"
]
},
{
"cell_type": "markdown",
"id": "19e74d2d-2b40-4a1b-a57e-38f27106220b",
"metadata": {},
"source": [
"## Task 2"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "1b386dae-78e4-44db-90e5-6da378de16fe",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Tables:\n",
" Addresses\n",
" Bookings\n",
" Customers\n",
" Employees\n",
" MenuItems\n",
" OrderItems\n",
" Orders\n"
]
}
],
"source": [
"try:\n",
" with connection.cursor() as cursor:\n",
" assert isinstance(cursor, CMySQLCursor)\n",
"\n",
" _ = cursor.execute(\"show tables\")\n",
" print(\"Tables:\")\n",
" for (table_name,) in cursor:\n",
" print(f\" {table_name}\")\n",
"except Error as err:\n",
" print(err)"
]
},
{
"cell_type": "markdown",
"id": "62e2485b-1391-4fc6-aa73-35d0ebd8e95d",
"metadata": {},
"source": [
"## Task 3\n",
"**SQL query in `sql/promotional_campaign.sql`:**\n",
"```sql\n",
"select\n",
" C.FirstName,\n",
" C.LastName,\n",
" C.PhoneNumber,\n",
" C.EmailAddress,\n",
" max(O.BillAmount) as MaxBillAmount\n",
"from Orders as O\n",
"inner join Bookings as B on O.BookingID = B.BookingID\n",
"inner join Customers as C on B.CustomerID = C.CustomerID\n",
"group by C.CustomerID\n",
"having MaxBillAmount > 60.00;\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "214d0b0e-dd5b-4113-b6d7-aca020655ef3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Customers that placed an order greater then 60.00€:\n",
" Li Wei Zhang\n",
" Minimum bill amount: 82.50€\n",
" Phone number: +86123456789\n",
" Email address: li.wei.zhang@example.com\n",
" Ivanov Petrov\n",
" Minimum bill amount: 150.50€\n",
" Phone number: +70987654321\n",
" Email address: ivanov.petrov@example.com\n"
]
}
],
"source": [
"with open(\"./sql/promotional_campaign.sql\") as promo_campaign_file:\n",
" promo_campain_request = promo_campaign_file.read()\n",
" \n",
"try:\n",
" with connection.cursor() as cursor:\n",
" assert isinstance(cursor, CMySQLCursor)\n",
" _ = cursor.execute(promo_campain_request)\n",
"\n",
" print()\n",
"\n",
" print(\"Customers that placed an order greater then 60.00€:\")\n",
" for (\n",
" first_name,\n",
" last_name,\n",
" phone_number,\n",
" email_address,\n",
" min_bill_amount,\n",
" ) in cursor:\n",
" assert isinstance(first_name, str)\n",
" assert isinstance(last_name, str)\n",
" assert isinstance(phone_number, str)\n",
" assert isinstance(email_address, str | None)\n",
" assert isinstance(min_bill_amount, Decimal)\n",
" print(f\" {first_name} {last_name}\")\n",
" print(f\" Minimum bill amount: {min_bill_amount}€\")\n",
" print(f\" Phone number: {phone_number}\")\n",
" if email_address:\n",
" print(f\" Email address: {email_address}\")\n",
"except Error as err:\n",
" print(err)"
]
},
{
"cell_type": "markdown",
"id": "be3c702d-5ab6-47a6-a19b-4e26aefdbd6e",
"metadata": {},
"source": [
"## Cleanup"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "e7f0a6dc-4940-4f8b-a89c-e714e9d375ba",
"metadata": {},
"outputs": [],
"source": [
"connection.close()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+19
View File
@@ -0,0 +1,19 @@
[tool.sqlfluff.core]
dialiact = "mysql"
max_line_length = 110
exclude_rules = "ST06"
[tool.sqlfluff.rules.capitalisation.keywords]
capitalisation_policy = "lower"
[tool.sqlfluff.rules.capitalisation.identifiers]
extended_capitalisation_policy = "pascal"
[tool.sqlfluff.rules.capitalisation.types]
extended_capitalisation_policy = "lower"
[tool.sqlfluff.rules.references.keywords]
ignore_words = "role"
[tool.sqlfluff.indentation]
allow_implicit_indents = true
+15
View File
@@ -0,0 +1,15 @@
-- modify bookings - task 1
-- changes:
-- changed BookingDate (Reserved) data type from date to datetime, because I assumed that Little Lemon
-- allows wants bookings per day and table - a table is considered blocked for 2 hours
-- added EmployeeID input parameter
-- noqa: disable=CP03,LT02,RF03
create procedure AddBooking (
in BookingID int, in Reserved datetime, in TableNumber int, in CustomerID int, in EmployeeID int
)
begin
insert into Bookings (BookingID, Reserved, TableNumber, CustomerID, EmployeeID) values (
BookingID, Reserved, TableNumber, CustomerID, EmployeeID
);
select concat("New booking added") as Confirmation;
end
+30
View File
@@ -0,0 +1,30 @@
-- available bookings - task 3
-- changes:
-- changed BookingDate (Reserved) data type from date to datetime, because I assumed that Little Lemon
-- allows wants bookings per day and table - a table is considered blocked for 2 hours
-- added CustomerID and EmployeeID input parameters
-- noqa: disable=CP03,LT02,RF03
--
create procedure AddValidBooking (
in Reserved datetime, in TableNumber int, in CustomerID int, in EmployeeID int
)
begin
start transaction;
if TableIsFree(Reserved, TableNumber) then
insert into Bookings (Reserved, TableNumber, CustomerID, EmployeeID) values (
Reserved, TableNumber, CustomerID, EmployeeID
);
commit;
select concat(
"Table ", TableNumber,
" was free - booking accepted (BookingID=", (select last_insert_id()), ')'
) as BookingStatus;
else
rollback;
select concat(
"Table ", TableNumber,
" is already booked - booking cancelled"
) as BookingStatus;
end if;
end
+97
View File
@@ -0,0 +1,97 @@
# Task 1
> source ./example_bookings.sql
> select * from `Bookings` where `BookingID` between 11 and 14
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 11 | 2022-10-14 18:00:00 | 5 | 1 | 1 |
| 12 | 2022-11-12 19:30:00 | 3 | 3 | 1 |
| 13 | 2022-10-11 18:45:00 | 2 | 2 | 1 |
| 14 | 2022-10-13 19:15:00 | 2 | 1 | 1 |
+-----------+---------------------+-------------+------------+------------+
# Task 2
> delimiter $
> source ./table_is_free.sql
> source ./check_booking.sql
> delimiter ;
> call CheckBooking("2022-11-12 18:15:00", 3, @IsFree);
+---------------------------+
| BookingStatus |
+---------------------------+
| Table 3 is already booked |
+---------------------------+
> select @IsFree;
+---------+
| @IsFree |
+---------+
| 0 |
+---------+
> call CheckBooking("2022-11-12 17:15:00", 3, @IsFree);
+-----------------+
| BookingStatus |
+-----------------+
| Table 3 is free |
+-----------------+
> select @IsFree;
+---------+
| @IsFree |
+---------+
| 1 |
+---------+
# Task 3
> delimiter $
> source ./add_valid_booking.sql
> delimiter ;
> call AddValidBooking("2022-11-12 18:15:00", 3, 4, 1);
+-----------------------------------------------+
| BookingStatus |
+-----------------------------------------------+
| Table 3 is already booked - booking cancelled |
+-----------------------------------------------+
> select * from `Bookings`
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 1 | 2024-11-14 18:00:00 | 1 | 3 | 1 |
| 2 | 2024-11-14 19:30:00 | 2 | 2 | 1 |
| 3 | 2024-11-14 18:45:00 | 3 | 4 | 1 |
| 4 | 2024-11-14 19:15:00 | 4 | 1 | 2 |
| 5 | 2024-11-14 18:30:00 | 5 | 6 | 2 |
| 6 | 2024-11-14 19:00:00 | 6 | 5 | 2 |
| 7 | 2024-11-15 18:15:00 | 1 | 7 | 5 |
| 8 | 2024-11-15 19:45:00 | 2 | 8 | 5 |
| 9 | 2024-11-15 18:30:00 | 3 | 9 | 2 |
| 10 | 2024-11-15 19:00:00 | 4 | 10 | 5 |
| 11 | 2022-10-14 18:00:00 | 5 | 1 | 1 |
| 12 | 2022-11-12 19:30:00 | 3 | 3 | 1 |
| 13 | 2022-10-11 18:45:00 | 2 | 2 | 1 |
| 14 | 2022-10-13 19:15:00 | 2 | 1 | 1 |
+-----------+---------------------+-------------+------------+------------+
> call AddValidBooking("2022-11-12 17:15:00", 3, 4, 1);
+----------------------------------------------------+
| BookingStatus |
+----------------------------------------------------+
| Table 3 was free - booking accepted (BookingID=15) |
+----------------------------------------------------+
> select * from `Bookings`
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 1 | 2024-11-14 18:00:00 | 1 | 3 | 1 |
| 2 | 2024-11-14 19:30:00 | 2 | 2 | 1 |
| 3 | 2024-11-14 18:45:00 | 3 | 4 | 1 |
| 4 | 2024-11-14 19:15:00 | 4 | 1 | 2 |
| 5 | 2024-11-14 18:30:00 | 5 | 6 | 2 |
| 6 | 2024-11-14 19:00:00 | 6 | 5 | 2 |
| 7 | 2024-11-15 18:15:00 | 1 | 7 | 5 |
| 8 | 2024-11-15 19:45:00 | 2 | 8 | 5 |
| 9 | 2024-11-15 18:30:00 | 3 | 9 | 2 |
| 10 | 2024-11-15 19:00:00 | 4 | 10 | 5 |
| 11 | 2022-10-14 18:00:00 | 5 | 1 | 1 |
| 12 | 2022-11-12 19:30:00 | 3 | 3 | 1 |
| 13 | 2022-10-11 18:45:00 | 2 | 2 | 1 |
| 14 | 2022-10-13 19:15:00 | 2 | 1 | 1 |
| 15 | 2022-11-12 17:15:00 | 3 | 4 | 1 |
+-----------+---------------------+-------------+------------+------------+
+13
View File
@@ -0,0 +1,13 @@
-- modify bookings - task 3
-- add and update bookings - task 3
-- noqa: disable=CP03,LT02,RF03
create procedure CancelBooking (in BookingID int)
begin
delete from Bookings as B
where B.BookingID = BookingID;
if row_count() = 1 then
select concat("Booking ", BookingID, " cancelled") as Confirmation;
else
select concat("Booking ", BookingID, " not cancelled - missing booking") as Confirmation;
end if;
end
+9
View File
@@ -0,0 +1,9 @@
-- query optimization - task 3
-- noqa: disable=CP03
create procedure CancelOrder (in TargetOrderID int)
begin
delete from Orders
where OrderID = TargetOrderID;
select concat("Order ", TargetOrderID, if(row_count() = 1, " is cancelled", " doesn't exist")) as Confirmation;
end
+10
View File
@@ -0,0 +1,10 @@
-- available bookings - task 2
-- changes:
-- changed BookingDate (Reserved) data type from date to datetime, because I assumed that Little Lemon
-- allows wants bookings per day and table - a table is considered blocked for 2 hours
-- noqa: disable=CP03,LT02,RF03
create procedure CheckBooking (in Reserved datetime, in TableNumber int, out IsFree boolean) --
begin
set IsFree = TableIsFree(Reserved, TableNumber);
select concat("Table ", TableNumber, " is ", if(IsFree, "free", "already booked")) as BookingStatus;
end
+15
View File
@@ -0,0 +1,15 @@
-- sales report - task 1
-- changes:
-- interpreted quantity as the number of ordered items, because I assumed that Little lemon wants
-- orders à la carte instead of fixed menus
drop view if exists OrdersView;
create view OrdersView as
select
O.OrderID,
count(OI.MenuItemID) as Quantity,
O.BillAmount as Cost
from Orders as O
inner join OrderItems as OI on O.OrderID = OI.OrderID
group by O.OrderID
having Quantity > 2;
+12
View File
@@ -0,0 +1,12 @@
-- available bookings - task 1
-- changes:
-- changed BookingDate (Reserved) data type from date to datetime, because I assumed that Little Lemon
-- allows wants bookings per day and table - a table is considered blocked for 2 hours
-- changed BookingID range from 1-4 to 11-14, because there are already 10 Bookings in my test data set
-- added arbitrary EmployeeID that corresponds to the Employee that handled the booking process
-- noqa: disable=CP03
insert into Bookings (BookingID, Reserved, TableNumber, CustomerID, EmployeeID) values
(11, '2022-10-14 18:00:00', 5, 1, 1),
(12, '2022-11-12 19:30:00', 3, 3, 1),
(13, '2022-10-11 18:45:00', 2, 2, 1),
(14, '2022-10-13 19:15:00', 2, 1, 1);
+47
View File
@@ -0,0 +1,47 @@
-- sales report - task 2
-- changes:
-- removed menu name, because I assumed that Little lemon wants orders à la carte instead of fixed menus
-- changed cost cutoff from 150.00 to 75.00, because I wanted more than one test result
with
GroupedOrderItems as (
select
OI.OrderID,
MI.Category,
concat(MI.Name, " (", count(OI.OrderItemID), "x)") as Item
from OrderItems as OI
inner join MenuItems as MI on OI.MenuItemID = MI.MenuItemID
group by OI.OrderID, MI.Category, OI.MenuItemID
),
MainOrderItems as (
select
OrderID,
group_concat(Item separator '\n') as Items
from GroupedOrderItems
where Category = "Main"
group by OrderID
),
StarterOrderItems as (
select
OrderID,
group_concat(Item separator '\n') as Items
from GroupedOrderItems
where Category = "Starter"
group by OrderID
)
select
C.CustomerID,
concat(C.FirstName, " ", C.LastName) as FullName,
O.OrderID,
O.BillAmount as Cost,
coalesce(MOI.Items, "") as Mains,
coalesce(SOI.Items, "") as Starters
from Orders as O
inner join Bookings as B on O.BookingID = B.BookingID
inner join Customers as C on B.CustomerID = C.CustomerID
left join MainOrderItems as MOI on O.OrderID = MOI.OrderID
left join StarterOrderItems as SOI on O.OrderID = SOI.OrderID
where O.BillAmount > 75.00
group by O.OrderID;
+12
View File
@@ -0,0 +1,12 @@
-- query optimization - task 1
-- changes:
-- interpreted quantity as the number of items in an order, because I assumed that Little lemon wants
-- orders à la carte instead of fixed menus
create procedure GetMaxQuantity () -- noqa: disable=CP03
select count(OI.OrderItemID) as MaxQuantityInOrder
from MenuItems as MI
inner join OrderItems as OI on MI.MenuItemID = OI.MenuItemID
group by OI.OrderID
order by MaxQuantityInOrder desc
limit 1
+15
View File
@@ -0,0 +1,15 @@
-- query optimization - task 2
-- changes:
-- interpreted quantity as the number of items in an order, because I assumed that Little lemon wants
-- orders à la carte instead of fixed menus
prepare GetOrderDetail from "
select
O.OrderID,
count(OI.MenuItemID) as Quantity,
O.BillAmount as Cost
from Orders as O
inner join OrderItems as OI on O.OrderID = OI.OrderID
inner join Bookings as B on O.BookingID = B.BookingID
where B.CustomerID = ?;
";
+11
View File
@@ -0,0 +1,11 @@
-- sales report - task 3
-- changes:
-- replaced menu name with menu item name, because I assumed that Little lemon wants orders à la carte
-- instead of fixed menus
select
MI.Name,
count(OI.OrderItemID) as OrderQuantity
from MenuItems as MI
inner join OrderItems as OI on MI.MenuItemID = OI.MenuItemID
group by OI.MenuItemID
having OrderQuantity > 2;
+126
View File
@@ -0,0 +1,126 @@
delete from MenuItems;
insert into MenuItems (MenuItemID, Name, Category, Price) values
(1, "Grilled Artichokes", "Starter", 6.00),
(2, "Lentil Soup", "Starter", 7.00),
(3, "Humus Plate", "Starter", 6.00),
(4, "Eggplant Bruschetta", "Starter", 7.00),
(5, "Gigantes Plaki", "Main", 14.00),
(6, "Minestrone", "Main", 16.00),
(7, "Moussaka", "Main", 17.00),
(8, "Pasta alla Norma", "Main", 12.00),
(9, "Tabbouleh", "Salad", 8.00),
(10, "Green Bean Salad", "Salad", 8.00),
(11, "Tomato Salad", "Salad", 9.50),
(12, "Fennel Salad", "Salad", 8.50),
(13, "Fruit Salad", "Desert", 7.00),
(14, "Roasted Grapes", "Desert", 6.50),
(15, "Grilled Mango", "Desert", 8.50),
(16, "Grilled Waterlemon", "Desert", 8.50);
delete from Addresses;
insert into Addresses (AddressID, Street, PostalCode, City, Country) values
(1, 'Hauptstraße 1', '10115', 'Berlin', 'Germany'),
(2, 'Friedrichstraße 56', '10119', 'Berlin', 'Germany'),
(3, 'Kurfürstenstraße 135', '10115', 'Berlin', 'Germany'),
(4, 'Altenhofen 168', '10623', 'Berlin', 'Germany'),
(5, 'Hauptstraße 180', '10116', 'Berlin', 'Germany');
delete from Employees;
insert into Employees (
EmployeeID, FirstName, LastName, PhoneNumber, EmailAddress, Role, AnnualSalary, AddressID
) values
(1, 'Mario', 'Gollini', '+4915123456789', 'mario.gollini@littlelemon.de', 'Manager', 72383.00, 1),
(2, 'Adrian', 'Gollini', '+4916198765432', 'adrian.gollini@littlelemon.de', 'Receptionist', 74083.00, 2),
(3, 'Giorgos', 'Dioudis', '+4917654321098', 'giogos.dioudis@littlelemon.de', 'Assistant Chef', 77912.00, 3),
(4, 'Fatma', 'Kaya', '+4918765432190', 'fatma.kaya@littlelemon.de', 'Head Chef', 79314.00, 4),
(5, 'Elena', 'Salvai', '+4919876543210', 'elena.salvai@littlelemon.de', 'Waiter', 78921.00, 5);
delete from Customers;
insert into Customers (
CustomerID, FirstName, LastName, PhoneNumber, EmailAddress, AddressID
)
values
(1, 'Ahmed', 'Mohamed', '+20212345678', 'ahmed.mohamed@example.com', null),
(2, 'Sophie', 'Dupont', '+33612345678', 'sophie.dupont@example.com', null),
(3, 'Li Wei', 'Zhang', '+86123456789', 'li.wei.zhang@example.com', null),
(4, 'Maria', 'Rodriguez', '+34612345678', 'maria.rodriguez@example.com', null),
(5, 'Ivanov', 'Petrov', '+70987654321', 'ivanov.petrov@example.com', null),
(6, 'José', 'Martinez', '+54987654321', 'jose.martinez@example.com', null),
(7, 'Maria', 'Schmidt', '+49987654321', 'maria.schmidt@example.com', null),
(8, 'Thomas', 'Müller', '+44987654321', 'thomas.mueller@example.com', null),
(9, 'Ramón', 'García', '+58987654321', 'ramon.garcia@example.com', null),
(10, 'Lee', 'Kim', '+82109876543', 'lee.kim@example.com', null);
delete from Bookings;
insert into Bookings (BookingID, Reserved, TableNumber, CustomerID, EmployeeID)
values
(1, '2024-11-14 18:00:00', 1, 3, 1),
(2, '2024-11-14 19:30:00', 2, 2, 1),
(3, '2024-11-14 18:45:00', 3, 4, 1),
(4, '2024-11-14 19:15:00', 4, 1, 2),
(5, '2024-11-14 18:30:00', 5, 6, 2),
(6, '2024-11-14 19:00:00', 6, 5, 2),
(7, '2024-11-15 18:15:00', 1, 7, 5),
(8, '2024-11-15 19:45:00', 2, 8, 5),
(9, '2024-11-15 18:30:00', 3, 9, 2),
(10, '2024-11-15 19:00:00', 4, 10, 5);
insert into Orders (OrderID, Started, Finished, BillAmount, BookingID)
values
(1, '2024-11-14 18:05:00', '2023-10-01 19:25:00', null, 1),
(2, '2024-11-14 19:35:00', '2023-10-02 20:45:00', null, 2),
(3, '2024-11-14 19:10:00', '2023-10-03 20:30:00', null, 3),
(4, '2024-11-14 19:35:00', '2023-10-04 20:50:00', null, 4),
(5, '2024-11-14 19:40:00', '2023-10-05 20:55:00', null, 5),
(6, '2024-11-14 19:40:00', '2023-10-06 20:45:00', null, 6);
insert into OrderItems (OrderItemID, MenuItemID, OrderID, Ordered, Delivered, DeliveryStatus)
values
(1, 1, 1, '2024-11-14 18:05:00', '2024-11-14 18:25:00', 'Delivered'),
(2, 2, 1, '2024-11-14 18:05:00', '2024-11-14 18:25:00', 'Delivered'),
(3, 3, 1, '2024-11-14 18:05:00', '2024-11-14 18:25:00', 'Delivered'),
(4, 5, 1, '2024-11-14 18:05:00', '2024-11-14 18:40:00', 'Delivered'),
(5, 5, 1, '2024-11-14 18:05:00', '2024-11-14 18:40:00', 'Delivered'),
(6, 8, 1, '2024-11-14 18:05:00', '2024-11-14 18:40:00', 'Delivered'),
(7, 14, 1, '2024-11-14 18:05:00', '2024-11-14 19:05:00', 'Delivered'),
(8, 15, 1, '2024-11-14 18:05:00', '2024-11-14 19:05:00', 'Delivered'),
(9, 16, 1, '2024-11-14 18:05:00', '2024-11-14 19:05:00', 'Delivered'),
(10, 2, 2, '2024-11-14 19:35:00', '2024-11-14 19:55:00', 'Delivered'),
(11, 5, 2, '2024-11-14 19:35:00', '2024-11-14 20:10:00', 'Delivered'),
(12, 13, 2, '2024-11-14 19:35:00', '2024-11-14 20:35:00', 'Delivered'),
(13, 4, 3, '2024-11-14 19:10:00', '2024-11-14 19:30:00', 'Delivered'),
(14, 7, 3, '2024-11-14 19:10:00', '2024-11-14 19:45:00', 'Delivered'),
(15, 13, 3, '2024-11-14 19:10:00', '2024-11-14 20:10:00', 'Delivered'),
(16, 3, 4, '2024-11-14 19:35:00', '2024-11-14 19:55:00', 'Delivered'),
(17, 6, 4, '2024-11-14 19:35:00', '2024-11-14 20:10:00', 'Delivered'),
(18, 13, 4, '2024-11-14 19:35:00', '2024-11-14 20:35:00', 'Delivered'),
(19, 9, 5, '2024-11-14 19:40:00', '2024-11-14 20:00:00', 'Delivered'),
(20, 8, 5, '2024-11-14 19:40:00', '2024-11-14 20:15:00', 'Delivered'),
(22, 2, 6, '2024-11-14 19:40:00', '2024-11-14 19:55:00', 'Delivered'),
(23, 4, 6, '2024-11-14 19:40:00', '2024-11-14 19:55:00', 'Delivered'),
(24, 2, 6, '2024-11-14 19:40:00', '2024-11-14 19:55:00', 'Delivered'),
(25, 3, 6, '2024-11-14 19:40:00', '2024-11-14 19:55:00', 'Delivered'),
(26, 1, 6, '2024-11-14 19:40:00', '2024-11-14 19:55:00', 'Delivered'),
(27, 6, 6, '2024-11-14 19:40:00', '2024-11-14 20:10:00', 'Delivered'),
(28, 6, 6, '2024-11-14 19:40:00', '2024-11-14 20:10:00', 'Delivered'),
(29, 5, 6, '2024-11-14 19:40:00', '2024-11-14 20:10:00', 'Delivered'),
(30, 5, 6, '2024-11-14 19:40:00', '2024-11-14 20:10:00', 'Delivered'),
(31, 7, 6, '2024-11-14 19:40:00', '2024-11-14 20:10:00', 'Delivered'),
(32, 15, 6, '2024-11-14 19:40:00', '2024-11-14 20:35:00', 'Delivered'),
(33, 14, 6, '2024-11-14 19:40:00', '2024-11-14 20:35:00', 'Delivered'),
(34, 15, 6, '2024-11-14 19:40:00', '2024-11-14 20:35:00', 'Delivered'),
(35, 16, 6, '2024-11-14 19:40:00', '2024-11-14 20:35:00', 'Delivered'),
(36, 16, 6, '2024-11-14 19:40:00', '2024-11-14 20:35:00', 'Delivered');
update Orders as O
inner join
(
select
OI.OrderID,
sum(MI.Price) as TotalItemPrice
from OrderItems as OI
inner join MenuItems as MI on OI.MenuItemID = MI.MenuItemID
group by OI.OrderID
) as A
on O.OrderID = A.OrderID
set O.BillAmount = A.TotalItemPrice;
+101
View File
@@ -0,0 +1,101 @@
# Task 1
> delimiter $
> source ./add_booking.sql
> delimiter ;
> call AddBooking(20, "2024-11-19 19:00:00", 3, 1, 2)
+-------------------+
| Confirmation |
+-------------------+
| New booking added |
+-------------------+
> select * from `Bookings` where `BookingID` = 20
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 20 | 2024-11-19 19:00:00 | 3 | 1 | 2 |
+-----------+---------------------+-------------+------------+------------+
# Task 2
> delimiter $
> source ./update_booking.sql
> delimiter ;
> call UpdateBooking(20, date_sub((select Reserved from `Bookings` where `BookingID` = 20), interval 1 day))
+--------------------+
| Confirmation |
+--------------------+
| Booking 20 updated |
+--------------------+
> select * from `Bookings` where `BookingID` = 20;
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 20 | 2024-11-18 19:00:00 | 3 | 1 | 2 |
+-----------+---------------------+-------------+------------+------------+
> call UpdateBooking(21, "2024-11-18 15:00:00")
+---------------------------------------------+
| Confirmation |
+---------------------------------------------+
| Booking 21 wasn't updated - missing booking |
+---------------------------------------------+
> select * from `Bookings` where `BookingID` = 21
+-----------+----------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+----------+-------------+------------+------------+
+-----------+----------+-------------+------------+------------+
# Task 3
> delimiter $
> source ./cancel_booking.sql
> delimiter ;
> call CancelBooking(20)
+----------------------+
| Confirmation |
+----------------------+
| Booking 20 cancelled |
+----------------------+
> select * from `Bookings`
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 1 | 2024-11-14 18:00:00 | 1 | 3 | 1 |
| 2 | 2024-11-14 19:30:00 | 2 | 2 | 1 |
| 3 | 2024-11-14 18:45:00 | 3 | 4 | 1 |
| 4 | 2024-11-14 19:15:00 | 4 | 1 | 2 |
| 5 | 2024-11-14 18:30:00 | 5 | 6 | 2 |
| 6 | 2024-11-14 19:00:00 | 6 | 5 | 2 |
| 7 | 2024-11-15 18:15:00 | 1 | 7 | 5 |
| 8 | 2024-11-15 19:45:00 | 2 | 8 | 5 |
| 9 | 2024-11-15 18:30:00 | 3 | 9 | 2 |
| 10 | 2024-11-15 19:00:00 | 4 | 10 | 5 |
| 11 | 2022-10-14 18:00:00 | 5 | 1 | 1 |
| 12 | 2022-11-12 19:30:00 | 3 | 3 | 1 |
| 13 | 2022-10-11 18:45:00 | 2 | 2 | 1 |
| 14 | 2022-10-13 19:15:00 | 2 | 1 | 1 |
| 15 | 2022-11-12 17:15:00 | 3 | 4 | 1 |
+-----------+---------------------+-------------+------------+------------+
> call CancelBooking(21)
+--------------------------------------------+
| Confirmation |
+--------------------------------------------+
| Booking 21 not cancelled - missing booking |
+--------------------------------------------+
> select * from `Bookings`
+-----------+---------------------+-------------+------------+------------+
| BookingID | Reserved | TableNumber | CustomerID | EmployeeID |
+-----------+---------------------+-------------+------------+------------+
| 1 | 2024-11-14 18:00:00 | 1 | 3 | 1 |
| 2 | 2024-11-14 19:30:00 | 2 | 2 | 1 |
| 3 | 2024-11-14 18:45:00 | 3 | 4 | 1 |
| 4 | 2024-11-14 19:15:00 | 4 | 1 | 2 |
| 5 | 2024-11-14 18:30:00 | 5 | 6 | 2 |
| 6 | 2024-11-14 19:00:00 | 6 | 5 | 2 |
| 7 | 2024-11-15 18:15:00 | 1 | 7 | 5 |
| 8 | 2024-11-15 19:45:00 | 2 | 8 | 5 |
| 9 | 2024-11-15 18:30:00 | 3 | 9 | 2 |
| 10 | 2024-11-15 19:00:00 | 4 | 10 | 5 |
| 11 | 2022-10-14 18:00:00 | 5 | 1 | 1 |
| 12 | 2022-11-12 19:30:00 | 3 | 3 | 1 |
| 13 | 2022-10-11 18:45:00 | 2 | 2 | 1 |
| 14 | 2022-10-13 19:15:00 | 2 | 1 | 1 |
| 15 | 2022-11-12 17:15:00 | 3 | 4 | 1 |
+-----------+---------------------+-------------+------------+------------+
+11
View File
@@ -0,0 +1,11 @@
select
C.FirstName,
C.LastName,
C.PhoneNumber,
C.EmailAddress,
max(O.BillAmount) as MaxBillAmount
from Orders as O
inner join Bookings as B on O.BookingID = B.BookingID
inner join Customers as C on B.CustomerID = C.CustomerID
group by C.CustomerID
having MaxBillAmount > 60.00;
+47
View File
@@ -0,0 +1,47 @@
# Task 1
> delimiter $
> source ./get_max_quantity.sql
> delimiter ;
> call GetMaxQuantity();
+--------------------+
| MaxQuantityInOrder |
+--------------------+
| 15 |
+--------------------+
# Task 2
> source ./get_order_detail.sql
> set @customerID = 1
> execute GetOrderDetail using @customerID
+---------+----------+-------+
| OrderID | Quantity | Cost |
+---------+----------+-------+
| 4 | 3 | 29.00 |
+---------+----------+-------+
# Task 3
> delimiter $
> source ./cancel_order.sql
> delimiter ;
> call CancelOrder(2)
+----------------------+
| Confirmation |
+----------------------+
| Order 2 is cancelled |
+----------------------+
> select * from `Orders`
+---------+---------------------+---------------------+------------+-----------+
| OrderID | Started | Finished | BillAmount | BookingID |
+---------+---------------------+---------------------+------------+-----------+
| 1 | 2024-11-14 18:05:00 | 2023-10-01 19:25:00 | 82.50 | 1 |
| 3 | 2024-11-14 19:10:00 | 2023-10-03 20:30:00 | 31.00 | 3 |
| 4 | 2024-11-14 19:35:00 | 2023-10-04 20:50:00 | 29.00 | 4 |
| 5 | 2024-11-14 19:40:00 | 2023-10-05 20:55:00 | 20.00 | 5 |
| 6 | 2024-11-14 19:40:00 | 2023-10-06 20:45:00 | 150.50 | 6 |
+---------+---------------------+---------------------+------------+-----------+
> call CancelOrder(2)
+-----------------------+
| Confirmation |
+-----------------------+
| Order 2 doesn't exist |
+-----------------------+
+40
View File
@@ -0,0 +1,40 @@
# Task 1
> source ./create_orders_view.sql
> select * from OrdersView;
+---------+----------+--------+
| OrderID | Quantity | Cost |
+---------+----------+--------+
| 1 | 9 | 82.50 |
| 2 | 3 | 28.00 |
| 3 | 3 | 31.00 |
| 4 | 3 | 29.00 |
| 6 | 15 | 150.50 |
+---------+----------+--------+
# Task 2
> source ./get_expensive_orders.sql
+------------+---------------+---------+--------+-----------------------+--------------------------+
| CustomerID | FullName | OrderID | Cost | Mains | Starters |
+------------+---------------+---------+--------+-----------------------+--------------------------+
| 3 | Li Wei Zhang | 1 | 82.50 | Gigantes Plaki (2x) | Grilled Artichokes (1x) |
| | | | | Pasta alla Norma (1x) | Lentil Soup (1x) |
| | | | | | Humus Plate (1x) |
| 5 | Ivanov Petrov | 6 | 150.50 | Minestrone (2x) | Lentil Soup (2x) |
| | | | | Gigantes Plaki (2x) | Eggplant Bruschetta (1x) |
| | | | | Moussaka (1x) | Humus Plate (1x) |
| | | | | | Grilled Artichokes (1x) |
+------------+---------------+---------+--------+-----------------------+--------------------------+
# Task 3
> source ./get_popular_menu_items.sql
+--------------------+---------------+
| Name | OrderQuantity |
+--------------------+---------------+
| Lentil Soup | 4 |
| Humus Plate | 3 |
| Gigantes Plaki | 5 |
| Minestrone | 3 |
| Fruit Salad | 3 |
| Grilled Mango | 3 |
| Grilled Waterlemon | 3 |
+--------------------+---------------+
+17
View File
@@ -0,0 +1,17 @@
-- available bookings - task 2
-- changes:
-- changed BookingDate (Reserved) data type from date to datetime, because I assumed that Little Lemon
-- allows wants bookings per day and table - a table is considered blocked for 2 hours
-- noqa: disable=CP03,LT02,RF03
create function TableIsFree(Reserved datetime, TableNumber int)
returns boolean
deterministic
begin
return (select not exists (
select BookingID
from Bookings as B
where
abs(timestampdiff(second, B.Reserved, Reserved)) < 2 * 60 * 60
and B.TableNumber = TableNumber
));
end
+16
View File
@@ -0,0 +1,16 @@
-- modify bookings - task 2
-- changes:
-- changed BookingDate (Reserved) data type from date to datetime, because I assumed that Little Lemon
-- allows wants bookings per day and table - a table is considered blocked for 2 hours
-- noqa: disable=CP03,LT02,RF03
create procedure UpdateBooking (in BookingID int, in Reserved datetime)
begin
update Bookings as B
set B.Reserved = Reserved
where B.BookingID = BookingID;
if row_count() = 1 then
select concat("Booking ", BookingID, " updated") as Confirmation;
else
select concat("Booking ", BookingID, " wasn't updated - missing booking") as Confirmation;
end if;
end