SQL 参考

DDL

师成师成· 更新于 2026-09-28· 阅读 20 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

DDL

DDL 即“数据定义语言”(Data Definition Language),用于创建和修改目录(catalog)对象,例如表。

CREATE DATABASE

使用指定的名称创建目录。

CREATE DATABASE [ IF NOT EXISTS ] catalog
-- create catalog cat
CREATE DATABASE cat;

CREATE SCHEMA

在指定的 catalog 下创建 schema;若未指定,则使用 DataFusion 默认的 catalog。

CREATE SCHEMA [ IF NOT EXISTS ] [ catalog. ] schema_name
-- create schema emu under catalog cat
CREATE SCHEMA cat.emu;

CREATE EXTERNAL TABLE

CREATE EXTERNAL TABLE SQL 语句会将本地文件系统或远程对象存储中的某个位置注册为可查询的具名表。

支持的语法如下:

CREATE [UNBOUNDED] EXTERNAL TABLE
[ IF NOT EXISTS ]
<TABLE_NAME>[ (<column_definition>) ]
STORED AS <file_type>
[ PARTITIONED BY (<column list>) ]
[ WITH ORDER (<ordered column list>) ]
[ OPTIONS (<key_value_list>) ]
LOCATION <literal>

<column_definition> := (<column_name> <data_type>, ...)

<column_list> := (<column_name>, ...)

<ordered_column_list> := (<column_name> <sort_clause>, ...)

<key_value_list> := (<literal> <literal>, <literal> <literal>, ...)

有关 OPTIONS 子句中可指定的各格式特定选项的完整列表,请参阅格式选项。

file_type 的取值为 CSV、ARROW、PARQUET、AVRO 或 JSON。

LOCATION <字面量> 指定查找数据的位置。它可以是本地或对象存储上某个文件的路径,也可以是分区文件目录的路径。

可以以括号括起的字符串字面量列表形式提供多个位置,此时这些文件将作为一个表一起读取:

CREATE EXTERNAL TABLE hits
STORED AS PARQUET
LOCATION (
  's3://clickhouse-public-datasets/hits_compatible/athena_partitioned/hits_1.parquet',
  's3://clickhouse-public-datasets/hits_compatible/athena_partitioned/hits_2.parquet'
);

所有列出的文件位置必须位于同一对象存储中,并且解析出的数据需具有相同的 schema。

示例:Parquet

可以通过执行如下 CREATE EXTERNAL TABLE SQL 语句来注册 Parquet 数据源。Parquet 文件无需提供 schema 信息。

CREATE EXTERNAL TABLE taxi
STORED AS PARQUET
LOCATION '/mnt/nyctaxi/tripdata.parquet';

:::note

统计信息

默认情况下,创建表时 DataFusion 会读取文件以收集统计信息,这一过程可能开销较大,但能显著加速后续查询。如果你不想在创建表时收集统计信息,可在建表之前将 datafusion.execution.collect_statistics 配置选项设置为 false。例如:

:::

SET datafusion.execution.collect_statistics = false;

更多详情请参阅配置设置文档。

示例:逗号分隔值(CSV)

也可以通过执行 CREATE EXTERNAL TABLE SQL 语句来注册 CSV 数据源。表结构会根据扫描文件的一部分来推断得出。

CREATE EXTERNAL TABLE test
STORED AS CSV
LOCATION '/path/to/aggregate_simple.csv'
OPTIONS ('has_header' 'true');

示例:压缩

也可以使用压缩文件,例如 .csv.gz:

CREATE EXTERNAL TABLE test
STORED AS CSV
COMPRESSION TYPE GZIP
LOCATION '/path/to/aggregate_simple.csv.gz'
OPTIONS ('has_header' 'true');

示例:指定模式

也可以手动指定模式。

CREATE EXTERNAL TABLE test (
    c1  VARCHAR NOT NULL,
    c2  INT NOT NULL,
    c3  SMALLINT NOT NULL,
    c4  SMALLINT NOT NULL,
    c5  INT NOT NULL,
    c6  BIGINT NOT NULL,
    c7  SMALLINT NOT NULL,
    c8  INT NOT NULL,
    c9  BIGINT NOT NULL,
    c10 VARCHAR NOT NULL,
    c11 FLOAT NOT NULL,
    c12 DOUBLE NOT NULL,
    c13 VARCHAR NOT NULL
)
STORED AS CSV
LOCATION '/path/to/aggregate_test_100.csv'
OPTIONS ('has_header' 'true');

