Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions AI_ASSIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Binary file added assets/borough_count.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 8 additions & 8 deletions data_dictionary.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) both linking to vw_dim_zones.location_id
- **Measures:** (fare_amount, trip_distance, tip_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 zone per row)
- **Primary key:** (location_id)
- **Foreign keys:** (none)
- **Measures:** (none, "descriptive attributes only")
25 changes: 18 additions & 7 deletions schema_setup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;
26 changes: 25 additions & 1 deletion validation_queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;
64 changes: 60 additions & 4 deletions verification_results.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;