Skip to content

Формат JSONQ

Модуль jsonq создан для удобного создания простых SQL конструкций по текстовой конфигурации в формате JSON

Спецификация формата

{
    "SELECT":   ["expression", ...],
    "FROM":     ["table_element", ...],
    "WHERE":    ["expression", ...],
    "GROUP BY": ["expression", ...],
    "HAVING":   ["expression", ...],
    "ORDER BY": ["expression", ...],
    "OPTIONS":  ["option", ...],
    "LIMIT":    int,
    "OFFSET":   int
}
expression
    =
    | <str>                       # имя столбца; короткий формат
    | [ <expr>, <as> ]            # выражение с алиасом; формат list
    ;

<expr> : любое поддерживаемое выражение в fs_alchemy.parsing.expression
table_element
    =
    | <str>                       # имя таблицы
    | [ <tab_expr>, <as>, <on>, <on>, ... ]  # имя таблицы, алиас, условие для join; формат list
    ;

<tab_expr> : любое поддерживаемое выражение в fs_alchemy.parsing.segment
option = 'distinct' | 'inner' ;
// если в секции всего один элемент и это str, то скобки списка можно опустить 
{
    ...
    "SECTION1": ["str", ...],
    "SECTION2": "str"
    ...
}

Поддержка переменных в запросе

Элементы \<expr>, \<tab_expr>, \<as>, \<on> поддерживают подстановку перенных. Переменной является alphanumeric текст в фигурных скобках, например "{prev_task}". Виды поддерживаемых переменных:

  • простые типы: int, float, bool, str - по ним подстановка осуществляется методом str.replace()
  • сложные: SQLAlchemy Selectable - поддерживается только в \<tab_expr> и только если выражение состоит ровно из одной переменной

Примеры запросов

// базовые SELECT
{
    "SELECT": "*",
    "FROM": "schema1.users"
}
{
    "SELECT": ["name", "gender"],
    "FROM": ["schema1.users"]
}
{
    "SELECT": [["1", "const_int"], ["'abc'", "const_str"]]
}
// алиасы
{
    "SELECT": ["u.name", "u.gender"],
    "FROM": [["schema1.users", "u"]]
}
{
    "SELECT": [
        ["u.name", "user_name"],
        "u.gender"
    ],
    "FROM": [["schema1.users", "u"]]
}
// джойны
{
    "SELECT": "*",
    "FROM": [
        ["schema1.users", "u"],
        ["schema1.salary", "s", "u.name = s.name"], // LEFT by default
    ]
}
{
    "OPTIONS": "inner",
    "SELECT": "*",
    "FROM": [
        ["schema1.users", "u"],
        ["schema1.salary", "s", "u.name = s.name"], // INNER
    ]
}
// distinct
{
    "OPTIONS": "distinct",
    "SELECT": "name",
    "FROM": "schema1.users"
}
// фильтры
{
    "SELECT": "*",
    "FROM": "schema1.users",
    "WHERE": "name = 'vasya'"
}
{
    "SELECT": "*",
    "FROM": "schema1.users",
    "WHERE": ["name = 'vasya'", "age > 18"] // условия через AND
}
// GROUP BY, HAVING, ORDER BY
{
    "SELECT": ["name", "gender", "count(1)"],
    "FROM": "schema1.users",
    "GROUP BY": ["name", "gender"],
    "HAVING": ["count(1) > 0"],
    "ORDER BY": "name" // ASC
}
// flat params
// column_name = 'name'
// salary_table = 'salary'
// min_pay = 1000
{
    "SELECT": "u.{column_name}",
    "FROM": [
        ["users", "u"],
        ["{salary_table}", "s", "u.{column_name} = s.{column_name}"],
    ],
    "WHERE": "gender = 'm' or salary_amt>{min_pay}",
}
// table params
{
    "id": "salary_subquery",
    "type": "cte",
    "body": {
        "SELECT": ["name", "salary_amt"],
        "FROM": "dwh.salary",
        "WHERE": ["salary_src = 'gbc'"]
    }
},
{
    "id": "query",
    "type": "cte",
    "body":{
        "SELECT": "u.name",
        "FROM": [
            ["users", "u"],
            ["{salary_subquery}", "s", "u.name = s.name"],
        ],
        "WHERE": "gender = 'm' or salary_amt > 1000",
    }
}