可写视图
可写视图
1. 功能概述
自 V2.0.10.1 版本起,支持通过 SQL 对指定表创建可写视图(Writable View)。可写视图可以像普通基表一样进行任意的读写操作,同时额外支持对表名和列名的修改。
2. 功能介绍
2.1 创建可写视图
2.1.1 语法定义
CREATE WRITABLE VIEW <VIEW_NAME> AS
SELECT (<SOURCE_COL>[ as <VIEW_COL>][COMMENT <comment>](,<SOURCE_COL>[ as <VIEW_COL>][COMMENT <comment>])* | '*')
FROM <TABLE_NAME> [COMMENT <comment>] [WITH (schema_cascade=true|false[, ttl=])];2.1.2 参数介绍
| 参数 | 说明 |
|---|---|
<VIEW_NAME> | 要创建的可写视图名称。 |
<TABLE_NAME> | 源表名称。可写视图基于该表创建。 |
<COLUMN_NAME> | 源表中的列名。可以选择全部列,也可以只选择部分列。 |
AS <NEW_NAME> | 为视图列指定新名称。未指定时,视图列名与源表列名一致。 |
COMMENT <comment> | 为视图或视图列添加注释。 |
schema_cascade | 是否将部分视图结构变更同步到源表。默认值为 true(详见下方说明)。 |
ttl | 视图 TTL。未指定或指定为 default 时继承源表 TTL。 |
2.1.3 使用说明
不支持跨 Database 创建可写视图。
不支持基于其他视图(包括树转表视图和可写视图)再次创建可写视图。
不支持多个视图列映射到同一个源表列,例如
temperature AS temp1, temperature AS temp2。如果创建视图时没有显式选择
time列,系统会自动补充源表的time列。支持仅选择部分 Tag 列,源表中未出现在视图中的 Tag 列,在通过视图写入时会使用
null补齐。通过可写视图写入或删除数据时,操作会作用到源表。操作可写视图时,若源表或其列已被删除,将会报错。
schema_cascade决定了通过可写视图发起的元数据修改操作是否会级联同步到源表。具体行为如下:
| 操作 | schema_cascade = true(默认) | schema_cascade = false |
|---|---|---|
| Rename Table / Column | 不支持同步到源表 | 不支持同步到源表 |
| 新增列(ADD COLUMN) | 同步到源表;若源表中已存在该列,需确保 category 和 type 一致,否则报错 | 仅在视图中新增;目标列必须在源表中存在,且 category 和 type 一致,否则报错 |
| 删除列(DROP COLUMN) | 同步到源表;若源表列的 category 与视图不一致则报错;若删除的是视图的 Tag 列,不会同步到源表; | 仅删除视图中的列,不影响源表 |
| 删除视图(DROP) | 若 cascade 为 true,则同步删除源表 | 仅删除视图,不影响源表 |
| 修改列数据类型 | 同步到源表 | 不允许修改 |
| 修改 TTL | 同步到源表 | 不影响源表 |
| 修改 Comment | 若显式设置了 comment 且 cascade 为 true,则同步给源表 | 不影响源表 |
注意:
源表的元数据修改 **不会 **自动同步到可写视图,操作可写视图时,如果源表或其列不存在,会报错。
源表的 TTL 修改 **不会 **自动同步到可写视图,当视图和源表的 TTL 不一致:
数据的物理删除会以源表为准
对新表的查询展示以两表较低的 TTL 为准
若
SET PROPERTIES同时修改了schema_cascade和其他属性(如 TTL),本次修改会沿用旧的schema_cascade值为准,后续操作才会以修改后的schema_cascade值为准。
数据同步相关:
创建 Pipe 时,如果指定的表为视图,则自动改写为源表。
元数据同步需要同步新的视图操作语句:
如果接收端同名表不为可写视图,或创建时接收端对应 sourceTable 不为基表,则报错。
cascade 对基表的任意修改需同步到接收端,无关接收端的状态。
pattern / privilege 仅支持 writable view 时,按接收端自身的 cascade 决定是否同步给接收端自身指定的源表;仅支持源表时,仅同步源表修改;都不支持则不同步。
对于 source 列,若发送端 view 和接收端 view 映射到表的列不同,接收端自身的和发送端的 source 列都会被修改。
对于接收端 privilege:skipIfNoPrivileges 为 true 时,按照上述规则进行裁剪映射;否则 view 鉴权报错返回失败,source 鉴权报错仍会无视 skipIfNoPrivileges 进行裁剪。
2.1.4 简单示例
- 创建一个与源表列一致的可写视图:
CREATE WRITABLE VIEW table1_view AS
SELECT *
FROM Table;- 创建一个使用新列名的可写视图:
CREATE WRITABLE VIEW table1_device_view AS
SELECT
region,
plant_id,
device_id AS device,
model_id AS model,
temperature AS temp,
humidity,
status,
arrival_time
FROM table1;- 创建一个带注释和 TTL 的可写视图:
CREATE WRITABLE VIEW table1_public_view AS
SELECT
region COMMENT '区域',
plant_id COMMENT '工厂编号',
device_id COMMENT '设备编号',
temperature COMMENT '温度',
humidity COMMENT '湿度',
status COMMENT '设备状态'
FROM table1
COMMENT '设备运行数据视图'
WITH (schema_cascade = false, ttl = 604800000);2.2 修改可写视图
2.2.1 语法定义
可写视图支持使用 ALTER VIEW 修改:
alterViewStatement
: ALTER VIEW (IF EXISTS)? from=qualifiedName RENAME TO to=identifier #renameTableView
| ALTER VIEW (IF EXISTS)? viewName=qualifiedName ADD COLUMN (IF NOT EXISTS)? viewColumnDefinition #addViewColumn
| ALTER VIEW (IF EXISTS)? viewName=qualifiedName RENAME COLUMN (IF EXISTS)? from=identifier TO to=identifier #renameViewColumn
| ALTER VIEW (IF EXISTS)? viewName=qualifiedName DROP COLUMN (IF EXISTS)? column=identifier #dropViewColumn
| ALTER VIEW (IF EXISTS)? viewName=qualifiedName SET PROPERTIES propertyAssignments #setTableViewProperties也可以使用兼容的 ALTER TABLE 语法:
alterTableStatement
: ALTER TABLE (IF EXISTS)? from=qualifiedName RENAME TO to=identifier #renameTable
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName ADD COLUMN (IF NOT EXISTS)? column=columnDefinition #addColumn
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName RENAME COLUMN (IF EXISTS)? from=identifier TO to=identifier #renameColumn
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName DROP COLUMN (IF EXISTS)? column=identifier #dropColumn
// set TTL can use this
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName SET PROPERTIES propertyAssignments #setTableProperties
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName ALTER COLUMN (IF EXISTS)? column=identifier SET DATA TYPE new_type=type #alterColumnDataType2.2.2 使用说明
重命名视图名或视图列名只影响视图自身,不会修改源表名称或源表列名。
视图元数据修改级联影响可参考2.1.3 小节中的说明表格。
2.2.3 简单示例
- 重命名可写视图:
ALTER VIEW table1_device_view
RENAME TO table1_equipment_view;- 重命名视图列:
ALTER VIEW table1_equipment_view
RENAME COLUMN device TO equipment_id;- 新增一个视图列:
ALTER VIEW table1_equipment_view
ADD COLUMN maintenance STRING ATTRIBUTE COMMENT '维护状态';- 修改视图 TTL:
ALTER VIEW table1_equipment_view
SET PROPERTIES ttl = 2592000000;- 关闭结构级联:
ALTER VIEW table1_equipment_view
SET PROPERTIES schema_cascade = false;- 重新开启结构级联后修改列类型:
ALTER VIEW table1_equipment_view
SET PROPERTIES schema_cascade = true;
ALTER TABLE table1_equipment_view
ALTER COLUMN humidity SET DATA TYPE DOUBLE;- 删除视图列:
ALTER VIEW table1_equipment_view
DROP COLUMN maintenance;2.3 删除可写视图
2.3.1 语法定义
dropViewStatement
: DROP VIEW (IF EXISTS)? qualifiedName
;也可以使用兼容的 DROP TABLE 语法:
dropTableStatement
: DROP TABLE (IF EXISTS)? qualifiedName
;2.3.2 使用说明
可写视图默认
schema_cascade=true。删除视图时,删除操作会同步影响源表。如果只希望删除视图、保留源表,请先将视图设置为
schema_cascade=false,再执行删除。
ALTER VIEW table1_equipment_view
SET PROPERTIES schema_cascade = false;2.3.3 简单示例
DROP VIEW IF EXISTS table1_equipment_view;
DROP TABLE IF EXISTS table1_equipment_view;2.4 查看可写视图
2.4.1 语法定义
showViewStatement
: SHOW WRITABLE? VIEWS ((FROM | IN) databaseName=identifier)? #showViews
| SHOW TABLES DETAILS ((FROM | IN) databaseName=identifier)? #showTablesDetails
| (DESC | DESCRIBE) viewName=qualifiedName DETAILS? #describeView
| SHOW CREATE (TABLE | VIEW) viewName=qualifiedName #showCreateView
;2.4.2 使用说明
SHOW VIEWS用于查看当前数据库下的视图;SHOW WRITABLE VIEWS仅展示可写视图。SHOW TABLES DETAILS会在结果集中通过TableType字段展示表或视图的类型。对于可写视图,TableType为WRITABLE VIEW,OriginalTableName列展示源表名称。对可写视图执行
DESC <VIEW_NAME> DETAILS时,结果集中OriginalColumn列,展示视图列对应的源表列名。SHOW CREATE VIEW和SHOW CREATE TABLE均可查看可写视图的创建语句。
2.4.3 简单示例
- 查看表和可写视图详情:
IoTDB:database1> show tables details
+------------------+---------+------+----------------+-------------+-----------------+
| TableName| TTL(ms)|Status| Comment| TableType|OriginalTableName|
+------------------+---------+------+----------------+-------------+-----------------+
| table1| INF| USING| null| BASE TABLE| null|
|table1_public_view|604800000| USING| 设备运行数据视图|WRITABLE VIEW| table1|
| table1_view| INF| USING| null|WRITABLE VIEW| table1|
+------------------+---------+------+----------------+-------------+-----------------+
Total line number = 3
It costs 0.004s- 查看可写视图的列信息:
IoTDB:database1> desc table1_view
+------------+---------+---------+
| ColumnName| DataType| Category|
+------------+---------+---------+
| time|TIMESTAMP| TIME|
| region| STRING| TAG|
| plant_id| STRING| TAG|
| device_id| STRING| TAG|
| model_id| STRING|ATTRIBUTE|
| maintenance| STRING|ATTRIBUTE|
| temperature| FLOAT| FIELD|
| humidity| FLOAT| FIELD|
| status| BOOLEAN| FIELD|
|arrival_time|TIMESTAMP| FIELD|
+------------+---------+---------+
Total line number = 10
It costs 0.013s- 查看可写视图的列详细信息:
IoTDB:database1> desc table1_view details
+------------+---------+---------+------+-------+------------------+
| ColumnName| DataType| Category|Status|Comment|OriginalColumnName|
+------------+---------+---------+------+-------+------------------+
| time|TIMESTAMP| TIME| USING| null| time|
| region| STRING| TAG| USING| null| region|
| plant_id| STRING| TAG| USING| null| plant_id|
| device_id| STRING| TAG| USING| null| device_id|
| model_id| STRING|ATTRIBUTE| USING| null| model_id|
| maintenance| STRING|ATTRIBUTE| USING| null| maintenance|
| temperature| FLOAT| FIELD| USING| null| temperature|
| humidity| FLOAT| FIELD| USING| null| humidity|
| status| BOOLEAN| FIELD| USING| null| status|
|arrival_time|TIMESTAMP| FIELD| USING| null| arrival_time|
+------------+---------+---------+------+-------+------------------+
Total line number = 10
It costs 0.006s- 查看可写视图创建语句:
IoTDB:database1> show create view table1_view
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| View| Create View|
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|table1_view|CREATE WRITABLE VIEW "table1_view" AS SELECT "time" AS "time","region" AS "region","plant_id" AS "plant_id","device_id" AS "device_id","model_id" AS "model_id","maintenance" AS "maintenance","temperature" AS "temperature","humidity" AS "humidity","status" AS "status","arrival_time" AS "arrival_time" FROM "table1" WITH (ttl='INF', schema_cascade=true)|
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Total line number = 1
It costs 0.011s- 查看可写视图列表:
IoTDB:database1> show writable views
+------------------+---------+
| TableName| TTL(ms)|
+------------------+---------+
|table1_public_view|604800000|
| table1_view| INF|
+------------------+---------+
Total line number = 2
It costs 0.004s3. 权限说明
| 操作 | 超级管理员 | 普通用户 |
|---|---|---|
| 创建可写视图 | 支持 | 需要 View(或所属DB,或 ANY) 的 CREATE 权限 和 原始 Table(或所属DB,或 ANY) 的 SELECT、INSERT、DELETE(如果 schema_cascade=true 则需要 ALTER 和 DROP)权限或 SYSTEM 权限 |
| 删除可写视图 | 支持 | 需要 View(或所属DB,或 ANY) 的 DROP 权限或 SYSTEM 权限 |
| 修改可写视图 | 支持 | 需要 View(或所属DB,或 ANY) 的 ALTER 权限或 SYSTEM 权限 |
| 对可写视图进行写入/删除/查询 | 支持 | 需要 View(或所属DB,或 ANY) 的 INSERT/DELETE/SELECT 权限或 SYSTEM 权限 |
由于创建视图时已经获取了源表的权限,后续操作时,如果操作者被赋予了对视图的权限,则视为被赋权者间接赋予了对源表的相应权限,因此不需要再对源表鉴权。
4. 场景示例
- 为已有表提供新名称
如果希望对外使用 table1_view 作为 table1 的新入口:
CREATE WRITABLE VIEW table1_view AS
SELECT *
FROM table1;之后可以直接查询视图:
SELECT *
FROM table1_view
WHERE device_id = '101';返回结果
+-----------------------------+------+--------+---------+--------+-----------+-----------+--------+------+-----------------------------+
| time|region|plant_id|device_id|model_id|maintenance|temperature|humidity|status| arrival_time|
+-----------------------------+------+--------+---------+--------+-----------+-----------+--------+------+-----------------------------+
|2024-11-30T09:30:00.000+08:00| 上海| 3002| 101| F| 360| 90.0| 35.2| true| null|
|2024-11-30T14:30:00.000+08:00| 上海| 3002| 101| F| 360| 90.0| 34.8| true|2024-11-30T14:30:17.000+08:00|
|2024-11-29T10:00:00.000+08:00| 上海| 3001| 101| D| 360| 85.0| null| null|2024-11-29T10:00:13.000+08:00|
|2024-11-27T16:38:00.000+08:00| 北京| 1001| 101| B| 180| null| 35.1| true|2024-11-27T16:37:01.000+08:00|
|2024-11-27T16:39:00.000+08:00| 北京| 1001| 101| B| 180| 85.0| 35.3| null| null|
|2024-11-27T16:40:00.000+08:00| 北京| 1001| 101| B| 180| 85.0| null| null|2024-11-27T16:37:03.000+08:00|
|2024-11-27T16:41:00.000+08:00| 北京| 1001| 101| B| 180| 85.0| null| null|2024-11-27T16:37:04.000+08:00|
|2024-11-27T16:42:00.000+08:00| 北京| 1001| 101| B| 180| null| 35.2| false| null|
|2024-11-27T16:43:00.000+08:00| 北京| 1001| 101| B| 180| null| null| false| null|
|2024-11-27T16:44:00.000+08:00| 北京| 1001| 101| B| 180| null| null| false|2024-11-27T16:37:08.000+08:00|
+-----------------------------+------+--------+---------+--------+-----------+-----------+--------+------+-----------------------------+
Total line number = 10
It costs 0.021s- 为字段提供业务名称
如果业务侧希望使用 device、temp 等更简短的字段名:
CREATE WRITABLE VIEW table1_business_view AS
SELECT
region,
plant_id,
device_id AS device,
model_id AS model,
maintenance,
temperature AS temp,
humidity,
status,
arrival_time
FROM table1;业务侧可以使用新字段名查询:
SELECT device, model, temp, humidity, status
FROM table1_business_view
WHERE region = '北京';返回结果
+------+-----+----+--------+------+
|device|model|temp|humidity|status|
+------+-----+----+--------+------+
| 100| A|90.0| 35.1| true|
| 100| A|90.0| 35.1| true|
| 101| B|null| 35.1| true|
| 101| B|85.0| 35.3| null|
| 101| B|85.0| null| null|
| 101| B|85.0| null| null|
| 101| B|null| 35.2| false|
| 101| B|null| null| false|
| 101| B|null| null| false|
+------+-----+----+--------+------+
Total line number = 9
It costs 0.044s- 只开放部分列
如果只希望用户访问设备状态和环境数据:
CREATE WRITABLE VIEW table1_status_view AS
SELECT
region,
plant_id,
device_id,
temperature,
humidity,
status
FROM table1
WITH (schema_cascade = false);用户查询时只需要关注公开列:
SELECT device_id, temperature, humidity, status
FROM table1_status_view
WHERE plant_id = '3002';返回结果
+---------+-----------+--------+------+
|device_id|temperature|humidity|status|
+---------+-----------+--------+------+
| 100| null| 45.1| true|
| 100| 90.0| 35.4| true|
| 101| 90.0| 35.2| true|
| 101| 90.0| 34.8| true|
+---------+-----------+--------+------+
Total line number = 4
It costs 0.034s- 兼容历史系统字段名
如果历史系统使用 factory、device、temp 字段名,可以创建兼容视图:
CREATE WRITABLE VIEW table1_legacy_view AS
SELECT
plant_id AS factory,
device_id AS device,
temperature AS temp,
humidity,
status
FROM table1;历史系统可以继续按旧字段名写入:
INSERT INTO table1_legacy_view (
time,
factory,
device,
temp,
humidity,
status
) VALUES (
2026-05-19T10:00:00+08:00,
'plant-01',
'device-001',
36.5,
42.0,
true
);验证写入结果:
IoTDB:database1> select * from table1_legacy_view where device = 'device-001';
+--------+----------+----+--------+------+-----------------------------+
| factory| device|temp|humidity|status| time|
+--------+----------+----+--------+------+-----------------------------+
|plant-01|device-001|36.5| 42.0| true|2026-05-19T10:00:00.000+08:00|
+--------+----------+----+--------+------+-----------------------------+
Total line number = 1
It costs 0.016s
IoTDB:database1> select * from table1 where device_id = 'device-001';
+-----------------------------+------+--------+----------+--------+-----------+-----------+--------+------+------------+
| time|region|plant_id| device_id|model_id|maintenance|temperature|humidity|status|arrival_time|
+-----------------------------+------+--------+----------+--------+-----------+-----------+--------+------+------------+
|2026-05-19T10:00:00.000+08:00| null|plant-01|device-001| null| null| 36.5| 42.0| true| null|
+-----------------------------+------+--------+----------+--------+-----------+-----------+--------+------+------------+
Total line number = 1
It costs 0.016s