DuckDB: как мне использовать результат запроса DESCRIBE для SELECT из таблицы?

Предположим, я хочу выбрать все столбцы определенного типа из таблицы 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.


3
54
3

Ответы:

Попробуйте использовать функцию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