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
1 change: 1 addition & 0 deletions .user.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
id: 65fed7dc-cfb1-40ec-af82-fb56180cafce
29 changes: 17 additions & 12 deletions AI_ASSIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,29 @@ Document one place you used an LLM during this assignment.

## The problem

<!-- TODO: describe the specific problem you asked an LLM about.
Example: "My safe_divide macro compiled but returned NULL for all rows even
when tip_amount and fare_amount were both non-zero." -->

TODO

While building the stg_trips staging model, i had an SQL syntax issue because i placed the "WHERE" clause before the "FROM" clause.
## The prompt

<!-- TODO: paste the exact prompt you sent to the LLM. -->

TODO

Im building a dbt staging model and my SQL query is failing. what is the problem here?
my query was :
SELECT
pickup_datetime,
pickup_location_id,
fare_amount,
tip_amount,
trip_distance,

{{ safe_divide('tip_amount', 'fare_amount') }} as tip_pct

where pickup_location_id is not null
FROM {{ source('nyc_taxi', 'raw_trips') }}
and fare_amount >= 0
## The response

<!-- TODO: summarise or paste what the LLM returned. -->

TODO
the llm explained that SQL clauses follow a fixed order. The FROM clause must come before the WHERE clause because SQL needs to know the source table before applying filters.

## Reflection

Expand All @@ -29,8 +35,7 @@ TODO
'ratio' to 'tip_pct' to match the assignment schema." -->

TODO

---
i changed the query order so that "FROM" comes immediately after the SELECT columns, followed by the WHERE filters.

> Remember: never paste real connection strings, passwords, or PII into an LLM.
> The NYC TLC dataset is public so sample rows are safe here, but practise the habit.
Binary file added docs/Lineage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 5 additions & 4 deletions macros/safe_divide.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
-- Use for tip_pct = tip_amount / fare_amount and similar ratio columns.

{% macro safe_divide(numerator, denominator) %}
-- TODO: implement the macro body.
-- Use NULLIF(denominator, 0) to avoid division-by-zero errors.
-- Return only the SQL expression (no SELECT, no semicolon).
NULL

{{ numerator }} / nullif({{ denominator }}, 0)

{% endmacro %}


32 changes: 23 additions & 9 deletions models/marts/_fct_daily_borough_stats.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,36 @@ version: 2
models:
- name: fct_daily_borough_stats
description: >
TODO: state the grain (one row per ___), the source lineage
(built from ___ and ___), and at least one known caveat
(e.g. rows dropped in staging, any WARN-severity tests).
Daily borough-level taxi statistics with a grain of one row per
(pickup_borough, pickup_date).
Built from stg_trips and stg_zones.
Trips with missing or invalid pickup locations are removed during staging
or excluded by the INNER JOIN.
The avg_tip_pct warning test may return some rows where
tips are higher than the fare amount.

tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- pickup_borough
- pickup_date
# TODO: Task 5 -- add the compound uniqueness test on the mart's primary
# key (pickup_borough, pickup_date). You need the dbt_utils package for
# this: declare it in packages.yml and run `dbt deps` first.
columns:
- name: pickup_borough
description: "TODO: explain what this column contains and where it comes from"
description: "The TLC borough where trips were picked up, sourced from stg_zones.borough"
tests:
- not_null
- name: pickup_date
description: "TODO: explain units and how it is derived"
description: "The calendar date of the trip pickup, derived from pickup_datetime."
tests:
- not_null
- name: trip_count
description: "TODO: explain what is counted (unit: number of trips)"
description: "The number of taxi trips picked up in the borough on that dat."
- name: total_fare
description: "TODO: explain units (USD) and what fare_amount represents"
description: "The total fare amount collected in US dollars, calculated as the sum of fare_amount"
- name: avg_tip_pct
description: "TODO: explain the ratio (tip_amount / fare_amount)"
description: "The average tipping ratio calculated as tip_amount divided by fare_amount."
- name: avg_trip_distance
description: "TODO: explain units (miles, from TLC source data)"
description: "The average trip distance in miles based on the TLC trip_distance field"
27 changes: 21 additions & 6 deletions models/marts/fct_daily_borough_stats.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
-- Grain: one row per (pickup_borough, pickup_date).
-- Used to answer: trip volume, revenue, tipping behaviour, and distance profile
-- per borough per day for January 2024.
{{ config(materialized='table') }}

