Представления

Представление (view) — именованный SQL-запрос, сохраненный в базу данных. Представление не хранит данные, а читает их из другой таблицы каждый раз, когда к нему обращаются. По сути, при чтении из представления определяющий его запрос используется как подзапрос в выражении FROM. Представления позволяют сохранять часто используемые или сложные запросы и использовать их в запросах SELECT как обычные таблицы.

Параметризованное представление (parameterized view) — представление с параметрами в условии фильтрации определяющего его запроса, значения которых должны передаваться при каждом обращении к представлению. Параметризованные представления могут быть удобны, когда нужно многократно использовать сложные аналитические запросы с переменными условиями фильтрации.

ADQM/ClickHouse также поддерживает материализованные представления (materialized view), которые в отличие от обычных представлений физически хранят данные (агрегатные состояния данных другой таблицы) и обновляются автоматически при вставке новых данных в исходную таблицу — подробнее в статье Материализованные представления.

Краткое сравнение типов представлений
Тип представления Хранение данных Параметры Производительность запросов Обновление представления

Представление

Нет

Нет

Не меняется (запрос выполняется каждый раз при обращении к представлению)

При каждом обращении к представлению

Параметризованное представление

Нет

Да

Не меняется (запрос выполняется при каждом обращении к представлению)

При каждом обращении к представлению

Материализованное представление

Да

Нет

Повышается (быстрое чтение за счет предварительной агрегации данных)

При вставке данных в исходную таблицу

Создание таблицы для примеров

Создайте таблицу sales и заполните ее тестовыми данными о продажах:

CREATE TABLE sales (
    sale_id UInt32,
    product_name String,
    sale_amount Decimal(10,2),
    customer_name String,
    sale_date Date
)
ENGINE = MergeTree()
ORDER BY sale_id;
INSERT INTO sales VALUES
(1, 'Smartphone_2', 700.00, 'Mary Burton', '2026-04-15'),
(2, 'Smartphone_1', 750.00, 'Robert Gray', '2026-04-17'),
(3, 'Monitor', 200.00, 'Linda Black', '2026-04-17'),
(4, 'Laptop', 1000.00, 'Paul Brown', '2026-04-17'),
(5, 'Monitor', 200.00, 'Mark Armstrong', '2026-04-18'),
(6, 'Keyboard', 75.50, 'David Green', '2026-04-18'),
(7, 'Keyboard', 75.50, 'Daniel Gray', '2026-05-01'),
(8, 'Laptop', 1000.00, 'Robert Gray', '2026-05-02'),
(9, 'Mouse', 25.50, 'Joseph Lewis', '2026-05-02'),
(10, 'Smartphone_2', 700.00, 'Paul Brown', '2026-05-03');
    ┌─sale_id─┬─product_name─┬─sale_amount─┬─customer_name──┬──sale_date─┐
 1. │       1 │ Smartphone_2 │         700 │ Mary Burton    │ 2026-04-15 │
 2. │       2 │ Smartphone_1 │         750 │ Robert Gray    │ 2026-04-17 │
 3. │       3 │ Monitor      │         200 │ Linda Black    │ 2026-04-17 │
 4. │       4 │ Laptop       │        1000 │ Paul Brown     │ 2026-04-17 │
 5. │       5 │ Monitor      │         200 │ Mark Armstrong │ 2026-04-18 │
 6. │       6 │ Keyboard     │        75.5 │ David Green    │ 2026-04-18 │
 7. │       7 │ Keyboard     │        75.5 │ Daniel Gray    │ 2026-05-01 │
 8. │       8 │ Laptop       │        1000 │ Robert Gray    │ 2026-05-02 │
 9. │       9 │ Mouse        │        25.5 │ Joseph Lewis   │ 2026-05-02 │
10. │      10 │ Smartphone_2 │         700 │ Paul Brown     │ 2026-05-03 │
    └─────────┴──────────────┴─────────────┴────────────────┴────────────┘

Создание представлений

Создание представления

Чтобы создать представление, используйте запрос CREATE VIEW. Синтаксис в общем виде:

