Malloy Documentation
search

Sometimes it is useful to add SQL statements into a Malloy file. You can do so by using the sql: keyword. An SQL statement has two properties.

  • select: -- Has a string value which is bracketed with triple quotes """

  • connection: -- A string value which is the name of the connection (if not specified the default connection will be used)

document
run: duckdb.sql("""
    SELECT
      first_name,
      last_name,
      gender
    FROM '../data/users.parquet'
    LIMIT 10
  """)
QUERY RESULTS
first_​namelast_​namegender
FRANKHUGHESMale
HAROLDGATEWOODMale
SCOTTJOACHIMMale
JAMESALLENMale
JEREMYCASASMale
[
  {
    "first_name": "FRANK",
    "last_name": "HUGHES",
    "gender": "Male"
  },
  {
    "first_name": "HAROLD",
    "last_name": "GATEWOOD",
    "gender": "Male"
  },
  {
    "first_name": "SCOTT",
    "last_name": "JOACHIM",
    "gender": "Male"
  },
  {
    "first_name": "JAMES",
    "last_name": "ALLEN",
    "gender": "Male"
  },
  {
    "first_name": "JEREMY",
    "last_name": "CASAS",
    "gender": "Male"
  }
]

    SELECT
      first_name,
      last_name,
      gender
    FROM '../data/users.parquet'
    LIMIT 10
  

Sources from SQL Blocks

Sources can be created from a SQL block, e.g.

document
source: limited_users is duckdb.sql("""
    SELECT
      first_name,
      last_name,
      gender
    FROM '../data/users.parquet'
    LIMIT 10
  """) extend {
  measure: user_count is count()
}

run: limited_users -> {
  aggregate: user_count
}
QUERY RESULTS
user_​count
10
[
  {
    "user_count": 10
  }
]
SELECT 
   COUNT( 1) as "user_count"
FROM (
    SELECT
      first_name,
      last_name,
      gender
    FROM '../data/users.parquet'
    LIMIT 10
  ) as limited_users

Embedding Malloy queries in an SQL block ( Turducken )

Malloy queries can be embedded in SQL blocks as well. When %{ and } appear inside the """ string of a select: statement, the Malloy query between the brackets is compiled and replaced with the SELECT statement generated from the query.

document
source: users is duckdb.table('../data/users.parquet')

run: duckdb.sql("""
-- BEGIN MALLOY QUERY
%{
  users -> {
    limit: 10 group_by: first_name, last_name, gender
    aggregate: n_with_this_name is count()
  }
}
-- END MALLOY QUERY
""")
QUERY RESULTS
first_​namelast_​namegendern_​with_​this_​name
MARYSMITHFemale45
JAMESSMITHMale40
MICHAELSMITHMale32
ROBERTSMITHMale32
JAMESWILLIAMSMale32
[
  {
    "first_name": "MARY",
    "last_name": "SMITH",
    "gender": "Female",
    "n_with_this_name": 45
  },
  {
    "first_name": "JAMES",
    "last_name": "SMITH",
    "gender": "Male",
    "n_with_this_name": 40
  },
  {
    "first_name": "MICHAEL",
    "last_name": "SMITH",
    "gender": "Male",
    "n_with_this_name": 32
  },
  {
    "first_name": "ROBERT",
    "last_name": "SMITH",
    "gender": "Male",
    "n_with_this_name": 32
  },
  {
    "first_name": "JAMES",
    "last_name": "WILLIAMS",
    "gender": "Male",
    "n_with_this_name": 32
  }
]

-- BEGIN MALLOY QUERY
(SELECT 
   users."first_name" as "first_name",
   users."last_name" as "last_name",
   users."gender" as "gender",
   COUNT( 1) as "n_with_this_name"
FROM '../data/users.parquet' as users
GROUP BY 1,2,3
ORDER BY 4 desc NULLS LAST
LIMIT 10
)
-- END MALLOY QUERY

> We have referred to this feature the "Turducken" because you then take the SQL block and wrap it in an SQL source. It isn't the perfect name for infinte nesting, but it is amusing...