SQL Crowdfunding education

School Facts

School Facts model for crowdfunding education.

source-preserved

Blocks

school_facts.sql · 44 lines
inferred
-- models/school_facts.sql
{{ config(materialized='view') }}

SELECT
  DISTINCT s.schoolid AS schoolid
  , COUNT(DISTINCT CASE WHEN school_teacher.excluded IS FALSE THEN school_teacher.teacherid ELSE NULL END) AS teachers_registered
  , COUNT(DISTINCT p.proposalid) AS lifetime_projects
  , COUNT(DISTINCT CASE WHEN p.fullyfunded THEN p.proposalid ELSE NULL END) AS lifetime_projects_fully_funded
  , COUNT(DISTINCT CASE WHEN posted_date.posted IS NOT NULL THEN p.proposalid ELSE NULL END) AS lifetime_projects_posted

-- Why are we not starting from school? Because it will be joined to school in school view, which includes all schools
-- Why are we starting from orgteacher? Because we want all registered teachers, regardless of whether or not they posted
-- Must join school with project directly (not throught teacher), because projects stay attached to schools even if teachers move to another school
-- For currently registered teachers, must join orgteacher with school directly, not through schoolid.
-- For teachers whose projects are tied to schools, join through project onto school
  -- LEFT JOIN orgteacher project_teacher ON project_teacher.teacherid = p.createduserid
-- Too slow. Do not join LEFT JOIN proposalworkflowstatus pwfs ON p.proposalid = pwfs.proposalid

FROM school s
LEFT JOIN proposal_data p ON s.schoolid = p.schoolid
LEFT JOIN (SELECT pwfs.proposalid, MAX(datecreated) posted
          FROM proposalworkflowstatus pwfs
          WHERE workflowstatusid = 6
          GROUP BY proposalid) posted_date ON posted_date.proposalid = p.proposalid
LEFT JOIN orgteacher school_teacher ON school_teacher.schoolid = s.schoolid
GROUP BY s.schoolid

# models/schema.yml
version: 2

models:
  - name: school_facts
    columns:
      - name: schoolid
        tests:
          - unique
          - not_null
      - name: teachers_registered
      - name: lifetime_projects
      - name: lifetime_projects_posted
      - name: lifetime_projects_fully_funded
      - name: has_lifetime_project_created
      - name: has_lifetime_project_posted
      - name: has_lifetime_project_fully_funded

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.
school_facts.sql · 23 lines
source-preserved validation: parses
SELECT
  DISTINCT s.schoolid AS schoolid
  , COUNT(DISTINCT CASE WHEN school_teacher.excluded IS FALSE THEN school_teacher.teacherid ELSE NULL END) AS teachers_registered
  , COUNT(DISTINCT p.proposalid) AS lifetime_projects
  , COUNT(DISTINCT CASE WHEN p.fullyfunded THEN p.proposalid ELSE NULL END) AS lifetime_projects_fully_funded
  , COUNT(DISTINCT CASE WHEN posted_date.posted IS NOT NULL THEN p.proposalid ELSE NULL END) AS lifetime_projects_posted

-- Why are we not starting from school? Because it will be joined to school in school view, which includes all schools
-- Why are we starting from orgteacher? Because we want all registered teachers, regardless of whether or not they posted
-- Must join school with project directly (not throught teacher), because projects stay attached to schools even if teachers move to another school
-- For currently registered teachers, must join orgteacher with school directly, not through schoolid.
-- For teachers whose projects are tied to schools, join through project onto school
  -- LEFT JOIN orgteacher project_teacher ON project_teacher.teacherid = p.createduserid
-- Too slow. Do not join LEFT JOIN proposalworkflowstatus pwfs ON p.proposalid = pwfs.proposalid

FROM school s
LEFT JOIN proposal_data p ON s.schoolid = p.schoolid
LEFT JOIN (SELECT pwfs.proposalid, MAX(datecreated) posted
          FROM proposalworkflowstatus pwfs
          WHERE workflowstatusid = 6
          GROUP BY proposalid) posted_date ON posted_date.proposalid = p.proposalid