CREATE VIEW [IF NOT EXISTS] [<db_name>.]<view_name> [ON CLUSTER <cluster_name>]
[DEFINER = { '<user_name>' | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER }]
AS SELECT ...
[COMMENT 'comment'];

где DEFINER и SQL SECURITY — параметры для управления доступом к данным (см. описание ниже).

ПРИМЕЧАНИЕ

Табличная функция view(<subquery>) реализует механизм, аналогичный представлению (CREATE VIEW), но существует только в рамках запроса, где она вызывается (объект в базе данных не создается). Функция возвращает результат подзапроса как таблицу, позволяя использовать ее в качестве источника данных в выражении FROM. Как и при использовании представления, данные не хранятся, подзапрос выполняется при каждом вызове функции.

Пример

Создайте представление, которое получает данные о продажах в мае:

CREATE VIEW sales_may AS
SELECT * FROM sales
WHERE toMonth(sale_date) = 5;

Запросы к представлению можно выполнять как к обычной таблице с помощью SELECT:

SELECT * FROM sales_may;
   ┌─sale_id─┬─product_name─┬─sale_amount─┬─customer_name─┬──sale_date─┐
1. │       7 │ Keyboard     │        75.5 │ Daniel Gray   │ 2026-05-01 │
2. │       8 │ Laptop       │        1000 │ Robert Gray   │ 2026-05-02 │
3. │       9 │ Mouse        │        25.5 │ Joseph Lewis  │ 2026-05-02 │
4. │      10 │ Smartphone_2 │         700 │ Paul Brown    │ 2026-05-03 │
   └─────────┴──────────────┴─────────────┴───────────────┴────────────┘

Создание параметризованного представления

Параметризованное представление создается как обычное представление, но в условии WHERE указываются параметры в виде {<param_name>:<param_type>}, например:

CREATE VIEW [IF NOT EXISTS] [<db_name>.]<view_name> [ON CLUSTER <cluster_name>]
[DEFINER = { '<user_name>' | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER }]
AS SELECT ...
WHERE <column_name1> = {<param_name1>:<data_type1>} AND <column_name2> != {<param_name2>:<data_type2>} ...
[COMMENT 'comment'];

где <param_name1>, <param_name2> — имена параметров; <data_type1>, <data_type2> — типы данных параметров.

Значения параметров необходимо передавать при каждом обращении к представлению в следующем формате:

SELECT <list_of_columns> FROM <view_name>(<param_name1>=<value1>, <param_name2>=<value2>, ...);

Таким образом, параметризованное представление вызывается как табличная функция — имя представления используется как имя функции, а значения параметров передаются в виде ее именованных аргументов.

Пример

Создайте параметризованное представление, которое получает данные о продажах указанного продукта за указанные месяц:

CREATE VIEW sales_product_by_month AS
SELECT * FROM sales
WHERE product_name = {product:String} AND toMonth(sale_date) = {month:UInt8};

При обращении к представлению необходимо передавать имя продукта и номер месяца как значения параметров product и month соответственно:

SELECT * FROM sales_product_by_month(product='Monitor', month=4);
   ┌─sale_id─┬─product_name─┬─sale_amount─┬─customer_name──┬──sale_date─┐
1. │       3 │ Monitor      │         200 │ Linda Black    │ 2026-04-17 │
2. │       5 │ Monitor      │         200 │ Mark Armstrong │ 2026-04-18 │
   └─────────┴──────────────┴─────────────┴────────────────┴────────────┘

SQL SECURITY и DEFINER

Параметры SQL SECURITY и DEFINER, которые можно указывать при создании представлений, позволяют гибко настраивать доступ к данным. Например, можно скрыть от пользователей исходные таблицы (данные из которых читают представления), предоставив им при этом доступ к агрегированным или отфильтрованным данным через представления.

Параметр Описание Возможные значения

SQL SECURITY

Указывает, права какого пользователя будут использоваться при выполнении запроса, определяющего представление

  • DEFINER — запрос будет выполняться от имени пользователя, указанного через параметр DEFINER. У этого пользователя должно быть право SELECT на таблицу, из которой представление читает данные.

  • INVOKER (по умолчанию) — запрос будет выполняться от имени пользователя, который обращается к представлению. У этого пользователя должно быть право SELECT на таблицу, из которой представление читает данные.

