Предположим, я хочу выбрать все столбцы определенного типа из таблицы DuckDB. Например, выбрав все столбцы типа VARCHAR
после создания таблицы, например:
CREATE TABLE dummy (x VARCHAR, y BIGINT, z VARCHAR);
INSERT INTO dummy
VALUES ('a', 0, 'a'),
('b', 1, 'b'),
('c', 2, 'c');
В общем, у меня может быть произвольное количество столбцов типа VARCHAR
, поэтому этот запрос должен быть «динамическим». Я получаю список соответствующих столбцов, используя DESCRIBE
:
SELECT column_name
FROM (DESCRIBE dummy)
WHERE column_type = 'VARCHAR';
Этот оператор дает мне список имен столбцов типа VARCHAR
. Но как мне это использовать? Я попробовал использовать выражение COLUMNS
:
SELECT COLUMNS(
c->c IN (
SELECT column_name
FROM (DESCRIBE dummy)
WHERE column_type = 'VARCHAR'
)
)
FROM dummy
Но это дает мне ошибку: BinderException: Binder Error: Table function cannot contain subqueries
. Я не очень понимаю ошибку. Я получаю ту же ошибку при попытке:
SELECT COLUMNS(
c->list_contains(
(
SELECT column_name
FROM (DESCRIBE dummy)
WHERE column_type = 'VARCHAR'
),
c
)
)
FROM dummy
Как соединить точки между получением списка столбцов с помощью запроса DESCRIBE tbl
и последующим использованием этого списка для выбора tbl
?
🤔 А знаете ли вы, что...
SQL поддерживает множество инструментов для администрирования баз данных, таких как phpMyAdmin и SQL Server Management Studio.
Попробуйте использовать функциюuckdb_columns(), поскольку она предоставляет метаданные о столбцах, доступных в экземпляре DuckDB:
SELECT column_name
FROM duckdb_columns()
WHERE table_name = 'dummy' AND data_type = 'VARCHAR'
Я использую Python для объединения имен столбцов в одну строку, а затем использую эту строку в SELECT:
import duckdb
con = duckdb.connect('your_database.db')
column_names = con.execute("""
SELECT column_name
FROM duckdb_columns()
WHERE table_name = 'dummy' AND data_type = 'VARCHAR';
""").fetchall()
column_names = [col[0] for col in column_names]
columns_string = ', '.join(column_names)
query = f"SELECT {columns_string} FROM dummy;"
result = con.execute(query).fetchdf()
print(result)
Проверьте @jqurious, возможно, вам подойдет использование переменных уровня SQL.
Как вы заметили, сообщение об ошибке связывателя DuckDB гласит:
Табличная функция не может содержать подзапросы
Фактически это означает, что DuckDB не поддерживает тип «динамического» SQL, который вы имеете в виду.
Предложение COLUMNS допускает лямбда-выражения, которые дают некоторую степень гибкости в зависимости от имен столбцов, но в целом (*), если вы хотите динамически создавать SQL-запрос, вам придется либо использовать CLI DuckDB, либо полагаться на язык программирования. (например, Питон).
Чтобы использовать CLI DuckDB, вы обычно используете .once
(чтобы записать построенный запрос), а затем .read
(чтобы выполнить его), как показано на https://duckdbsnippets.com/snippets/14/dynamic-sql-in- дакдб-кли
(*) Расширение JSON обеспечивает некоторую поддержку выполнения операторов SQL SELECT
, созданных на основе JSON. См. json_execute_serialized_sql
в инструкции.
В DuckDB добавлены переменные уровня SQL¹, которые будут в следующем выпуске.
Пример SET VARIABLE
/GETVARIABLE
с использованием ночной сборки Python.
duckdb.sql("""
SET VARIABLE VARCHAR_NAMES = (
SELECT LIST(column_name)
FROM (DESCRIBE dummy)
WHERE column_type = 'VARCHAR'
)
""")
duckdb.sql("""
FROM DUMMY SELECT COLUMNS(x -> x in GETVARIABLE('VARCHAR_NAMES'))
""")
┌─────────┬─────────┐
│ x │ z │
│ varchar │ varchar │
├─────────┼─────────┤
│ a │ a │
│ b │ b │
│ c │ c │
└─────────┴─────────┘
1. https://github.com/duckdb/duckdb/pull/13084