LEFT JOIN orgteacher school_teacher ON school_teacher.schoolid = s.schoolid
GROUP BY s.schoolid
school_facts.view.lkml · 71 lines
inferred
view: school_facts {
  derived_table: {
    sql: SELECT
  DISTINCT s.schoolid AS schoolid
  , COUNT(DISTINCT CASE WHEN school_teacher.excluded IS FALSE THEN school_teacher.teacherid ELSE NULL END) AS teachers_registered
  , COUNT(DISTINCT p.proposalid) AS lifetime_projects
  , COUNT(DISTINCT CASE WHEN p.fullyfunded THEN p.proposalid ELSE NULL END) AS lifetime_projects_fully_funded
  , COUNT(DISTINCT CASE WHEN posted_date.posted IS NOT NULL THEN p.proposalid ELSE NULL END) AS lifetime_projects_posted

-- Why are we not starting from school? Because it will be joined to school in school view, which includes all schools
-- Why are we starting from orgteacher? Because we want all registered teachers, regardless of whether or not they posted
-- Must join school with project directly (not throught teacher), because projects stay attached to schools even if teachers move to another school
-- For currently registered teachers, must join orgteacher with school directly, not through schoolid.
-- For teachers whose projects are tied to schools, join through project onto school
  -- LEFT JOIN orgteacher project_teacher ON project_teacher.teacherid = p.createduserid
-- Too slow. Do not join LEFT JOIN proposalworkflowstatus pwfs ON p.proposalid = pwfs.proposalid

FROM school s
LEFT JOIN proposal_data p ON s.schoolid = p.schoolid
LEFT JOIN (SELECT pwfs.proposalid, MAX(datecreated) posted
          FROM proposalworkflowstatus pwfs
          WHERE workflowstatusid = 6
          GROUP BY proposalid) posted_date ON posted_date.proposalid = p.proposalid
LEFT JOIN orgteacher school_teacher ON school_teacher.schoolid = s.schoolid
GROUP BY s.schoolid ;;
  }

  dimension: schoolid {
    label: "School ID"
    type: int
    primary_key: yes
    hidden: yes
  }

  dimension: teachers_registered {
    type: int
  }

  dimension: lifetime_projects {
    label: "Lifetime Projects Created"
    type: int
  }

  dimension: lifetime_projects_posted {
    type: int
  }

  dimension: lifetime_projects_fully_funded {
    label: "Lifetime Projects Funded"
    type: int
  }

  dimension: has_lifetime_project_created {
    type: yesno
    hidden: yes
    sql: ${lifetime_projects} > 0 ;;
  }

  dimension: has_lifetime_project_posted {
    type: yesno
    hidden: yes
    sql: ${lifetime_projects_posted} > 0 ;;
  }

  dimension: has_lifetime_project_fully_funded {
    label: "Has Lifetime Project Funded (Yes / No)"
    type: yesno
    hidden: yes
    sql: ${lifetime_projects_fully_funded} > 0 ;;
  }
}
school_facts.view.lookml · 54 lines
source-preserved
- view: school_facts
  derived_table:
    sql: SELECT
  DISTINCT s.schoolid AS schoolid
  , COUNT(DISTINCT CASE WHEN school_teacher.excluded IS FALSE THEN school_teacher.teacherid ELSE NULL END) AS teachers_registered
  , COUNT(DISTINCT p.proposalid) AS lifetime_projects
  , COUNT(DISTINCT CASE WHEN p.fullyfunded THEN p.proposalid ELSE NULL END) AS lifetime_projects_fully_funded
  , COUNT(DISTINCT CASE WHEN posted_date.posted IS NOT NULL THEN p.proposalid ELSE NULL END) AS lifetime_projects_posted

-- Why are we not starting from school? Because it will be joined to school in school view, which includes all schools
-- Why are we starting from orgteacher? Because we want all registered teachers, regardless of whether or not they posted
-- Must join school with project directly (not throught teacher), because projects stay attached to schools even if teachers move to another school
-- For currently registered teachers, must join orgteacher with school directly, not through schoolid.
-- For teachers whose projects are tied to schools, join through project onto school
  -- LEFT JOIN orgteacher project_teacher ON project_teacher.teacherid = p.createduserid
-- Too slow. Do not join LEFT JOIN proposalworkflowstatus pwfs ON p.proposalid = pwfs.proposalid

FROM school s
LEFT JOIN proposal_data p ON s.schoolid = p.schoolid
LEFT JOIN (SELECT pwfs.proposalid, MAX(datecreated) posted
          FROM proposalworkflowstatus pwfs
          WHERE workflowstatusid = 6
          GROUP BY proposalid) posted_date ON posted_date.proposalid = p.proposalid
LEFT JOIN orgteacher school_teacher ON school_teacher.schoolid = s.schoolid
GROUP BY s.schoolid
  fields:
  - dimension: schoolid
    type: int
    primary_key: true
    hidden: true
    label: School ID
  - dimension: teachers_registered
    type: int
  - dimension: lifetime_projects
    type: int
    label: Lifetime Projects Created
  - dimension: lifetime_projects_posted
    type: int
  - dimension: lifetime_projects_fully_funded
    type: int
    label: Lifetime Projects Funded
  - dimension: has_lifetime_project_created
    type: yesno
    hidden: true
    sql: ${lifetime_projects} > 0
  - dimension: has_lifetime_project_posted
    type: yesno
    hidden: true
    sql: ${lifetime_projects_posted} > 0
  - dimension: has_lifetime_project_fully_funded
    type: yesno
    hidden: true
    label: Has Lifetime Project Funded (Yes / No)
    sql: ${lifetime_projects_fully_funded} > 0

Contents

  • school_facts.sql
  • school_facts.sql
  • school_facts.view.lkml
  • school_facts.view.lookml