DEFINER

Указывает, права какого пользователя будут использоваться при выполнении запроса представления, если установлено SQL SECURITY DEFINER.

Чтобы установить значение параметра, у создающего представление пользователя должна быть привилегия SET DEFINER

  • '<user_name>' — имя существующего пользователя ADQM.

  • CURRENT_USER (по умолчанию) — в качестве значения параметра устанавливается имя пользователя, который создал представление.

Независимо от того, как настроены параметры разграничения доступа, для чтения данных из представления пользователю требуется разрешение SELECT ON <view_name>.

Пример

Предположим, доступ ко всем данным таблицы sales может иметь только администратор (пользователь admin, который создал эту таблицу), а другие пользователи могут получать данные о продажах без имен покупателей. Чтобы реализовать этот сценарий, выполните следующие шаги:

  1. Создайте нового пользователя:

    CREATE USER john IDENTIFIED WITH sha256_password BY 'qwerty';
  2. От имени администратора создайте представление, которое читает все данные о продажах из таблицы sales кроме имен покупателей:

    CREATE VIEW sales_without_customers
    DEFINER = admin SQL SECURITY DEFINER
    AS SELECT sale_id, product_name, sale_amount, sale_date
    FROM sales;
  3. Выдайте пользователю john доступ к этому представлению:

    GRANT SELECT ON sales_without_customers TO john;
  4. Обратитесь к представлению от имени пользователя john:

    SELECT * FROM sales_without_customers;

    Пользователю john будут доступны данные о продажах без информации о покупателях через представление sales_without_customers:

        ┌─sale_id─┬─product_name─┬─sale_amount─┬──sale_date─┐
     1. │       1 │ Smartphone_2 │         700 │ 2026-04-15 │
     2. │       2 │ Smartphone_1 │         750 │ 2026-04-17 │
     3. │       3 │ Monitor      │         200 │ 2026-04-17 │
     4. │       4 │ Laptop       │        1000 │ 2026-04-17 │
     5. │       5 │ Monitor      │         200 │ 2026-04-18 │
     6. │       6 │ Keyboard     │        75.5 │ 2026-04-18 │
     7. │       7 │ Keyboard     │        75.5 │ 2026-05-01 │
     8. │       8 │ Laptop       │        1000 │ 2026-05-02 │
     9. │       9 │ Mouse        │        25.5 │ 2026-05-02 │
    10. │      10 │ Smartphone_2 │         700 │ 2026-05-03 │
        └─────────┴──────────────┴─────────────┴────────────┘

    При этом у пользователя john нет прямого доступа к таблице sales. Если попытаться прочитать данные из таблицы sales от его имени, будет выведено сообщение:

    Exception: Received from localhost:9000. DB::Exception: john: Not enough privileges.
    To execute this query, it's necessary to have the grant SELECT(sale_id, product_name, sale_amount, customer_name, sale_date) ON default.sales. (ACCESS_DENIED)

Изменение представлений

Изменение запроса представления

Если необходимо изменить запрос, который определяет представление, используйте команду CREATE OR REPLACE VIEW:

CREATE OR REPLACE VIEW [<db_name>.]<view_name> AS SELECT ...

Если представление с таким именем существует, оно обновится в соответствии с новым определением его внутреннего запроса. Если представление не существует, то оно будет создано.

Изменение SQL SECURITY и DEFINER

Чтобы изменить настройки SQL SECURITY и DEFINER для существующего представления, используйте команду ALTER TABLE:

ALTER TABLE <view_name> MODIFY SQL SECURITY { DEFINER | INVOKER } [DEFINER = { '<user_name>' | CURRENT_USER }];

Получение информации о представлениях

