A practical guide to Looker development
In Looker, a View is like a blueprint for a table in your database.
sql_table_name
) anddimension
, measure
, etc.)Think of it as a wrapper around a database table or SQL result, where you define:
sql_table_name: schema.table_name
to establish this connectionModel → Explore → View
📌 TL;DR:
A View defines how Looker should understand and work with a single table (or derived result), including what to expose to business users.
Every LookML view file starts with a view:
declaration. It’s used to define fields like dimensions and measures based on an underlying table.
view: users {
sql_table_name: analytics.users ;;
dimension: user_id {
type: number
primary_key: yes
sql: ${TABLE}.user_id ;;
}
measure: total_users {
type: count
}
}
view:
— Name of the view (typically matches the table)sql_table_name:
— Specifies the source table or derived resultdimension:
is requiredlabel:
— UI-friendly name for the viewdescription:
— Tooltip info for views or fieldsgroup_label:
— Collapses related fields together in the UIA dimension in Looker represents a raw column or a derived field — used for grouping, filtering, or displaying raw values in reports.
user_id
, state
, product_category
, signup_date
type:
Valuesstring
— text fields like names, emails, categoriesnumber
— integers, floats, pricesyesno
— boolean flagsdate
, time
, datetime
— date/time fieldstier
— bucketing logic (e.g., price tiers)dimension: product_name {
type: string
sql: ${TABLE}.product_name ;;
}
Used to auto-generate multiple time resolutions (e.g., day, week, month).
dimension_group: signup_date {
type: time
timeframes: [raw, date, week, month, year]
sql: ${TABLE}.signup_ts ;;
}
;;
in sql:
blockssql:
A measure is an aggregated field — used to compute metrics like totals, averages, counts. Measures are typically the numbers business users care about.
total_sales
, avg_order_value
, count_users
type:
and often a sql:
clausetype:
Valuescount
— total number of rowscount_distinct
— unique count of a columnsum
— total of a numeric fieldaverage
— mean valuemin
, max
— smallest/largest valuenumber
— use when defining a custom SQL aggregation manuallymeasure: total_sales {
type: sum
sql: ${TABLE}.sales_amount ;;
}
Use type: number
when you’re writing full SQL logic yourself.
measure: new_vs_repeat_ratio {
type: number
sql: CASE WHEN ${is_new} THEN 1 ELSE 0 END * 1.0 / COUNT(*) ;;
}
${price}
in sum)Time-based fields in Looker are handled using dimension_group
, which auto-generates multiple granularities from a single timestamp.
Use this to expose fields like signup_date
, signup_week
, signup_year
— all from one column.
dimension_group: signup_date {
type: time
timeframes: [raw, date, week, month, quarter, year]
sql: ${TABLE}.signup_ts ;;
}
If your DB stores UTC but you want reports in a local timezone:
sql: CONVERT_TZ(${TABLE}.created_at, 'UTC', 'America/Los_Angeles') ;;
TIMESTAMP
functionsOnce a dimension_group
is defined, Looker automatically enables time filters like:
is in the past 7 days
is on or after last month
is between date A and date B
These filters are accessible from the Explore UI without extra config.
dimension_group
datatype: date_time
in SQL Runner to preview data formatsA Persistent Derived Table (PDT) is a temporary table that Looker creates in your warehouse based on a SQL query. It’s used when your logic is too complex to model directly off a raw table.
PDTs are defined inside a view using the derived_table
block:
view: product_rollup {
derived_table: {
sql: SELECT product_id, SUM(sales) AS total_sales FROM orders GROUP BY 1 ;;
}
persist_for: "24 hours"
}
Alternatively, you can use:
persist_for: "24 hours"
→ rebuild every 24 hoursdatagroup_trigger: hourly_refresh
→ tie to a datagroup from your modelderived_table
persist_for:
or datagroup_trigger:
for refresh policyHere are two example view files to demonstrate how dimensions, measures, and time handling come together in real projects.
view: orders {
sql_table_name: analytics.orders ;;
dimension: order_id {
type: number
primary_key: yes
sql: ${TABLE}.order_id ;;
}
dimension: customer_id {
type: number
sql: ${TABLE}.customer_id ;;
}
dimension_group: order_date {
type: time
timeframes: [date, week, month, year]
sql: ${TABLE}.order_ts ;;
}
measure: total_revenue {
type: sum
sql: ${TABLE}.order_amount ;;
}
}
view: users {
sql_table_name: analytics.users ;;
dimension: user_id {
type: number
primary_key: yes
sql: ${TABLE}.user_id ;;
}
dimension: email {
type: string
sql: ${TABLE}.email_address ;;
}
dimension_group: signup_date {
type: time
timeframes: [date, month, year]
sql: ${TABLE}.signup_ts ;;
}
measure: total_users {
type: count
}
}