Example

SQL Query

Small SQL-like queries.

← All examples

Specification

$flags: [ 'CASE_INSENSITIVE', 'WORD_BOUNDARY', 'FLEXIBLE_WHITESPACE' ]

Keyword:
  Select: 'select'
  Distinct: 'distinct'
  From: 'from'
  JoinType: { Inner: 'inner', Left: 'left( outer)?', Right: 'right( outer)?', Full: 'full( outer)?' }
  Join: 'join'
  On: 'on'
  Where: 'where'
  As: 'as'
  And: 'and'
  Or: 'or'
  In: 'in'
  GroupBy: 'group by'
  Having: 'having'
  OrderBy: 'order by'
  Limit: 'limit'
  Direction: { Asc: 'asc', Desc: 'desc' }

Token:
  
  String: [ '''.*?''', '".*?"' ]
  
  Number: '\d+(\.\d+)?'
  
  Identifier: '${!Keyword}[A-Za-z_][A-Za-z0-9_]*'
  
  Wildcard: '\*'
  
  ColumnRef:
    $fields: { table: Identifier, column: Identifier }
    $patterns: '#{table}\.#{column}'
  
  FunctionCall:
    $flags: OPTIONAL_WHITESPACE
    $fields: { name: Identifier, arguments: 'Token[]' }
    $patterns: '#{name}\(#{arguments}?\)'
  
  AliasedExpression:
    $fields: { value: Token, alias: Identifier }
    $patterns: '#{value} ${Keyword::As} #{alias}'
  
  Operator: '>=|<=|<>|!=|=|>|<'
  
  Subquery: '\(${Query}\)'

Condition:
  
  Comparison:
    $fields: { left: Token, operator: Operator, right: Token }
    $patterns: '#{left} #{operator} #{right}'
  
  InPredicate:
    $flags: OPTIONAL_WHITESPACE
    $fields: { field: Token, values: 'Token[]' }
    $patterns: '#{field} ${Keyword::In} \((#{values}(, #{values})*)\)'
  
  And:
    $fields: { conditions: 'Condition[]' }
    $patterns: '#{conditions}( ${Keyword::And} #{conditions})+'
  
  Or:
    $fields: { conditions: 'Condition[]' }
    $patterns: '#{conditions}( ${Keyword::Or} #{conditions})+'
  
  Group:
    $flags: OPTIONAL_WHITESPACE
    $patterns: '\( ${Condition} \)'

Clause:
  $types:
    TableRef:
      $fields: { name: Identifier, alias: Identifier }
      $patterns: '#{name}( #{alias})?'

  Select:
    $flags: OPTIONAL_WHITESPACE
    $fields: { selectItems: 'Token[]' }
    $patterns: '${Keyword::Select} #{selectItems}(, #{selectItems})*'
  
  From:
    $fields: { table: TableRef }
    $patterns: '${Keyword::From} #{table}'
  
  Join:
    $fields: { joinType: Keyword::JoinType, table: TableRef, condition: Condition }
    $patterns: '(#{joinType} )?${Keyword::Join} #{table} ${Keyword::On} #{condition}'
  
  Where:
    $fields: { condition: Condition }
    $patterns: '${Keyword::Where} #{condition}'
  
  GroupBy:
    $flags: OPTIONAL_WHITESPACE
    $fields: { columns: 'Token[]' }
    $patterns: '${Keyword::GroupBy} #{columns}(, #{columns})*'
  
  Having:
    $fields: { condition: Condition }
    $patterns: '${Keyword::Having} #{condition}'
  
  OrderBy:
    $flags: OPTIONAL_WHITESPACE
    $types:
      SortItem:
        $fields: { column: Token, direction: Keyword::Direction }
        $patterns: '#{column} #{direction}'
    $fields: { sortItems: 'SortItem[]' }
    $patterns: '${Keyword::OrderBy} #{sortItems}(, #{sortItems})*'
  
  Limit:
    $fields: { count: Number }
    $patterns: '${Keyword::Limit} #{count}'

