diff --git a/AI_ASSIST.md b/AI_ASSIST.md index 07efd00..ac96e85 100644 --- a/AI_ASSIST.md +++ b/AI_ASSIST.md @@ -8,14 +8,22 @@ Document one session where you used an LLM to help with a query or a design deci TODO: What were you trying to solve? Paste the relevant SQL or schema fragment. +CREATE OR REPLACE VIEW vw_dim_zones AS +SELECT + location_id, + zone + borough +FROM nyc_taxi.raw_zones; ## The prompt TODO: What did you ask the AI? Include the context you provided. - +why this query was giving me a syntax error in PostgreSQL? ## The response TODO: What did it suggest? Did it work first try? +AI pointed out that i forgot a comma after zone . ## Reflection TODO: Did you understand *why* the suggestion worked, or did you accept it blindly? +I understood why the error happened and i added comma . \ No newline at end of file diff --git a/assets/borough_count.png b/assets/borough_count.png new file mode 100644 index 0000000..cc78be1 Binary files /dev/null and b/assets/borough_count.png differ diff --git a/data_dictionary.md b/data_dictionary.md index 5e44612..3f8fd32 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 represents one taxi trip. +- **Primary key:** There is no primary key . +- **Foreign keys:** pickup_location_id and dropoff_location_id and both link to vw_dim_zones.location_id +- **Measures:** fare_amount , trip_distance , tip_amount ,total_amount , passenger_count. ## vw_dim_zones -- **Grain:** TODO -- **Primary key:** TODO -- **Foreign keys:** TODO (or "none") -- **Measures:** TODO (or "none, descriptive attributes only") +- **Grain:** One row represents one taxi zone +- **Primary key:** location_id +- **Foreign keys:** None +- **Measures:** None. descriptive attributes only . diff --git a/schema_setup.sql b/schema_setup.sql index a7ae1ad..036eebf 100644 --- a/schema_setup.sql +++ b/schema_setup.sql @@ -5,7 +5,9 @@ -- TODO: complete the SELECT (location_id, zone, borough). CREATE OR REPLACE VIEW vw_dim_zones AS SELECT - -- TODO + location_id, + zone, + borough FROM nyc_taxi.raw_zones; -- Fact: one row per taxi trip. @@ -15,12 +17,25 @@ FROM nyc_taxi.raw_zones; -- TODO: complete the SELECT and the WHERE. CREATE OR REPLACE VIEW vw_fact_trips AS SELECT - -- TODO + vendor_id, + pickup_datetime::TIMESTAMP AS pickup_datetime, + dropoff_datetime, + pickup_location_id, + dropoff_location_id, + passenger_count, + trip_distance, + fare_amount, + tip_amount, + total_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 vw_fact_trips f +JOIN vw_dim_zones d + ON f.pickup_location_id = d.location_id; diff --git a/validation_queries.sql b/validation_queries.sql index 301b194..16398c0 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 + vendor_id, + pickup_datetime, + dropoff_datetime, + COUNT(*) AS duplicate_count +FROM nyc_taxi.raw_trips +GROUP BY + vendor_id, + pickup_datetime, + dropoff_datetime +HAVING COUNT(*) > 1; -- 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(*) FILTER (WHERE pickup_location_id IS NULL) AS null_pickup_location_id, + COUNT(*) FILTER (WHERE dropoff_location_id IS NULL) AS null_dropoff_location_id +FROM nyc_taxi.raw_trips; -- 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(fare_amount) AS minimum_fare, + MAX(fare_amount) AS maximum_fare, + COUNT(*) FILTER (WHERE fare_amount < 0) AS negative_fare_count +FROM nyc_taxi.raw_trips; -- 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 DISTINCT + 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; diff --git a/verification_results.sql b/verification_results.sql index 68a8d26..0cdbf0e 100644 --- a/verification_results.sql +++ b/verification_results.sql @@ -5,18 +5,89 @@ -- 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_trips +FROM vw_fact_trips; +SELECT + d.borough, + COUNT(*) AS trip_count +FROM vw_fact_trips f +JOIN vw_dim_zones d + ON f.pickup_location_id = d.location_id +GROUP BY d.borough +ORDER BY trip_count DESC; +SELECT + pickup_location_id, + dropoff_location_id, + COUNT(*) AS trip_count +FROM vw_fact_trips +GROUP BY + pickup_location_id, + dropoff_location_id +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 + d.zone, + SUM(f.fare_amount) AS total_revenue +FROM vw_fact_trips f +JOIN vw_dim_zones d + ON f.pickup_location_id = d.location_id +GROUP BY d.zone +ORDER BY total_revenue DESC +LIMIT 1; +SELECT + d.zone, + DATE(f.pickup_datetime) AS trip_date, + SUM(f.fare_amount) AS total_revenue +FROM vw_fact_trips f +JOIN vw_dim_zones d + ON f.pickup_location_id = d.location_id +GROUP BY + d.zone, + DATE(f.pickup_datetime) +ORDER BY total_revenue DESC +LIMIT 1; -- 3. Geospatial: total number of trips and average trip_distance for each borough. -- TODO +SELECT + d.borough, + COUNT(*) AS total_trips, + AVG(f.trip_distance) AS average_trip_distance +FROM vw_fact_trips f +JOIN vw_dim_zones d + ON f.pickup_location_id = d.location_id +GROUP BY d.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(pickup_datetime, 'Day') AS day_of_week, + SUM(tip_amount) AS total_tips +FROM vw_fact_trips +GROUP BY day_of_week +ORDER BY total_tips DESC +LIMIT 1; + +SELECT + EXTRACT(HOUR FROM pickup_datetime) AS hour_of_day, + AVG(tip_amount) AS average_tip +FROM vw_fact_trips +GROUP BY hour_of_day +ORDER BY average_tip DESC +LIMIT 1; + +SELECT * +FROM vw_fact_trips +LIMIT 1; +