Query of Queries

Execute SQL queries against in-memory query result sets for powerful data manipulation

Query of Queries (QoQ) allows you to execute SQL queries against in-memory query result sets, eliminating the need for additional database round trips. BoxLang's QoQ implementation is built from scratch using a high-performance ANTLR grammar based on SQLite, delivering exceptional speed and a comprehensive feature set that surpasses traditional CFML implementations.

📋 Overview

BoxLang's Query of Queries provides:

  • Fast Performance, optimized for large datasets

  • ANSI JOIN syntax - INNER, LEFT, RIGHT, FULL, and CROSS joins

  • Unlimited table joins - No restrictions on number of tables

  • Subqueries - Nested SELECT statements in FROM, JOIN, and IN clauses

  • CASE statements - Standard and input-based CASE expressions

  • Custom functions - Register your own scalar and aggregate functions

  • Complete SQL syntax - TOP/LIMIT, UNION, DISTINCT, GROUP BY, ORDER BY

  • Bitwise operators - XOR, AND, OR, NOT operations

  • Type safety - Preserves column types and NULL handling

🚀 Basic Usage

To execute a query of queries, set the dbtype option to "query":

// Create source data
employees = queryNew(
    "name,department,salary,hireDate",
    "varchar,varchar,integer,date",
    [
        [ "John Doe", "Engineering", 75000, createDate( 2020, 1, 15 ) ],
        [ "Jane Smith", "Marketing", 68000, createDate( 2019, 3, 22 ) ],
        [ "Bob Johnson", "Engineering", 82000, createDate( 2018, 7, 10 ) ],
        [ "Alice Williams", "Sales", 71000, createDate( 2021, 5, 5 ) ]
    ]
);

// Query the query
result = queryExecute(
    "SELECT name, salary FROM employees WHERE department = ?",
    [ "Engineering" ],
    { dbtype: "query" }
);

// Result contains 2 rows: John Doe and Bob Johnson
writeOutput( "Found #result.recordCount# engineers" );

🔗 ANSI JOIN Syntax

BoxLang supports modern ANSI JOIN syntax with unlimited table joins and full alias support.

INNER JOIN

Returns only matching rows from both tables:

LEFT (OUTER) JOIN

Returns all rows from the left table, with NULLs for non-matching right table rows:

RIGHT (OUTER) JOIN

Returns all rows from the right table, with NULLs for non-matching left table rows:

FULL (OUTER) JOIN

Returns all rows from both tables, with NULLs where matches don't exist:

CROSS JOIN

Returns the Cartesian product of both tables (every combination):

Multiple Table Joins

Join as many tables as needed:

🧩 Subqueries

BoxLang supports non-correlated subqueries in multiple contexts.

FROM/JOIN Subqueries

Use a subquery as a table source:

IN/NOT IN Subqueries

Filter using a subquery result set:

🎯 CASE Statements

CASE expressions provide conditional logic within SQL queries.

Standard CASE

Each WHEN contains a boolean expression:

Input CASE

Compare against a single input expression:

CASE in ORDER BY

📊 Aggregate Functions

BoxLang supports all standard aggregate functions plus powerful additions.

Standard Aggregates

String Aggregation

Concatenate values with delimiters:

🔧 Built-In Functions

BoxLang provides a comprehensive set of SQL functions.

Math Functions

Available: abs(), acos(), asin(), atan(), cos(), sin(), tan(), exp(), sqrt(), ceiling(), floor()

String Functions

Available: upper(), lower(), ucase(), lcase(), concat(), left(), right(), length(), ltrim(), rtrim()

NULL Handling

Available: coalesce(), isNull()

Type Conversion

Available: cast(), convert()

🛠️ Custom Function Registration

Register your own functions for use in QoQ queries.

Scalar Functions

Process a single value and return a single result:

Aggregate Functions

Process multiple values and return a single result:

📐 Operators

BoxLang QoQ supports all standard SQL operators plus bitwise operations.

Comparison Operators

Available: =, !=, <>, <, >, <=, >=, IS, IS NOT, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN

Mathematical Operators

Available: +, -, *, /, % (modulo)

Bitwise Operators

Available: & (AND), | (OR), ^ (XOR), ! (NOT)

String Concatenation

Available: || (concatenation)

🎚️ Query Clauses

DISTINCT

Remove duplicate rows:

WHERE

Filter rows:

GROUP BY

Aggregate data:

ORDER BY

Sort results:

TOP and LIMIT

Limit result count:

UNION

Combine multiple queries:

🎯 Advanced Examples

Data Transformation Pipeline

Complex Filtering

Pivot-like Operations

Data Deduplication

💡 Best Practices

Performance

  • Use JOINs over subqueries when possible for better performance

  • Filter early - Apply WHERE clauses to reduce row count before JOINs

  • Limit columns - SELECT only needed columns, not SELECT *

  • Use indexes - Original database query results maintain index information

  • Minimize DISTINCT - Use only when necessary as it requires deduplication

Memory Management

  • Limit result sets - Use TOP/LIMIT to prevent memory issues

  • Process in batches - For large datasets, break into smaller QoQ operations

  • Clean up queries - Remove references to large query objects when done

  • Monitor query size - Be aware of result set row counts and column widths

Code Quality

  • Use parameterized queries - Prevent SQL injection even in QoQ

  • Alias tables - Always use table aliases for clarity and readability

  • Format SQL - Use proper indentation and line breaks

  • Document complex logic - Comment non-obvious CASE statements and subqueries

  • Test edge cases - Verify NULL handling, empty results, and data type conversions

Data Integrity

  • Preserve types - QoQ maintains original column data types

  • Handle NULLs - Use COALESCE or ISNULL for NULL-safe operations

  • Validate joins - Ensure JOIN conditions match appropriate data types

  • Check for duplicates - Use DISTINCT when necessary

🚫 Common Pitfalls

Forgetting dbtype option

Ambiguous column references with multiple tables

Not handling NULL values

Using correlated subqueries

🔍 Limitations

Query of Queries has some limitations to be aware of:

  • No correlated subqueries - Subqueries cannot reference outer query tables

  • No window functions - OVER(), PARTITION BY not supported

  • No CTEs - Common Table Expressions (WITH clause) not available

  • Read-only - Cannot INSERT, UPDATE, or DELETE rows

  • No transactions - All operations are immediate

  • In-memory only - Large result sets may impact memory usage

📚 Additional Resources

Last updated

Was this helpful?