Query:
  $fields:
    select: Clause::Select
    from: Clause::From
    join: Clause::Join
    where: Clause::Where
    groupBy: Clause::GroupBy
    having: Clause::Having
    orderBy: Clause::OrderBy
    limit: Clause::Limit
  $patterns:
    - '#{select} #{from}( #{join})?( #{where})?( #{groupBy})?( #{having})?( #{orderBy})?( #{limit})?'

Sample input

select * from projects;

SELECT customers.name, orders.order_date, orders.total_amount
FROM customers
  INNER JOIN orders ON customers.id = orders.customer_id
WHERE orders.total_amount > 100
  AND orders.status = 'Completed'
ORDER BY orders.order_date ASC
LIMIT 20;

select name, age, count(*) as total
from users
where age >= 18
group by name, age
having count(*) > 1
order by age desc
limit 10;

Select p.product_name, c.category_name, p.price
From products p
  Join categories c On p.category_id = c.id
Where p.price > (Select avg(price) From products Where category_id = p.category_id)
  And c.category_name In ('Books', 'Games')
Order By p.price Desc
Limit 15;

Result

[
  {
    "type": "Query",
    "text": "select * from projects",
    "start": 0,
    "end": 22,
    "fields": [
      {
        "type": "Clause::Select",
        "field": "select",
        "text": "select *",
        "start": 0,
        "end": 8,
        "fields": [
          {
            "type": "Token[]",
            "field": "selectItems",
            "text": "*",
            "start": 7,
            "end": 8,
            "items": [
              {
                "type": "Token::Wildcard",
                "text": "*",
                "start": 7,
                "end": 8
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::From",
        "field": "from",
        "text": "from projects",
        "start": 9,
        "end": 22,
        "fields": [
          {
            "type": "TableRef",
            "field": "table",
            "text": "projects",
            "start": 14,
            "end": 22,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "name",
                "text": "projects",
                "start": 14,
                "end": 22
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "type": "Query",
    "text": "SELECT customers.name, orders.order_date, orders.total_amount\nFROM customers\n  INNER JOIN orders ON customers.id = orders.customer_id\nWHERE orders.total_amount > 100\n  AND orders.status = 'Completed'\nORDER BY orders.order_date ASC\nLIMIT 20",
    "start": 25,
    "end": 264,
    "fields": [
      {
        "type": "Clause::Select",
        "field": "select",
        "text": "SELECT customers.name, orders.order_date, orders.total_amount",
        "start": 25,
        "end": 86,
        "fields": [
          {
            "type": "Token[]",
            "field": "selectItems",
            "text": "customers.name, orders.order_date, orders.total_amount",
            "start": 32,
            "end": 86,
            "items": [
              {
                "type": "Token::ColumnRef",
                "text": "customers.name",
                "start": 32,
                "end": 46,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "customers",
                    "start": 32,
                    "end": 41
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "name",
                    "start": 42,
                    "end": 46
                  }
                ]
              },
              {
                "type": "Token::ColumnRef",
                "text": "orders.order_date",
                "start": 48,
                "end": 65,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "orders",
                    "start": 48,
                    "end": 54
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "order_date",
                    "start": 55,
                    "end": 65
                  }
                ]
              },
              {
                "type": "Token::ColumnRef",
                "text": "orders.total_amount",
                "start": 67,
                "end": 86,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "orders",
                    "start": 67,
                    "end": 73
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "total_amount",
                    "start": 74,
                    "end": 86
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::From",
        "field": "from",
        "text": "FROM customers",
        "start": 87,
        "end": 101,
        "fields": [
          {
            "type": "TableRef",
            "field": "table",
            "text": "customers",
            "start": 92,
            "end": 101,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "name",
                "text": "customers",
                "start": 92,
                "end": 101
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Join",
        "field": "join",
        "text": "INNER JOIN orders ON customers.id = orders.customer_id",
        "start": 104,
        "end": 158,
        "fields": [
          {
            "type": "Keyword::JoinType::Inner",
            "field": "joinType",
            "text": "INNER",
            "start": 104,
            "end": 109
          },
          {
            "type": "TableRef",
            "field": "table",
            "text": "orders",
            "start": 115,
            "end": 121,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "name",
                "text": "orders",
                "start": 115,
                "end": 121
              }
            ]
          },
          {
            "type": "Condition::Comparison",
            "field": "condition",
            "text": "customers.id = orders.customer_id",
            "start": 125,
            "end": 158,
            "fields": [
              {
                "type": "Token::ColumnRef",
                "field": "left",
                "text": "customers.id",
                "start": 125,
                "end": 137,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "customers",
                    "start": 125,
                    "end": 134
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "id",
                    "start": 135,
                    "end": 137
                  }
                ]
              },
              {
                "type": "Token::Operator",
                "field": "operator",
                "text": "=",
                "start": 138,
                "end": 139
              },
              {
                "type": "Token::ColumnRef",
                "field": "right",
                "text": "orders.customer_id",
                "start": 140,
                "end": 158,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "orders",
                    "start": 140,
                    "end": 146
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "customer_id",
                    "start": 147,
                    "end": 158
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Where",
        "field": "where",
        "text": "WHERE orders.total_amount > 100\n  AND orders.status = 'Completed'",
        "start": 159,
        "end": 224,
        "fields": [
          {
            "type": "Condition::And",
            "field": "condition",
            "text": "orders.total_amount > 100\n  AND orders.status = 'Completed'",
            "start": 165,
            "end": 224,
            "fields": [
              {
                "type": "Condition[]",
                "field": "conditions",
                "text": "orders.total_amount > 100\n  AND orders.status = 'Completed'",
                "start": 165,
                "end": 224,
                "items": [
                  {
                    "type": "Condition::Comparison",
                    "text": "orders.total_amount > 100",
                    "start": 165,
                    "end": 190,
                    "fields": [
                      {
                        "type": "Token::ColumnRef",
                        "field": "left",
                        "text": "orders.total_amount",
                        "start": 165,
                        "end": 184,
                        "fields": [
                          {
                            "type": "Token::Identifier",
                            "field": "table",
                            "text": "orders",
                            "start": 165,
                            "end": 171
                          },
                          {
                            "type": "Token::Identifier",
                            "field": "column",
                            "text": "total_amount",
                            "start": 172,
                            "end": 184
                          }
                        ]
                      },
                      {
                        "type": "Token::Operator",
                        "field": "operator",
                        "text": ">",
                        "start": 185,
                        "end": 186
                      },
                      {
                        "type": "Token::Number",
                        "field": "right",
                        "text": "100",
                        "start": 187,
                        "end": 190
                      }
                    ]
                  },
                  {
                    "type": "Condition::Comparison",
                    "text": "orders.status = 'Completed'",
                    "start": 197,
                    "end": 224,
                    "fields": [
                      {
                        "type": "Token::ColumnRef",
                        "field": "left",
                        "text": "orders.status",
                        "start": 197,
                        "end": 210,
                        "fields": [
                          {
                            "type": "Token::Identifier",
                            "field": "table",
                            "text": "orders",
                            "start": 197,
                            "end": 203
                          },
                          {
                            "type": "Token::Identifier",
                            "field": "column",
                            "text": "status",
                            "start": 204,
                            "end": 210
                          }
                        ]
                      },
                      {
                        "type": "Token::Operator",
                        "field": "operator",
                        "text": "=",
                        "start": 211,
                        "end": 212
                      },
                      {
                        "type": "Token::String",
                        "field": "right",
                        "text": "'Completed'",
                        "start": 213,
                        "end": 224
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::OrderBy",
        "field": "orderBy",
        "text": "ORDER BY orders.order_date ASC",
        "start": 225,
        "end": 255,
        "fields": [
          {
            "type": "SortItem[]",
            "field": "sortItems",
            "text": "orders.order_date ASC",
            "start": 234,
            "end": 255,
            "items": [
              {
                "type": "SortItem",
                "text": "orders.order_date ASC",
                "start": 234,
                "end": 255,
                "fields": [
                  {
                    "type": "Token::ColumnRef",
                    "field": "column",
                    "text": "orders.order_date",
                    "start": 234,
                    "end": 251,
                    "fields": [
                      {
                        "type": "Token::Identifier",
                        "field": "table",
                        "text": "orders",
                        "start": 234,
                        "end": 240
                      },
                      {
                        "type": "Token::Identifier",
                        "field": "column",
                        "text": "order_date",
                        "start": 241,
                        "end": 251
                      }
                    ]
                  },
                  {
                    "type": "Keyword::Direction::Asc",
                    "field": "direction",
                    "text": "ASC",
                    "start": 252,
                    "end": 255
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Limit",
        "field": "limit",
        "text": "LIMIT 20",
        "start": 256,
        "end": 264,
        "fields": [
          {
            "type": "Token::Number",
            "field": "count",
            "text": "20",
            "start": 262,
            "end": 264
          }
        ]
      }
    ]
  },
  {
    "type": "Query",
    "text": "select name, age, count(*) as total\nfrom users\nwhere age >= 18\ngroup by name, age\nhaving count(*) > 1\norder by age desc\nlimit 10",
    "start": 267,
    "end": 395,
    "fields": [
      {
        "type": "Clause::Select",
        "field": "select",
        "text": "select name, age, count(*) as total",
        "start": 267,
        "end": 302,
        "fields": [
          {
            "type": "Token[]",
            "field": "selectItems",
            "text": "name, age, count(*) as total",
            "start": 274,
            "end": 302,
            "items": [
              {
                "type": "Token::Identifier",
                "text": "name",
                "start": 274,
                "end": 278
              },
              {
                "type": "Token::Identifier",
                "text": "age",
                "start": 280,
                "end": 283
              },
              {
                "type": "Token::AliasedExpression",
                "text": "count(*) as total",
                "start": 285,
                "end": 302,
                "fields": [
                  {
                    "type": "Token::FunctionCall",
                    "field": "value",
                    "text": "count(*)",
                    "start": 285,
                    "end": 293,
                    "fields": [
                      {
                        "type": "Token::Identifier",
                        "field": "name",
                        "text": "count",
                        "start": 285,
                        "end": 290
                      },
                      {
                        "type": "Token[]",
                        "field": "arguments",
                        "text": "*",
                        "start": 291,
                        "end": 292,
                        "items": [
                          {
                            "type": "Token::Wildcard",
                            "text": "*",
                            "start": 291,
                            "end": 292
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "alias",
                    "text": "total",
                    "start": 297,
                    "end": 302
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::From",
        "field": "from",
        "text": "from users",
        "start": 303,
        "end": 313,
        "fields": [
          {
            "type": "TableRef",
            "field": "table",
            "text": "users",
            "start": 308,
            "end": 313,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "name",
                "text": "users",
                "start": 308,
                "end": 313
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Where",
        "field": "where",
        "text": "where age >= 18",
        "start": 314,
        "end": 329,
        "fields": [
          {
            "type": "Condition::Comparison",
            "field": "condition",
            "text": "age >= 18",
            "start": 320,
            "end": 329,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "left",
                "text": "age",
                "start": 320,
                "end": 323
              },
              {
                "type": "Token::Operator",
                "field": "operator",
                "text": ">=",
                "start": 324,
                "end": 326
              },
              {
                "type": "Token::Number",
                "field": "right",
                "text": "18",
                "start": 327,
                "end": 329
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::GroupBy",
        "field": "groupBy",
        "text": "group by name, age",
        "start": 330,
        "end": 348,
        "fields": [
          {
            "type": "Token[]",
            "field": "columns",
            "text": "name, age",
            "start": 339,
            "end": 348,
            "items": [
              {
                "type": "Token::Identifier",
                "text": "name",
                "start": 339,
                "end": 343
              },
              {
                "type": "Token::Identifier",
                "text": "age",
                "start": 345,
                "end": 348
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Having",
        "field": "having",
        "text": "having count(*) > 1",
        "start": 349,
        "end": 368,
        "fields": [
          {
            "type": "Condition::Comparison",
            "field": "condition",
            "text": "count(*) > 1",
            "start": 356,
            "end": 368,
            "fields": [
              {
                "type": "Token::FunctionCall",
                "field": "left",
                "text": "count(*)",
                "start": 356,
                "end": 364,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "name",
                    "text": "count",
                    "start": 356,
                    "end": 361
                  },
                  {
                    "type": "Token[]",
                    "field": "arguments",
                    "text": "*",
                    "start": 362,
                    "end": 363,
                    "items": [
                      {
                        "type": "Token::Wildcard",
                        "text": "*",
                        "start": 362,
                        "end": 363
                      }
                    ]
                  }
                ]
              },
              {
                "type": "Token::Operator",
                "field": "operator",
                "text": ">",
                "start": 365,
                "end": 366
              },
              {
                "type": "Token::Number",
                "field": "right",
                "text": "1",
                "start": 367,
                "end": 368
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::OrderBy",
        "field": "orderBy",
        "text": "order by age desc",
        "start": 369,
        "end": 386,
        "fields": [
          {
            "type": "SortItem[]",
            "field": "sortItems",
            "text": "age desc",
            "start": 378,
            "end": 386,
            "items": [
              {
                "type": "SortItem",
                "text": "age desc",
                "start": 378,
                "end": 386,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "age",
                    "start": 378,
                    "end": 381
                  },
                  {
                    "type": "Keyword::Direction::Desc",
                    "field": "direction",
                    "text": "desc",
                    "start": 382,
                    "end": 386
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Limit",
        "field": "limit",
        "text": "limit 10",
        "start": 387,
        "end": 395,
        "fields": [
          {
            "type": "Token::Number",
            "field": "count",
            "text": "10",
            "start": 393,
            "end": 395
          }
        ]
      }
    ]
  },
  {
    "type": "Query",
    "text": "Select p.product_name, c.category_name, p.price\nFrom products p\n  Join categories c On p.category_id = c.id\nWhere p.price > (Select avg(price) From products Where category_id = p.category_id)\n  And c.category_name In ('Books', 'Games')\nOrder By p.price Desc\nLimit 15",
    "start": 398,
    "end": 664,
    "fields": [
      {
        "type": "Clause::Select",
        "field": "select",
        "text": "Select p.product_name, c.category_name, p.price",
        "start": 398,
        "end": 445,
        "fields": [
          {
            "type": "Token[]",
            "field": "selectItems",
            "text": "p.product_name, c.category_name, p.price",
            "start": 405,
            "end": 445,
            "items": [
              {
                "type": "Token::ColumnRef",
                "text": "p.product_name",
                "start": 405,
                "end": 419,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "p",
                    "start": 405,
                    "end": 406
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "product_name",
                    "start": 407,
                    "end": 419
                  }
                ]
              },
              {
                "type": "Token::ColumnRef",
                "text": "c.category_name",
                "start": 421,
                "end": 436,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "c",
                    "start": 421,
                    "end": 422
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "category_name",
                    "start": 423,
                    "end": 436
                  }
                ]
              },
              {
                "type": "Token::ColumnRef",
                "text": "p.price",
                "start": 438,
                "end": 445,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "p",
                    "start": 438,
                    "end": 439
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "price",
                    "start": 440,
                    "end": 445
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::From",
        "field": "from",
        "text": "From products p",
        "start": 446,
        "end": 461,
        "fields": [
          {
            "type": "TableRef",
            "field": "table",
            "text": "products p",
            "start": 451,
            "end": 461,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "name",
                "text": "products",
                "start": 451,
                "end": 459
              },
              {
                "type": "Token::Identifier",
                "field": "alias",
                "text": "p",
                "start": 460,
                "end": 461
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Join",
        "field": "join",
        "text": "Join categories c On p.category_id = c.id",
        "start": 464,
        "end": 505,
        "fields": [
          {
            "type": "TableRef",
            "field": "table",
            "text": "categories c",
            "start": 469,
            "end": 481,
            "fields": [
              {
                "type": "Token::Identifier",
                "field": "name",
                "text": "categories",
                "start": 469,
                "end": 479
              },
              {
                "type": "Token::Identifier",
                "field": "alias",
                "text": "c",
                "start": 480,
                "end": 481
              }
            ]
          },
          {
            "type": "Condition::Comparison",
            "field": "condition",
            "text": "p.category_id = c.id",
            "start": 485,
            "end": 505,
            "fields": [
              {
                "type": "Token::ColumnRef",
                "field": "left",
                "text": "p.category_id",
                "start": 485,
                "end": 498,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "p",
                    "start": 485,
                    "end": 486
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "category_id",
                    "start": 487,
                    "end": 498
                  }
                ]
              },
              {
                "type": "Token::Operator",
                "field": "operator",
                "text": "=",
                "start": 499,
                "end": 500
              },
              {
                "type": "Token::ColumnRef",
                "field": "right",
                "text": "c.id",
                "start": 501,
                "end": 505,
                "fields": [
                  {
                    "type": "Token::Identifier",
                    "field": "table",
                    "text": "c",
                    "start": 501,
                    "end": 502
                  },
                  {
                    "type": "Token::Identifier",
                    "field": "column",
                    "text": "id",
                    "start": 503,
                    "end": 505
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Where",
        "field": "where",
        "text": "Where p.price > (Select avg(price) From products Where category_id = p.category_id)\n  And c.category_name In ('Books', 'Games')",
        "start": 506,
        "end": 633,
        "fields": [
          {
            "type": "Condition::And",
            "field": "condition",
            "text": "p.price > (Select avg(price) From products Where category_id = p.category_id)\n  And c.category_name In ('Books', 'Games')",
            "start": 512,
            "end": 633,
            "fields": [
              {
                "type": "Condition[]",
                "field": "conditions",
                "text": "p.price > (Select avg(price) From products Where category_id = p.category_id)\n  And c.category_name In ('Books', 'Games')",
                "start": 512,
                "end": 633,
                "items": [
                  {
                    "type": "Condition::Comparison",
                    "text": "p.price > (Select avg(price) From products Where category_id = p.category_id)",
                    "start": 512,
                    "end": 589,
                    "fields": [
                      {
                        "type": "Token::ColumnRef",
                        "field": "left",
                        "text": "p.price",
                        "start": 512,
                        "end": 519,
                        "fields": [
                          {
                            "type": "Token::Identifier",
                            "field": "table",
                            "text": "p",
                            "start": 512,
                            "end": 513
                          },
                          {
                            "type": "Token::Identifier",
                            "field": "column",
                            "text": "price",
                            "start": 514,
                            "end": 519
                          }
                        ]
                      },
                      {
                        "type": "Token::Operator",
                        "field": "operator",
                        "text": ">",
                        "start": 520,
                        "end": 521
                      },
                      {
                        "type": "Token::Subquery",
                        "field": "right",
                        "text": "(Select avg(price) From products Where category_id = p.category_id)",
                        "start": 522,
                        "end": 589,
                        "fields": [
                          {
                            "type": "Clause::Select",
                            "field": "select",
                            "text": "Select avg(price)",
                            "start": 523,
                            "end": 540,
                            "fields": [
                              {
                                "type": "Token[]",
                                "field": "selectItems",
                                "text": "avg(price)",
                                "start": 530,
                                "end": 540,
                                "items": [
                                  {
                                    "type": "Token::FunctionCall",
                                    "text": "avg(price)",
                                    "start": 530,
                                    "end": 540,
                                    "fields": [
                                      {
                                        "type": "Token::Identifier",
                                        "field": "name",
                                        "text": "avg",
                                        "start": 530,
                                        "end": 533
                                      },
                                      {
                                        "type": "Token[]",
                                        "field": "arguments",
                                        "text": "price",
                                        "start": 534,
                                        "end": 539,
                                        "items": [
                                          {
                                            "type": "Token::Identifier",
                                            "text": "price",
                                            "start": 534,
                                            "end": 539
                                          }
                                        ]
                                      }
                                    ]
                                  }
                                ]
                              }
                            ]
                          },
                          {
                            "type": "Clause::From",
                            "field": "from",
                            "text": "From products",
                            "start": 541,
                            "end": 554,
                            "fields": [
                              {
                                "type": "TableRef",
                                "field": "table",
                                "text": "products",
                                "start": 546,
                                "end": 554,
                                "fields": [
                                  {
                                    "type": "Token::Identifier",
                                    "field": "name",
                                    "text": "products",
                                    "start": 546,
                                    "end": 554
                                  }
                                ]
                              }
                            ]
                          },
                          {
                            "type": "Clause::Where",
                            "field": "where",
                            "text": "Where category_id = p.category_id",
                            "start": 555,
                            "end": 588,
                            "fields": [
                              {
                                "type": "Condition::Comparison",
                                "field": "condition",
                                "text": "category_id = p.category_id",
                                "start": 561,
                                "end": 588,
                                "fields": [
                                  {
                                    "type": "Token::Identifier",
                                    "field": "left",
                                    "text": "category_id",
                                    "start": 561,
                                    "end": 572
                                  },
                                  {
                                    "type": "Token::Operator",
                                    "field": "operator",
                                    "text": "=",
                                    "start": 573,
                                    "end": 574
                                  },
                                  {
                                    "type": "Token::ColumnRef",
                                    "field": "right",
                                    "text": "p.category_id",
                                    "start": 575,
                                    "end": 588,
                                    "fields": [
                                      {
                                        "type": "Token::Identifier",
                                        "field": "table",
                                        "text": "p",
                                        "start": 575,
                                        "end": 576
                                      },
                                      {
                                        "type": "Token::Identifier",
                                        "field": "column",
                                        "text": "category_id",
                                        "start": 577,
                                        "end": 588
                                      }
                                    ]
                                  }
                                ]
                              }
                            ]
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "type": "Condition::InPredicate",
                    "text": "c.category_name In ('Books', 'Games')",
                    "start": 596,
                    "end": 633,
                    "fields": [
                      {
                        "type": "Token::ColumnRef",
                        "field": "field",
                        "text": "c.category_name",
                        "start": 596,
                        "end": 611,
                        "fields": [
                          {
                            "type": "Token::Identifier",
                            "field": "table",
                            "text": "c",
                            "start": 596,
                            "end": 597
                          },
                          {
                            "type": "Token::Identifier",
                            "field": "column",
                            "text": "category_name",
                            "start": 598,
                            "end": 611
                          }
                        ]
                      },
                      {
                        "type": "Token[]",
                        "field": "values",
                        "text": "'Books', 'Games'",
                        "start": 616,
                        "end": 632,
                        "items": [
                          {
                            "type": "Token::String",
                            "text": "'Books'",
                            "start": 616,
                            "end": 623
                          },
                          {
                            "type": "Token::String",
                            "text": "'Games'",
                            "start": 625,
                            "end": 632
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::OrderBy",
        "field": "orderBy",
        "text": "Order By p.price Desc",
        "start": 634,
        "end": 655,
        "fields": [
          {
            "type": "SortItem[]",
            "field": "sortItems",
            "text": "p.price Desc",
            "start": 643,
            "end": 655,
            "items": [
              {
                "type": "SortItem",
                "text": "p.price Desc",
                "start": 643,
                "end": 655,
                "fields": [
                  {
                    "type": "Token::ColumnRef",
                    "field": "column",
                    "text": "p.price",
                    "start": 643,
                    "end": 650,
                    "fields": [
                      {
                        "type": "Token::Identifier",
                        "field": "table",
                        "text": "p",
                        "start": 643,
                        "end": 644
                      },
                      {
                        "type": "Token::Identifier",
                        "field": "column",
                        "text": "price",
                        "start": 645,
                        "end": 650
                      }
                    ]
                  },
                  {
                    "type": "Keyword::Direction::Desc",
                    "field": "direction",
                    "text": "Desc",
                    "start": 651,
                    "end": 655
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "Clause::Limit",
        "field": "limit",
        "text": "Limit 15",
        "start": 656,
        "end": 664,
        "fields": [
          {
            "type": "Token::Number",
            "field": "count",
            "text": "15",
            "start": 662,
            "end": 664
          }
        ]
      }
    ]
  }
]

Notes

# SQL Query

Decompose a small SQL-like query subset into clauses, expressions, tables, and conditions.

## Notice

- SQL keywords are semantic keyword types.
- `Token` covers columns, literals, function calls, aliases, lists, and subqueries.
- `Condition` composes comparisons with `AND` and `OR`.
- `Clause` models select/from/join/where/group/having/order/limit parts.
- `OrderBy` supports multiple sort items.
- `Query` combines clauses into a full statement.

Try changing a column to `sum(orders.total)`.