diff --git a/02_activities/assignments/Assignment2.md b/02_activities/assignments/Assignment2.md index 5cbb4e70f..8081d0e81 100644 --- a/02_activities/assignments/Assignment2.md +++ b/02_activities/assignments/Assignment2.md @@ -56,8 +56,35 @@ The store wants to keep customer addresses. Propose two architectures for the CU ``` Your answer... ``` - -*** +Type 1 (Overwriting) +CUSTOMER_ADDRESS (Type 1) +- address_id (PK) +- customer_id (FK) +- apartment +- street +- city +- state +- postal_code +- country +- is_primary +This architecture only maintains customer's current address, every time it updates it overwrites previous address. + +Type 2 (Historical Retention) +CUSTOMER_ADDRESS (Type 2) +- address_id (PK) +- customer_id (FK) +- apartment +- street +- city +- state +- postal_code +- country +- is_primary +- effective_date +- end_date +- current_flag (Y/N) + +The 2nd architecture keeps historical address for the customer through including the effective date and end date also with a indicator to identify the current active address. Every time it updates it will append the new records. ## Section 2: You can start this section following *session 4*. diff --git a/02_activities/assignments/W3_Assignment2 book logical model.pdf b/02_activities/assignments/W3_Assignment2 book logical model.pdf new file mode 100644 index 000000000..9cef2a98d Binary files /dev/null and b/02_activities/assignments/W3_Assignment2 book logical model.pdf differ diff --git a/02_activities/assignments/W3_Assignment2 book logical model_Extended with Shift.pdf b/02_activities/assignments/W3_Assignment2 book logical model_Extended with Shift.pdf new file mode 100644 index 000000000..776d89018 Binary files /dev/null and b/02_activities/assignments/W3_Assignment2 book logical model_Extended with Shift.pdf differ diff --git a/02_activities/assignments/assignment2.sql b/02_activities/assignments/assignment2.sql index 793d3d7eb..65e007f23 100644 --- a/02_activities/assignments/assignment2.sql +++ b/02_activities/assignments/assignment2.sql @@ -20,7 +20,9 @@ The `||` values concatenate the columns into strings. Edit the appropriate columns -- you're making two edits -- and the NULL rows will be fixed. All the other rows will remain the same.) */ - +SELECT + product_name || ', ' || COALESCE(product_size, '') || ' (' || COALESCE(product_qty_type, 'unit') || ')' +FROM product; --Windowed Functions /* 1. Write a query that selects from the customer_purchases table and numbers each customer’s @@ -32,18 +34,85 @@ each new market date for each customer, or select only the unique market dates p (without purchase details) and number those visits. HINT: One of these approaches uses ROW_NUMBER() and one uses DENSE_RANK(). */ +-- Approache One uses ROW_NUMBER() +SELECT + m.*, + ROW_NUMBER() OVER ( + PARTITION BY customer_id + ORDER BY market_date + ) AS customer_visit_number +FROM + customer_purchases m; +-- Approache One uses DENSE_RANK() + +SELECT + customer_id, + market_date, + DENSE_RANK() OVER ( + PARTITION BY customer_id + ORDER BY market_date + ) AS customer_visit_number +FROM + (SELECT DISTINCT customer_id, market_date FROM customer_purchases) AS unique_visits; /* 2. Reverse the numbering of the query from a part so each customer’s most recent visit is labeled 1, then write another query that uses this one as a subquery (or temp table) and filters the results to only the customer’s most recent visit. */ +-- Approache One uses ROW_NUMBER() reverser +SELECT + m.*, + ROW_NUMBER() OVER ( + PARTITION BY customer_id + ORDER BY market_date DESC + ) AS customer_visit_number +FROM + customer_purchases m; +-- Approache One uses DENSE_RANK() reverser + +SELECT + customer_id, + market_date, + DENSE_RANK() OVER ( + PARTITION BY customer_id + ORDER BY market_date DESC + ) AS customer_visit_number +FROM + (SELECT DISTINCT customer_id, market_date FROM customer_purchases) AS unique_visits; + +-- + +WITH ranked_visits AS ( + SELECT + customer_id, + market_date, + ROW_NUMBER() OVER ( + PARTITION BY customer_id + ORDER BY market_date DESC + ) AS visit_rank + FROM + (SELECT DISTINCT customer_id, market_date FROM customer_purchases) AS unique_visits +) +SELECT + customer_id, + market_date AS most_recent_visit_date +FROM + ranked_visits +WHERE + visit_rank = 1; /* 3. Using a COUNT() window function, include a value along with each row of the customer_purchases table that indicates how many different times that customer has purchased that product_id. */ - +SELECT + cp.*, + COUNT(*) OVER ( + PARTITION BY customer_id, product_id + ) AS customer_product_purchase_count +FROM + customer_purchases cp; -- String manipulations /* 1. Some product names in the product table have descriptions like "Jar" or "Organic". @@ -57,7 +126,18 @@ Remove any trailing or leading whitespaces. Don't just use a case statement for Hint: you might need to use INSTR(product_name,'-') to find the hyphens. INSTR will help split the column. */ - +SELECT + product_name, + CASE + WHEN INSTR(product_name, '-') > 0 + THEN TRIM(SUBSTR( + product_name, + INSTR(product_name, '-') + 1 + )) + ELSE NULL + END AS description +FROM + product; -- UNION @@ -71,7 +151,41 @@ HINT: There are a possibly a few ways to do this query, but if you're struggling with a UNION binding them. */ - +WITH daily_sales AS ( + SELECT + market_date, + SUM(quantity * cost_to_customer_per_qty) AS total_sales + FROM + customer_purchases + GROUP BY + market_date +) + +SELECT * FROM ( + SELECT + market_date, + total_sales, + 'Highest Sales Day' AS sales_category + FROM + daily_sales + ORDER BY + total_sales DESC + LIMIT 1 +) AS highest + +UNION ALL + +SELECT * FROM ( + SELECT + market_date, + total_sales, + 'Lowest Sales Day' AS sales_category + FROM + daily_sales + ORDER BY + total_sales ASC + LIMIT 1 +) AS lowest; /* SECTION 3 */ @@ -87,6 +201,18 @@ How many customers are there (y). Before your final group by you should have the product of those two queries (x*y). */ +SELECT + v.vendor_name, + p.product_name, + (5 * vi.original_price * (SELECT COUNT(*) FROM customer)) AS projected_revenue +FROM ( + SELECT DISTINCT vendor_id, product_id, original_price + FROM vendor_inventory +) vi +JOIN vendor v ON vi.vendor_id = v.vendor_id +JOIN product p ON vi.product_id = p.product_id +ORDER BY projected_revenue DESC, v.vendor_name, p.product_name; + -- INSERT /*1. Create a new table "product_units". @@ -94,11 +220,35 @@ This table will contain only products where the `product_qty_type = 'unit'`. It should use all of the columns from the product table, as well as a new column for the `CURRENT_TIMESTAMP`. Name the timestamp column `snapshot_timestamp`. */ - +CREATE TABLE product_units AS +SELECT + p.*, + CURRENT_TIMESTAMP AS snapshot_timestamp +FROM + product p +WHERE + product_qty_type = 'unit'; /*2. Using `INSERT`, add a new row to the product_units table (with an updated timestamp). This can be any product you desire (e.g. add another record for Apple Pie). */ +INSERT INTO product_units ( + product_id, + product_name, + product_size, + product_category_id, + product_qty_type, + snapshot_timestamp + +) +VALUES ( + (SELECT MAX(product_id) + 1 FROM product_units), -- Auto-generate a new ID + 'Butter Tart', + '1 dozen', + 3, + 'unit', + CURRENT_TIMESTAMP +); -- DELETE @@ -106,7 +256,15 @@ This can be any product you desire (e.g. add another record for Apple Pie). */ HINT: If you don't specify a WHERE clause, you are going to have a bad time.*/ - +DELETE FROM product_units +WHERE product_id = ( + SELECT product_id + FROM product_units + WHERE product_name = 'Butter Tart' + ORDER BY snapshot_timestamp ASC + LIMIT 1 +) +AND product_name = 'Butter Tart'; -- UPDATE /* 1.We want to add the current_quantity to the product_units table. @@ -126,5 +284,17 @@ Finally, make sure you have a WHERE statement to update the right row, When you have all of these components, you can run the update statement. */ - - +UPDATE product_units pu +SET current_quantity = COALESCE( + ( + SELECT vi.quantity + FROM vendor_inventory vi + WHERE vi.product_id = pu.product_id + AND vi.market_date = ( + SELECT MAX(market_date) + FROM vendor_inventory + WHERE product_id = pu.product_id + ) + ), + 0 +);