WITH trips AS (
SELECT *
Expand All @@ -26,13 +27,27 @@ SELECT
-- total_fare NUMERIC - sum(fare_amount)
-- avg_tip_pct NUMERIC - avg(tip_pct)
-- avg_trip_distance NUMERIC - avg(trip_distance)
NULL AS pickup_borough,
NULL AS pickup_date,
NULL AS trip_count,
NULL AS total_fare,
NULL AS avg_tip_pct,
NULL AS avg_trip_distance
z.borough AS pickup_borough,

t.pickup_datetime::date AS pickup_date,

count(*) AS trip_count,

sum(t.fare_amount) AS total_fare,

avg(t.tip_pct) AS avg_tip_pct,

avg(t.trip_distance) AS avg_trip_distance


FROM trips t
-- TODO: add JOIN to zones here
INNER JOIN zones z

ON t.pickup_location_id = z.location_id
-- TODO: add GROUP BY here
GROUP BY

z.borough,

t.pickup_datetime::date
4 changes: 2 additions & 2 deletions models/staging/_sources.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ sources:
schema: nyc_taxi # TODO: confirm this matches the schema where raw_trips and raw_zones live
tables:
- name: raw_trips
description: "TODO: one sentence on what this table contains and its grain"
description: "Raw NYC green Taxi trip records, with one row representing one individual taxi trip."
- name: raw_zones
description: "TODO: one sentence on what this table contains"
description: "Raw TLC taxi zone lookup table containing location IDs and borough/zone information."
18 changes: 11 additions & 7 deletions models/staging/_stg_trips.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@ version: 2

models:
- name: stg_trips
description: "TODO: state the grain (one row per ___) and what source this reads from"
description: "One row per taxi trip from the raw_trips source after basic cleaning and filtering."
columns:
- name: pickup_datetime
description: "TODO"
description: "Timestamp when the trip started"
tests:
- not_null
# TODO: Task 5 -- add not_null tests on every column used as a join or
# group-by key. See the chapter's dbt Tests section for the syntax.
- name: pickup_location_id
description: "TODO"
description: "TLC location ID where the trip was picked up."
tests:
- not_null
- name: fare_amount
description: "TODO"
description: "Fare charged for the trip in US dollars"
- name: tip_amount
description: "TODO"
description: "Tip paid by the passenger in US dollars"
- name: trip_distance
description: "TODO"
description: "Distance travelled during the trip in miles"
- name: tip_pct
description: "TODO"
description: "Tip as a percentage of the fare amount"
10 changes: 7 additions & 3 deletions models/staging/_stg_zones.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ version: 2

models:
- name: stg_zones
description: "TODO: state the grain and what source this reads from"
description: "One row per TLC taxi zone from the raw_zones source"
columns:
- name: location_id
description: "TODO"
description: "Unique identifier for each TLC taxi zone."
tests:
- not_null
- unique

# TODO: Task 5 -- this column is the join key. Which two generic tests
# guarantee a clean one-to-many join from stg_trips?
- name: borough
description: "TODO"
description: "Borough that the taxi zone belongs to."
17 changes: 11 additions & 6 deletions models/staging/stg_trips.sql
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
-- Staging model: one row per NYC green taxi trip (January 2024).
-- Renames source columns, adds derived columns, and filters bad rows.
-- Downstream: fct_daily_borough_stats joins this to stg_zones.
{{ config(materialized='view') }}

SELECT
-- TODO: select the columns you need for the mart:
-- pickup_datetime, pickup_location_id, fare_amount, tip_amount, trip_distance
--
-- TODO: add tip_pct using {{ safe_divide('tip_amount', 'fare_amount') }}
--
-- TODO: filter out rows where pickup_location_id IS NULL or fare_amount < 0
pickup_datetime,
pickup_location_id,
fare_amount,
tip_amount,
trip_distance,

{{ safe_divide('tip_amount', 'fare_amount') }} as tip_pct

FROM {{ source('nyc_taxi', 'raw_trips') }}

where pickup_location_id is not null
and fare_amount >= 0
5 changes: 3 additions & 2 deletions models/staging/stg_zones.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
-- Staging model: one row per TLC zone (265 zones).
-- Exposes location_id and borough for use as a lookup in the mart.
{{ config(materialized='view') }}

SELECT
-- TODO: select location_id and borough from {{ source('nyc_taxi', 'raw_zones') }}

location_id,
borough
FROM {{ source('nyc_taxi', 'raw_zones') }}
5 changes: 5 additions & 0 deletions package-lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
packages:
- name: dbt_utils
package: dbt-labs/dbt_utils
version: 1.3.0
sha1_hash: 226ae69cdfbc9367e2aa2c472b01f99dbce11de0
4 changes: 3 additions & 1 deletion packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
# `dbt deps` to install it. You need it for the compound uniqueness test
# on the mart. See https://hub.getdbt.com/dbt-labs/dbt_utils/latest/
# for the package block syntax.
packages: []
packages:
- package: dbt-labs/dbt_utils
version: 1.3.0
74 changes: 60 additions & 14 deletions reports/answers.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Business Question Answers

Queries run against `dev_<your_name>.fct_daily_borough_stats`.
Queries run against `dev_baraah.fct_daily_borough_stats`.

## Q1: Highest total `total_fare` across the whole loaded dataset

Expand All @@ -9,10 +9,20 @@ Queries run against `dev_<your_name>.fct_daily_borough_stats`.
```sql
-- TODO: query fct_daily_borough_stats grouped by pickup_borough, sum total_fare, order DESC
```

**Result:** TODO

**Interpretation:** TODO (one sentence)
SELECT
pickup_borough,
SUM(total_fare) AS total_revenue
FROM dev_baraah.fct_daily_borough_stats
GROUP BY pickup_borough
ORDER BY total_revenue DESC
LIMIT 1;
**Result:**
pickup_borough | total_revenue
----------------+---------------
Manhattan | 493955.62
(1 row)

**Interpretation:** The borough with the highest total fare revenue across the loaded dataset was Manhattan $493955.62.

---

Expand All @@ -23,10 +33,20 @@ Queries run against `dev_<your_name>.fct_daily_borough_stats`.
```sql
-- TODO: query fct_daily_borough_stats grouped by pickup_date, sum trip_count, order DESC LIMIT 1
```

**Result:** TODO

**Interpretation:** TODO (one sentence)
SELECT
pickup_date,
SUM(trip_count) AS total_trips
FROM dev_baraah.fct_daily_borough_stats
GROUP BY pickup_date
ORDER BY total_trips DESC
LIMIT 1;
**Result:**
pickup_date | total_trips
-------------+-------------
2024-01-17 | 2221
(1 row)

**Interpretation:** The busiest day in the dataset was 2024-01-17 with 2221 trips across all boroughs.

---

Expand All @@ -37,10 +57,25 @@ Queries run against `dev_<your_name>.fct_daily_borough_stats`.
```sql
-- TODO: query fct_daily_borough_stats order by avg_tip_pct DESC LIMIT 5
```

**Result:** TODO

**Interpretation:** TODO — note whether any avg_tip_pct > 1 rows appear and what causes them
SELECT
pickup_borough,
pickup_date,
avg_tip_pct
FROM dev_baraah.fct_daily_borough_stats
ORDER BY avg_tip_pct DESC
LIMIT 5;

**Result:**
pickup_borough | pickup_date | avg_tip_pct
----------------+-------------+--------------------
Unknown | 2024-01-30 | 2.500125
Unknown | 2024-01-07 | 1.3396296296296295
Unknown | 2024-01-11 | 1.1044956140350877
Unknown | 2024-01-16 | 1
Unknown | 2024-01-18 | 0.611111111111111
(5 rows)

**Interpretation:** The highest average tip percentage occurred in Unknown on 2024-01-30 .

---

Expand All @@ -51,7 +86,18 @@ Queries run against `dev_<your_name>.fct_daily_borough_stats`.
```sql
-- TODO: use percentile_cont(0.5) WITHIN GROUP (ORDER BY trip_count) filtered by borough
```
SELECT
pickup_borough,
percentile_cont(0.5) WITHIN GROUP (ORDER BY trip_count) AS median_trip_count
FROM dev_baraah.fct_daily_borough_stats
WHERE pickup_borough IN ('Manhattan', 'Brooklyn')
GROUP BY pickup_borough;

**Result:** TODO
pickup_borough | median_trip_count
----------------+-------------------
Brooklyn | 248
Manhattan | 1169.5
(2 rows)

**Interpretation:** TODO (one sentence on the ratio)
**Interpretation:** Manhattan had a higher median daily trip count than Brooklyn.
1 change: 1 addition & 0 deletions test-output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bash: test.sh: No such file or directory
11 changes: 9 additions & 2 deletions tests/assert_avg_tip_pct_within_bounds.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@
-- unique_combination primary-key tests, which you want to stay at ERROR.
--
-- The test passes (no WARN) when zero rows are returned; any returned rows are flagged.
{{ config(severity='warn') }}

-- TODO: write the SELECT here.
-- Query {{ ref('fct_daily_borough_stats') }} and return rows where avg_tip_pct > 1.
SELECT NULL AS pickup_borough, NULL AS pickup_date, NULL AS avg_tip_pct
WHERE FALSE -- TODO: replace with the real query
SELECT
pickup_borough,
pickup_date,
avg_tip_pct

FROM {{ ref('fct_daily_borough_stats') }}

WHERE avg_tip_pct > 1
Loading