示例:分区表

也可以指定一个包含分区表的目录(多个具有相同 schema 的文件)。

CREATE EXTERNAL TABLE test
STORED AS CSV
LOCATION '/path/to/directory/of/files'
OPTIONS ('has_header' 'true');

采用 Hive 兼容分区方案进行分区的表,其分区列和分区值会被自动检测并纳入表的架构与数据中。假设存在如下示例目录结构:

hive_partitioned/
├── a=1
│   └── b=200
│       └── file1.parquet
└── a=2
    └── b=100
        └── file2.parquet

用户可以将顶层 hive_partitioned 目录指定为 EXTERNAL TABLE,并利用 Hive 分区来查询和过滤数据。

CREATE EXTERNAL TABLE hive_partitioned
STORED AS PARQUET
LOCATION '/path/to/hive_partitioned/';

SELECT count(*) FROM hive_partitioned WHERE b=100;
+------------------+
| count(*)         |
+------------------+
| 1                |
+------------------+

示例:无界数据源

我们可以使用 CREATE UNBOUNDED EXTERNAL TABLE SQL 语句创建无界数据源。

CREATE UNBOUNDED EXTERNAL TABLE taxi
STORED AS PARQUET
LOCATION '/mnt/nyctaxi/tripdata.parquet';

请注意,该语句实际上是从一个固定大小的文件中读取数据,因此更好的示例应该从 FIFO 文件中读取。不过,一旦 DataFusion 在数据源中看到 UNBOUNDED 关键字,它就会尝试以流式方式执行引用该无界源的查询。如果根据查询规范无法这样做,计划生成将失败,并提示无法以流式方式执行给定查询。请注意,能够与无界源(即在流式模式下)一起运行的查询,是能够与有界源一起运行的查询的子集。在无界源上失败的查询,在有界源上可能可以正常工作。

示例:WITH ORDER 子句

在基于某个已按某表达式排序的数据源生成输出时,你可以使用 WITH ORDER 子句预先指定数据的顺序。即使用于排序的表达式很复杂,这一子句也同样适用,从而提供了更大的灵活性。

以下是如何使用 WITH ORDER 子句的示例。

CREATE EXTERNAL TABLE test (
    c1  VARCHAR NOT NULL,
    c2  INT NOT NULL,
    c3  SMALLINT NOT NULL,
    c4  SMALLINT NOT NULL,
    c5  INT NOT NULL,
    c6  BIGINT NOT NULL,
    c7  SMALLINT NOT NULL,
    c8  INT NOT NULL,
    c9  BIGINT NOT NULL,
    c10 VARCHAR NOT NULL,
    c11 FLOAT NOT NULL,
    c12 DOUBLE NOT NULL,
    c13 VARCHAR NOT NULL
)
STORED AS CSV
WITH ORDER (c2 ASC, c5 + c8 DESC NULLS FIRST)
LOCATION '/path/to/aggregate_test_100.csv'
OPTIONS ('has_header' 'true');

WITH ORDER 子句用于指定排序顺序:

WITH ORDER (sort_expression1 [ASC | DESC] [NULLS { FIRST | LAST }]
         [, sort_expression2 [ASC | DESC] [NULLS { FIRST | LAST }] ...])

使用 WITH ORDER 子句的注意事项

  • 需要注意的是,在 CREATE EXTERNAL TABLE 语句中使用 WITH ORDER 子句,只是指定了从外部文件读取数据的顺序。如果文件中的数据并未按照指定的顺序排序,那么查询结果可能不正确。
  • 同样需要注意的是,WITH ORDER 子句不会影响外部文件中数据本身的排列顺序。

如果数据源已经采用 Hive 风格进行分区,可以使用 PARTITIONED BY 来实现分区裁剪。