Получить информацию о представлениях в базе данных ADQM/ClickHouse можно несколькими способами.

  • Посмотреть все таблицы и представления (см. столбец engine — для реализации представлений используется табличный движок View):

    SHOW FULL TABLES;
       ┌─name────────────────────┬─engine────┐
    1. │ sales                   │ MergeTree │
    2. │ sales_may               │ View      │
    3. │ sales_product_by_month  │ View      │
    4. │ sales_without_customers │ View      │
       └─────────────────────────┴───────────┘
  • Получить детальную информацию о представлениях можно из системной таблицы system.tables. Например, могут быть полезны столбцы:

    • as_select — запрос, определяющий представление;

    • parameterized_view_parameters — параметры параметризованного представления;

    • definer — пользователь, с правами которого выполняется запрос представления.

    SELECT
        name,
        as_select,
        parameterized_view_parameters,
        definer
    FROM system.tables
    WHERE engine = 'View' AND database = '<database_name>';\G
    Row 1:
    ──────
    name:                          sales_may
    as_select:                     SELECT * FROM default.sales WHERE toMonth(sale_date) = 5
    parameterized_view_parameters: []
    definer:
    
    Row 2:
    ──────
    name:                          sales_product_by_month
    as_select:                     SELECT * FROM default.sales WHERE (product_name = {product:String}) AND (toMonth(sale_date) = {month:UInt8})
    parameterized_view_parameters: [('product','String'),('month','UInt8')]
    definer:
    
    Row 3:
    ──────
    name:                          sales_without_customers
    as_select:                     SELECT sale_id, product_name, sale_amount, sale_date FROM default.sales
    parameterized_view_parameters: []
    definer:                       admin
  • Посмотреть запрос CREATE VIEW, с помощью которого было создано конкретное представление:

    SHOW CREATE VIEW <view_name>;

    Пример вывода на экран для представления sales_without_customers:

       ┌─statement───────────────────────────────────┐
    1. │ CREATE VIEW default.sales_without_customers │
       │ (                                           │
       │     `sale_id` UInt32,                       │
       │     `product_name` String,                  │
       │     `sale_amount` Decimal(10, 2),           │
       │     `sale_date` Date                        │
       │ )                                           │
       │ DEFINER = admin SQL SECURITY DEFINER        │
       │ AS SELECT                                   │
       │     sale_id,                                │
       │     product_name,                           │
       │     sale_amount,                            │
       │     sale_date                               │
       │ FROM default.sales                          │
       └─────────────────────────────────────────────┘
  • Информацию о представлениях можно также посмотреть в таблице VIEWS системной базы данных INFORMATION_SCHEMA:

    SELECT table_name, view_definition
    FROM information_schema.views
    WHERE table_schema = '<your_database_name>';
       ┌─table_name──────────────┬─view_definition──────────────────────────────────────────────────────────────────────────────────────────────┐
    1. │ sales_may               │ SELECT * FROM default.sales WHERE toMonth(sale_date) = 5                                                     │
    2. │ sales_product_by_month  │ SELECT * FROM default.sales WHERE (product_name = {product:String}) AND (toMonth(sale_date) = {month:UInt8}) │
    3. │ sales_without_customers │ SELECT sale_id, product_name, sale_amount, sale_date FROM default.sales                                      │
       └─────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

Отключение и подключение представлений

Представление можно отключить с помощью запроса DETACH VIEW:

DETACH VIEW [IF EXISTS] [<db_name.]<view_name> [ON CLUSTER <cluster_name>] [PERMANENTLY];

При выполнении этого запроса представление становится "невидимым" для сервера (перестает быть доступным для запросов), но его метаданные не удаляются. Если отключение не было перманентным (ключевое слово PERMANENTLY не использовалось в запросе), при следующем запуске сервер прочитает метаданные и снова будет "видеть" представление. Если представление было отключено перманентно, то сервер не подключит его обратно автоматически.

Независимо от того, каким способом представление было отключено, его можно подключить обратно с помощью запроса ATTACH TABLE:

ATTACH TABLE [IF NOT EXISTS] [<db_name.]<view_name> [ON CLUSTER <cluster_name>];

Удаление представлений

Чтобы удалить представление, используйте команду DROP VIEW:

DROP VIEW [IF EXISTS] [<db_name.]<view_name> [ON CLUSTER <cluster_name>];

Удалить представление также можно с помощью запроса DROP TABLE:

DROP TABLE [IF EXISTS] [<db_name.]<view_name> [ON CLUSTER <cluster_name>];
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней