From 1ff18ee4c4f365511329f39373e99e848b6e6941 Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 04:14:44 +0200 Subject: [PATCH 1/7] added validation sql --- validation_queries.sql | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/validation_queries.sql b/validation_queries.sql index 301b194..e8979f1 100644 --- a/validation_queries.sql +++ b/validation_queries.sql @@ -5,16 +5,40 @@ -- 1. Duplicate check: are there rows with the same vendor_id, pickup_datetime, dropoff_datetime? -- TODO: GROUP BY the three columns and keep only groups with HAVING COUNT(*) > 1. +SELECT + t.vendor_id, + t.pickup_datetime, + t.dropoff_datetime, + COUNT(*) AS duplicate_count +FROM nyc_taxi.raw_trips t +GROUP BY t.vendor_id, t.pickup_datetime, t.dropoff_datetime +HAVING COUNT(*) > 1 +ORDER BY duplicate_count DESC; -- 2. Null integrity: how many rows have a NULL pickup_location_id or dropoff_location_id? -- TODO: count the NULLs (COUNT(*) FILTER (WHERE ... IS NULL) is handy for several columns at once). - +SELECT + COUNT(*) AS total_rows, + COUNT(*) FILTER (WHERE t.pickup_location_id IS NULL) AS null_pickup, + COUNT(*) FILTER (WHERE t.dropoff_location_id IS NULL) AS null_dropoff +FROM nyc_taxi.raw_trips t; -- 3. Range validation: what are the min and max fare_amount? Are there negative values? -- TODO: SELECT MIN(fare_amount), MAX(fare_amount), and a count of rows where fare_amount < 0. +SELECT + MIN(t.fare_amount) AS min_fare, + MAX(t.fare_amount) AS max_fare, + COUNT(*) FILTER (WHERE t.fare_amount < 0) AS negative_fares +FROM nyc_taxi.raw_trips t; -- 4. Relationship check: which pickup_location_id values in nyc_taxi.raw_trips do NOT exist in nyc_taxi.raw_zones? -- TODO: LEFT JOIN nyc_taxi.raw_zones ... WHERE z.location_id IS NULL (or NOT EXISTS). -- Do NOT use NOT IN: a single NULL in the subquery hides every orphan. +SELECT + t.pickup_location_id +FROM nyc_taxi.raw_trips t +LEFT JOIN nyc_taxi.raw_zones z ON t.pickup_location_id = z.location_id +WHERE z.location_id IS NULL +ORDER BY t.pickup_location_id; \ No newline at end of file From c7a53591b1416653802e9d824598228295b8fd36 Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 05:22:53 +0200 Subject: [PATCH 2/7] added schema setup for views --- schema_setup.sql | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/schema_setup.sql b/schema_setup.sql index a7ae1ad..0f44a13 100644 --- a/schema_setup.sql +++ b/schema_setup.sql @@ -3,24 +3,35 @@ -- Dimension: one row per location_id. Treat location_id as the primary key. -- TODO: complete the SELECT (location_id, zone, borough). -CREATE OR REPLACE VIEW vw_dim_zones AS +CREATE OR REPLACE VIEW dev_bader.vw_dim_zones AS SELECT - -- TODO -FROM nyc_taxi.raw_zones; + z.location_id, + z.zone, + z.borough +FROM nyc_taxi.raw_zones z; -- Fact: one row per taxi trip. -- - Exclude rows where fare_amount is less than 0. -- - Cast pickup_datetime to TIMESTAMP. -- - Keep the location IDs so the view can join to vw_dim_zones. -- TODO: complete the SELECT and the WHERE. -CREATE OR REPLACE VIEW vw_fact_trips AS +CREATE OR REPLACE VIEW dev_bader.vw_fact_trips AS SELECT - -- TODO + vendor_id, + pickup_datetime::timestamp AS pickup_datetime, + dropoff_datetime, + passenger_count, + pickup_location_id, + dropoff_location_id, + trip_distance, + fare_amount, + tip_amount, + payment_type FROM nyc_taxi.raw_trips --- TODO: WHERE fare_amount >= 0 -; +WHERE fare_amount >= 0; -- Join-readiness test (run after creating the views; it must run without error -- and return a count close to the vw_fact_trips row count): -- SELECT COUNT(*) FROM vw_fact_trips f -- JOIN vw_dim_zones d ON f.pickup_location_id = d.location_id; +SELECT COUNT(*) FROM dev_bader.vw_fact_trips f JOIN dev_bader.vw_dim_zones d ON f.pickup_location_id = d.location_id; \ No newline at end of file From dbc9574ac6f98cd17a048533561f83dd3df31810 Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 05:25:07 +0200 Subject: [PATCH 3/7] added data_dictionary --- data_dictionary.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/data_dictionary.md b/data_dictionary.md index 5e44612..c243498 100644 --- a/data_dictionary.md +++ b/data_dictionary.md @@ -4,14 +4,14 @@ Document both views. State the grain in one sentence, identify the keys, and lis ## vw_fact_trips -- **Grain:** TODO (one sentence, e.g. "One row per ...") -- **Primary key:** TODO -- **Foreign keys:** TODO -- **Measures:** TODO (columns you would SUM or AVG) +- **Grain:** (one row per taxi trip) +- **Primary key:** (none) +- **Foreign keys:** (pickup_location_id, dropoff_location_id) +- **Measures:** (fare_amount, trip_distance, tip_amount) ## vw_dim_zones -- **Grain:** TODO -- **Primary key:** TODO -- **Foreign keys:** TODO (or "none") -- **Measures:** TODO (or "none, descriptive attributes only") +- **Grain:** (one zone per row) +- **Primary key:** (location_id) +- **Foreign keys:** (none) +- **Measures:** (none, "descriptive attributes only") From c157ee49a53a3f8182ed873fc8255fe623deb308 Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 05:26:41 +0200 Subject: [PATCH 4/7] added passenger count to measures --- data_dictionary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_dictionary.md b/data_dictionary.md index c243498..de8f227 100644 --- a/data_dictionary.md +++ b/data_dictionary.md @@ -7,7 +7,7 @@ Document both views. State the grain in one sentence, identify the keys, and lis - **Grain:** (one row per taxi trip) - **Primary key:** (none) - **Foreign keys:** (pickup_location_id, dropoff_location_id) -- **Measures:** (fare_amount, trip_distance, tip_amount) +- **Measures:** (fare_amount, trip_distance, tip_amount, passenger_count) ## vw_dim_zones From b8261dacab2adb075923f889f3cfa8ae0713ab1f Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 05:36:35 +0200 Subject: [PATCH 5/7] clarified FK in fact trips view --- data_dictionary.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_dictionary.md b/data_dictionary.md index de8f227..e0b2b82 100644 --- a/data_dictionary.md +++ b/data_dictionary.md @@ -6,7 +6,7 @@ Document both views. State the grain in one sentence, identify the keys, and lis - **Grain:** (one row per taxi trip) - **Primary key:** (none) -- **Foreign keys:** (pickup_location_id, dropoff_location_id) +- **Foreign keys:** (pickup_location_id, dropoff_location_id) both linking to vw_dim_zones.location_id - **Measures:** (fare_amount, trip_distance, tip_amount, passenger_count) ## vw_dim_zones From bec51d91e165c2a3e75b5ca67c7b7891b6bb3509 Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 06:35:53 +0200 Subject: [PATCH 6/7] added verification results and png --- assets/borough_count.png | Bin 0 -> 25043 bytes verification_results.sql | 64 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 assets/borough_count.png diff --git a/assets/borough_count.png b/assets/borough_count.png new file mode 100644 index 0000000000000000000000000000000000000000..62575c27801734e01dffc94e8a0abe0f57a89968 GIT binary patch literal 25043 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 literal 0 HcmV?d00001 diff --git a/verification_results.sql b/verification_results.sql index 68a8d26..bce7217 100644 --- a/verification_results.sql +++ b/verification_results.sql @@ -4,19 +4,75 @@ -- 1. Volume: how many total rows in vw_fact_trips? How many rows per borough? -- What is the most common pickup/dropoff location combination? --- TODO +SELECT COUNT(*) AS total_rows +FROM dev_bader.vw_fact_trips t; + + +SELECT z.borough, COUNT(*) AS borough_count +FROM dev_bader.vw_fact_trips t +JOIN dev_bader.vw_dim_zones z ON t.pickup_location_id = z.location_id +GROUP BY z.borough +ORDER BY borough_count DESC; + +SELECT + z1.zone AS pickup_zone, + z2.zone AS dropoff_zone, + COUNT(*) AS trip_count +FROM dev_bader.vw_fact_trips t +JOIN dev_bader.vw_dim_zones z1 ON t.pickup_location_id = z1.location_id +JOIN dev_bader.vw_dim_zones z2 ON t.dropoff_location_id = z2.location_id +GROUP BY z1.zone, z2.zone +ORDER BY trip_count DESC +LIMIT 1; -- (Take a screenshot of the per-borough counts and save it as assets/borough_count.png.) -- 2. Revenue: which pickup zone (name, not ID) generated the highest total fare_amount? -- Which pickup zone collected the highest total fare_amount on any single day? --- TODO +SELECT + z.zone AS pickup_zone, + SUM(f.fare_amount) AS total_fare +FROM dev_bader.vw_fact_trips t +JOIN dev_bader.vw_dim_zones z ON t.pickup_location_id = z.location_id +GROUP BY z.zone +ORDER BY total_fare DESC +LIMIT 1; +SELECT + z.zone AS pickup_zone, + t.pickup_datetime::date AS trip_date, + SUM(t.fare_amount) AS total_fare +FROM dev_bader.vw_fact_trips t +JOIN dev_bader.vw_dim_zones z ON t.pickup_location_id = z.location_id +GROUP BY z.zone, t.pickup_datetime::date +ORDER BY total_fare DESC +LIMIT 1; -- 3. Geospatial: total number of trips and average trip_distance for each borough. --- TODO +SELECT + z.borough, + COUNT(*) AS total_trips, + AVG(t.trip_distance) AS avg_trip_distance +FROM dev_bader.vw_fact_trips t +JOIN dev_bader.vw_dim_zones z ON t.pickup_location_id = z.location_id +GROUP BY z.borough +ORDER BY total_trips DESC; -- 4. Time patterns: which day of the week had the highest total tip_amount? -- What hour of the day has the highest average tip? --- TODO +SELECT + TO_CHAR(t.pickup_datetime, 'Day') AS day_of_week, + SUM(t.tip_amount) AS total_tip +FROM dev_bader.vw_fact_trips t +GROUP BY day_of_week +ORDER BY total_tip DESC +LIMIT 1; + +SELECT + TO_CHAR(t.pickup_datetime, 'HH12 AM') AS pickup_hour, + AVG(t.tip_amount) AS avg_tip +FROM dev_bader.vw_fact_trips t +GROUP BY pickup_hour +ORDER BY avg_tip DESC +LIMIT 1; \ No newline at end of file From ee73676547e311024ead095e16ec6fabbf78c964 Mon Sep 17 00:00:00 2001 From: Mohamad Bader almsaddi alzin Date: Wed, 1 Jul 2026 06:47:41 +0200 Subject: [PATCH 7/7] added AI assist --- AI_ASSIST.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/AI_ASSIST.md b/AI_ASSIST.md index 07efd00..1e6fc64 100644 --- a/AI_ASSIST.md +++ b/AI_ASSIST.md @@ -5,17 +5,30 @@ Document one session where you used an LLM to help with a query or a design deci > ⚠️ Never paste real customer data or PII into an LLM. The NYC taxi dataset used here is public, so sample rows are safe to share. ## The problem +didnt know how to get the day of the week or the hour for verification +## The prompt -TODO: What were you trying to solve? Paste the relevant SQL or schema fragment. +how do i get day of the week from timestamp date in postgresql +## The response -## The prompt +In PostgreSQL, you can easily get the day of the week from a timestamp using either EXTRACT() / DATE_PART() or TO_CHAR().The best method depends on whether you want the result as a number (e.g., 0-6 or 1-7) or as a text name (e.g., "Monday").Here is how to do both.1. Get the Day of the Week as a NumberYou can use EXTRACT(DOW FROM timestamp) or EXTRACT(ISODOW FROM timestamp). Pay close attention to how they count the days:Standard Day of Week (DOW)Range: 0 (Sunday) to 6 (Saturday).SQLSELECT EXTRACT(DOW FROM TIMESTAMP '2026-07-01'); +-- Returns 3 (Since July 1, 2026 is a Wednesday) +ISO 8601 Day of Week (ISODOW)Range: 1 (Monday) to 7 (Sunday). This is highly recommended if your weeks strictly start on Monday.SQLSELECT EXTRACT(ISODOW FROM TIMESTAMP '2026-07-01'); +-- Returns 3 (Wednesday) +💡 Note: You can also use DATE_PART('dow', timestamp) which achieves the exact same result as EXTRACT.2. Get the Day of the Week as text (Name)If you need the actual name of the day, use the TO_CHAR() function with the appropriate template pattern.Full Day Name (Day)SQLSELECT TO_CHAR(TIMESTAMP '2026-07-01', 'Day'); +-- Returns 'Wednesday ' (padded with spaces) + +SELECT TO_CHAR(TIMESTAMP '2026-07-01', 'FMDay'); +-- Returns 'Wednesday' (FM removes trailing whitespace padding) +Abbreviated Day Name (Dy)SQLSELECT TO_CHAR(TIMESTAMP '2026-07-01', 'FMDy'); +-- Returns 'Wed' +Quick Reference TableFunction / PatternResult for a WednesdayFormat TypeRange/NotesEXTRACT(DOW FROM ...)3Numeric0 (Sun) - 6 (Sat)EXTRACT(ISODOW FROM ...)3Numeric1 (Mon) - 7 (Sun)TO_CHAR(..., 'FMDay')"Wednesday"TextFull name, capitalizedTO_CHAR(..., 'fmday')"wednesday"TextFull name, lowercaseTO_CHAR(..., 'FMDy')"Wed"Text3-letter abbreviation -TODO: What did you ask the AI? Include the context you provided. -## The response -TODO: What did it suggest? Did it work first try? +it didnt work first try since i used extract first then to_char (t.pickup_datetime, 'D') which gave me only the index of the day so i switched to (t.pickup_datetime, 'Day') which showed the day name +also did the same with the hour ## Reflection -TODO: Did you understand *why* the suggestion worked, or did you accept it blindly? +i did understand why and learned few more things to keep in mind considering timestamps and datetime and the use of Day/'HH12 AM' \ No newline at end of file