/mnt/nyctaxi/year=2022/month=01/tripdata.parquet
/mnt/nyctaxi/year=2021/month=12/tripdata.parquet
/mnt/nyctaxi/year=2021/month=11/tripdata.parquet
CREATE EXTERNAL TABLE taxi
STORED AS PARQUET
PARTITIONED BY (year, month)
LOCATION '/mnt/nyctaxi';

CREATE TABLE

可以使用查询或值列表创建内存表。

CREATE [OR REPLACE] TABLE [IF NOT EXISTS] table_name AS [SELECT | VALUES LIST];
CREATE TABLE IF NOT EXISTS valuetable AS VALUES(1,'HELLO'),(12,'DATAFUSION');

CREATE TABLE IF NOT EXISTS valuetable(c1 INT, c2 VARCHAR) AS VALUES(1,'HELLO'),(12,'DATAFUSION');

CREATE TABLE memtable as select * from valuetable;

DROP TABLE

从 DataFusion 的 catalog 中移除该表。

DROP TABLE [ IF EXISTS ] table_name;
CREATE TABLE users AS VALUES(1,2),(2,3);
DROP TABLE users;
-- or use 'if exists' to silently ignore if the table doesn't exist
DROP TABLE IF EXISTS nonexistent_table;

CREATE VIEW

视图是基于 SQL 查询结果的虚拟表。它可以从现有的表或值列表创建。

CREATE [ OR REPLACE ] VIEW view_name AS statement;
CREATE TABLE users AS VALUES(1,2),(2,3),(3,4),(4,5);
CREATE VIEW test AS SELECT column1 FROM users;
SELECT * FROM test;
+---------+
| column1 |
+---------+
| 1       |
| 2       |
| 3       |
| 4       |
+---------+
CREATE VIEW test AS VALUES(1,2),(5,6);
SELECT * FROM test;
+---------+---------+
| column1 | column2 |
+---------+---------+
| 1       | 2       |
| 5       | 6       |
+---------+---------+

DROP VIEW(删除视图)

从 DataFusion 的 catalog 中移除该视图。

DROP VIEW [ IF EXISTS ] view_name;
-- drop users_v view from the customer_a schema
DROP VIEW IF EXISTS customer_a.users_v;

DESCRIBE

显示表的结构,包括列名、数据类型和是否可为空。DESCRIBE 和 DESC 均受支持,二者互为别名。

{ DESCRIBE | DESC } table_name

输出包含三列:

  • column_name:列的名称
  • data_type:列的数据类型(例如 Int32、Utf8、Boolean)
  • is_nullable:该列是否可以包含空值(YES/NO)

示例:基本表描述

-- Create a table
CREATE TABLE users AS VALUES (1, 'Alice', true), (2, 'Bob', false);

-- Describe the table structure
DESCRIBE users;

输出:

+--------------+-----------+-------------+
| column_name  | data_type | is_nullable |
+--------------+-----------+-------------+
| column1      | Int64     | YES         |
| column2      | Utf8      | YES         |
| column3      | Boolean   | YES         |
+--------------+-----------+-------------+

示例:使用 DESC 别名

-- DESC is an alias for DESCRIBE
DESC users;

示例:描述外部表

-- Create an external table
CREATE EXTERNAL TABLE taxi
STORED AS PARQUET
LOCATION '/mnt/nyctaxi/tripdata.parquet';

-- Describe its schema
DESCRIBE taxi;

输出可能显示:

+--------------------+-----------------------------+-------------+
| column_name        | data_type                   | is_nullable |
+--------------------+-----------------------------+-------------+
| vendor_id          | Int32                       | YES         |
| pickup_datetime    | Timestamp(Nanosecond, None) | NO          |
| passenger_count    | Int32                       | YES         |
| trip_distance      | Float64                     | YES         |
+--------------------+-----------------------------+-------------+

DESCRIBE 命令适用于 DataFusion 中的所有表类型,包括:

  • 使用 CREATE TABLE 创建的常规表
  • 使用 CREATE EXTERNAL TABLE 创建的外部表
  • 使用 CREATE VIEW 创建的视图
  • 使用限定名访问的不同 schema 中的表(例如 DESCRIBE schema_name.table_name)

评论

登录后参与评论

正在加载评论…