SQL
Mobile ticketing
Sessions
Sessions model for mobile ticketing.
source-preserved
Blocks
sessions.sql · 39 lines
inferred
-- models/sessions.sql
{{ config(materialized='view') }}
SELECT
lag.e_tstamp AS session_start
, lag.idle_time AS idle_time
, lag.user_id AS user_id
, ROW_NUMBER () OVER (ORDER BY lag.e_tstamp) AS unique_session_id
, RANK() OVER(PARTITION BY lag.user_id ORDER BY lag.e_tstamp) AS session_sequence
, COALESCE(
LEAD(lag.e_tstamp) OVER (PARTITION BY lag.user_id ORDER BY lag.e_tstamp)
, '3000-01-01') AS next_session_start
FROM
( SELECT
timestamp 'epoch' + logs.ts * interval '1 second' AS e_tstamp
, logs.uid AS user_id
, DATEDIFF(
minute,
LAG(timestamp 'epoch' + logs.ts * interval '1 second') OVER ( PARTITION BY logs.uid ORDER BY logs.ts)
, timestamp 'epoch' + logs.ts * interval '1 second') AS idle_time
FROM ts_user_base AS logs
) AS lag
WHERE (lag.idle_time > 30 OR lag.idle_time IS NULL) -- session threshold
# models/schema.yml
version: 2
models:
- name: sessions
columns:
- name: unique_session_id
tests:
- unique
- not_null
- name: idle_time
- name: user_id
- name: session_sequence_by_user
description: "For a given user, what order did the sessions take place in? 1=First, 2=Second, etc"
- name: is_first_session
Assumptions
- materialized='view' is the default; no persist hint found.
- schema.yml columns come from view dimensions; a primary_key dimension gets unique + not_null tests.
sessions.sql · 20 lines
source-preserved
validation: parses
SELECT
lag.e_tstamp AS session_start
, lag.idle_time AS idle_time
, lag.user_id AS user_id
, ROW_NUMBER () OVER (ORDER BY lag.e_tstamp) AS unique_session_id
, RANK() OVER(PARTITION BY lag.user_id ORDER BY lag.e_tstamp) AS session_sequence
, COALESCE(
LEAD(lag.e_tstamp) OVER (PARTITION BY lag.user_id ORDER BY lag.e_tstamp)
, '3000-01-01') AS next_session_start
FROM
( SELECT
timestamp 'epoch' + logs.ts * interval '1 second' AS e_tstamp
, logs.uid AS user_id
, DATEDIFF(
minute,
LAG(timestamp 'epoch' + logs.ts * interval '1 second') OVER ( PARTITION BY logs.uid ORDER BY logs.ts)
, timestamp 'epoch' + logs.ts * interval '1 second') AS idle_time
FROM ts_user_base AS logs
) AS lag
WHERE (lag.idle_time > 30 OR lag.idle_time IS NULL) -- session threshold
sessions.view.lkml · 74 lines
inferred
view: sessions {
derived_table: {
sql: SELECT
lag.e_tstamp AS session_start
, lag.idle_time AS idle_time
, lag.user_id AS user_id
, ROW_NUMBER () OVER (ORDER BY lag.e_tstamp) AS unique_session_id
, RANK() OVER(PARTITION BY lag.user_id ORDER BY lag.e_tstamp) AS session_sequence
, COALESCE(
LEAD(lag.e_tstamp) OVER (PARTITION BY lag.user_id ORDER BY lag.e_tstamp)
, '3000-01-01') AS next_session_start
FROM
( SELECT
timestamp 'epoch' + logs.ts * interval '1 second' AS e_tstamp
, logs.uid AS user_id
, DATEDIFF(
minute,
LAG(timestamp 'epoch' + logs.ts * interval '1 second') OVER ( PARTITION BY logs.uid ORDER BY logs.ts)
, timestamp 'epoch' + logs.ts * interval '1 second') AS idle_time
FROM ts_user_base AS logs
) AS lag
WHERE (lag.idle_time > 30 OR lag.idle_time IS NULL) -- session threshold ;;
}
dimension: unique_session_id {
type: int
primary_key: yes
sql: ${TABLE}.unique_session_id ;;
}
dimension: idle_time {
type: number
sql: ${TABLE}.idle_time ;;
}
dimension: user_id {
hidden: yes
sql: ${TABLE}.user_id ;;
}
dimension: session_sequence_by_user {
description: "For a given user, what order did the sessions take place in? 1=First, 2=Second, etc"
type: number
sql: ${TABLE}.session_sequence ;;
}
dimension: is_first_session {
type: yesno
sql: ${session_sequence_by_user} = 1 ;;
}
dimension_group: start {
type: time
timeframes: [time, date, week, month, hour_of_day, day_of_week, hour, raw]
sql: ${TABLE}.session_start ;;
}
dimension_group: next_session_start {
type: time
timeframes: [time, date, week, month, raw]
sql: ${TABLE}.next_session_start ;;
}
measure: count {
type: count
drill_fields: [detail*]
}
measure: count_distinct_users {
type: count_distinct
drill_fields: [detail*]
sql: ${user_id} ;;
}
}
sessions.view.lookml · 70 lines
source-preserved
- view: sessions
derived_table:
sql: SELECT
lag.e_tstamp AS session_start
, lag.idle_time AS idle_time
, lag.user_id AS user_id
, ROW_NUMBER () OVER (ORDER BY lag.e_tstamp) AS unique_session_id
, RANK() OVER(PARTITION BY lag.user_id ORDER BY lag.e_tstamp) AS session_sequence
, COALESCE(
LEAD(lag.e_tstamp) OVER (PARTITION BY lag.user_id ORDER BY lag.e_tstamp)
, '3000-01-01') AS next_session_start
FROM
( SELECT
timestamp 'epoch' + logs.ts * interval '1 second' AS e_tstamp
, logs.uid AS user_id
, DATEDIFF(
minute,
LAG(timestamp 'epoch' + logs.ts * interval '1 second') OVER ( PARTITION BY logs.uid ORDER BY logs.ts)
, timestamp 'epoch' + logs.ts * interval '1 second') AS idle_time
FROM ts_user_base AS logs
) AS lag
WHERE (lag.idle_time > 30 OR lag.idle_time IS NULL) -- session threshold
fields:
- dimension: unique_session_id
type: int
primary_key: true
sql: ${TABLE}.unique_session_id
- dimension: idle_time
type: number
sql: ${TABLE}.idle_time
- dimension: user_id
hidden: true
sql: ${TABLE}.user_id
- dimension: session_sequence_by_user
type: number
description: For a given user, what order did the sessions take place in? 1=First, 2=Second, etc
sql: ${TABLE}.session_sequence
- dimension: is_first_session
type: yesno
sql: ${session_sequence_by_user} = 1
- dimension_group: start
type: time
timeframes:
- time
- date
- week
- month
- hour_of_day
- day_of_week
- hour
- raw
sql: ${TABLE}.session_start
- dimension_group: next_session_start
type: time
timeframes:
- time
- date
- week
- month
- raw
sql: ${TABLE}.next_session_start
- measure: count
type: count
drill_fields:
- detail*
- measure: count_distinct_users
type: count_distinct
drill_fields:
- detail*
sql: ${user_id}
Contents
- sessions.sql
- sessions.sql
- sessions.view.lkml
- sessions.view.lookml