> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8c05c8a2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> وثائق CREATE VIEW

# CREATE VIEW

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            غير مدعوم في ClickHouse Cloud
        </div>;
};

export const DeprecatedBadge = () => {
  return <div className="deprecatedBadge">
            <div className="deprecatedIcon">
            <svg width="14" height="10" viewBox="0 0 14 10" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M13 0H1C0.734784 0 0.48043 0.105357 0.292893 0.292893C0.105357 0.48043 0 0.734784 0 1V2.5C0 2.76522 0.105357 3.01957 0.292893 3.20711C0.48043 3.39464 0.734784 3.5 1 3.5V9C1 9.26522 1.10536 9.51957 1.29289 9.70711C1.48043 9.89464 1.73478 10 2 10H12C12.2652 10 12.5196 9.89464 12.7071 9.70711C12.8946 9.51957 13 9.26522 13 9V3.5C13.2652 3.5 13.5196 3.39464 13.7071 3.20711C13.8946 3.01957 14 2.76522 14 2.5V1C14 0.734784 13.8946 0.48043 13.7071 0.292893C13.5196 0.105357 13.2652 0 13 0ZM12 9H2V3.5H12V9ZM13 2.5H1V1H13V2.5ZM5 5.5C5 5.36739 5.05268 5.24021 5.14645 5.14645C5.24021 5.05268 5.36739 5 5.5 5H8.5C8.63261 5 8.75979 5.05268 8.85355 5.14645C8.94732 5.24021 9 5.36739 9 5.5C9 5.63261 8.94732 5.75979 8.85355 5.85355C8.75979 5.94732 8.63261 6 8.5 6H5.5C5.36739 6 5.24021 5.94732 5.14645 5.85355C5.05268 5.75979 5 5.63261 5 5.5Z" fill="currentColor" />
            </svg>
        </div>
            ميزة متقادمة
        </div>;
};

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            ميزة تجريبية. <u><a href="/docs/beta-and-experimental-features#experimental-features">تعرّف على المزيد.</a></u>
        </div>;
};

ينشئ عرضًا جديدًا. يمكن أن تكون العروض [عادية](#normal-view)، أو [مادية](#materialized-view)، أو [مادية قابلة للتحديث](#refreshable-materialized-view)، أو [عرض نافذة](/ar/reference/statements/create/view#window-view).

<div id="normal-view">
  ## عرض عادي
</div>

الصيغة:

```sql theme={null}
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [(alias1 [, alias2 ...])] [ON CLUSTER cluster_name]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

لا تخزّن العروض العادية أي بيانات. فهي تقتصر على القراءة من جدول آخر عند كل عملية وصول. وبعبارة أخرى، لا يعدّ العرض العادي سوى استعلام محفوظ. وعند القراءة من عرض، يُستخدم هذا الاستعلام المحفوظ بوصفه استعلامًا فرعيًا في بند [FROM](/ar/reference/statements/select/from).

على سبيل المثال، لنفترض أنك أنشأت عرضًا:

```sql theme={null}
CREATE VIEW view AS SELECT ...
```

وكتبت استعلامًا:

```sql theme={null}
SELECT a, b, c FROM view
```

هذا الاستعلام مطابق تمامًا لاستخدام الاستعلام الفرعي:

```sql theme={null}
SELECT a, b, c FROM (SELECT ...)
```

<div id="parameterized-view">
  ## العرض ذو المعلمات
</div>

تشبه العروض ذات المعلمات العروض العادية، لكنها يمكن أن تُنشأ بمعلمات لا تُفسَّر فورًا. ويمكن استخدام هذه العروض مع دوال الجداول، بحيث يُستخدَم اسم العرض اسمًا للدالة، وتُمرَّر قيم المعلمات كوسائط لها.

```sql theme={null}
CREATE VIEW view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...
```

ينشئ ما سبق عرضًا للجدول يمكن استخدامه كدالة جدولية بعد استبدال المعلمات كما هو موضح أدناه.

```sql theme={null}
SELECT * FROM view(column1=value1, column2=value2 ...)
```

<div id="materialized-view">
  ## العرض المادي
</div>

```sql theme={null}
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

```sql theme={null}
CREATE OR REPLACE MATERIALIZED VIEW [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[REFRESH ...]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

`OR REPLACE` و`IF NOT EXISTS` لا يمكن استخدامهما معًا: فالجمع بينهما يؤدي إلى خطأ نحوي.

<div id="create-or-replace-materialized-view">
  ### CREATE OR REPLACE MATERIALIZED VIEW
</div>

تستبدل `CREATE OR REPLACE MATERIALIZED VIEW` بشكل ذري عرضًا ماديًا موجودًا وجدول التخزين الداخلي الخاص به (إن وُجد). وتتطلب هذه العملية محرك قاعدة بيانات `Atomic` أو `Replicated`.

```sql theme={null}
CREATE OR REPLACE MATERIALIZED VIEW [db.]name [ON CLUSTER cluster]
[TO [db.]target_table]
[ENGINE = engine]
[POPULATE]
[REFRESH ...]
AS SELECT ...
```

السلوكيات الرئيسية:

* **بدون بند `TO`**: يُحذف الجدول الداخلي القديم ويُنشأ جدول جديد. وتُفقد البيانات الموجودة في الجدول الداخلي ما لم يتم تحديد `POPULATE`.
* **مع بند `TO`**: يُستبدل تعريف الـ view فقط؛ ولا يتأثر الجدول الهدف أو بياناته.
* متوافق مع `REFRESH` و`ON CLUSTER` وجميع خيارات المحرك. ولا يكون `POPULATE` مدعومًا إلا في قواعد البيانات `Atomic` — ويُرفض في قواعد البيانات `Replicated` (راجع ملاحظة `POPULATE` أدناه).
* يتطلب امتيازي `CREATE VIEW` و`DROP VIEW`.

<Note>
  لا يكون `CREATE OR REPLACE MATERIALIZED VIEW` مدعومًا إلا مع محركات قواعد البيانات `Atomic` أو `Replicated`. وهو غير مدعوم مع محرك قاعدة البيانات `Ordinary`.
</Note>

**أمثلة:**

```sql theme={null}
-- Create a materialized view with an inner table
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, sum(y) AS total FROM src GROUP BY x;

-- Replace with a new definition (old inner table data is lost)
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    AS SELECT x, count() AS cnt FROM src GROUP BY x;

-- Replace with POPULATE to backfill from existing source data
CREATE OR REPLACE MATERIALIZED VIEW mv
    ENGINE = MergeTree ORDER BY x
    POPULATE
    AS SELECT x FROM src;

-- Replace an inner-table MV with a TO-table MV (target data is preserved)
CREATE OR REPLACE MATERIALIZED VIEW mv TO target
    AS SELECT x FROM src;
```

<Tip>
  إليك دليلًا خطوة بخطوة لاستخدام [العروض المادية](/ar/concepts/features/materialized-views/cascading-materialized-views).
</Tip>

تخزّن العروض المادية البيانات التي يُحوّلها استعلام [SELECT](/ar/reference/statements/select/index) المرتبط بها.

عند إنشاء عرض مادي بدون `TO [db].[table]`، يجب تحديد `ENGINE` — وهو محرك الجدول المستخدم لتخزين البيانات.

عند إنشاء عرض مادي باستخدام `TO [db].[table]`، لا يمكنك أيضًا استخدام `POPULATE`.

يُنفَّذ العرض المادي على النحو التالي: عند إدراج البيانات في الجدول المحدد في `SELECT`، يُحوَّل جزء من البيانات المُدرَجة بواسطة استعلام `SELECT` هذا، ثم تُدرَج النتيجة في العرض.

<Note>
  تستخدم العروض المادية في ClickHouse **أسماء الأعمدة** بدلًا من ترتيب الأعمدة عند الإدراج في جدول الوجهة. وإذا لم تكن بعض أسماء الأعمدة موجودة في نتيجة استعلام `SELECT`، فإن ClickHouse يستخدم قيمة افتراضية، حتى إذا لم يكن العمود من النوع [Nullable](/ar/reference/data-types/nullable). ومن الممارسات الآمنة إضافة أسماء مستعارة لكل عمود عند استخدام العروض المادية.

  تُنفَّذ العروض المادية في ClickHouse بطريقة أقرب إلى مشغلات الإدراج. وإذا وُجد أي تجميع في استعلام العرض، فإنه يُطبَّق فقط على دفعة البيانات المُدرجة حديثًا. وأي تغييرات على البيانات الموجودة مسبقًا في الجدول المصدر (مثل update أو delete أو drop partition وما إلى ذلك) لا تغيّر العرض المادي.

  لا تتمتع العروض المادية في ClickHouse بسلوك حتمي عند حدوث أخطاء. وهذا يعني أن الكتل التي كُتبت بالفعل ستبقى محفوظة في جدول الوجهة، لكن جميع الكتل التي تأتي بعد الخطأ لن تُحفَظ.

  افتراضيًا، إذا تسببت الكتابة إلى أحد العروض في حدوث استثناء، فإن استعلام `INSERT` يفشل. وليس هناك ما يضمن ما إذا كانت الكتلة قد وصلت بالفعل إلى الجدول المصدر عند تلك النقطة — إذ يعتمد ذلك على توقيت مسار الإدراج، لا على خطأ العرض. أعد محاولة تنفيذ `INSERT` الذي فشل باستخدام إزالة تكرار الإدراج (`insert_deduplicate`, `deduplicate_blocks_in_dependent_materialized_views`) للحصول على تسليم exactly-once إلى الجدول المصدر وجميع العروض التابعة.

  إن تعيين `materialized_views_ignore_errors=true` في استعلام `INSERT` يغيّر فقط طريقة الإبلاغ عن الأخطاء: إذ يُسجَّل خطأ كل عرض على أنه تحذير وينجح استعلام `INSERT`. ويكون التسليم إلى وجهة العرض الفاشل جزئيًا — إذ تُحفَظ الكتل التي عولجت قبل الاستثناء، بينما تُسقَط الكتلة الفاشلة وأي كتل لاحقة من ذلك العرض. ولا ترى العروض التابعة لتلك الوجهة إلا الكتل التي وصلت فعلًا، لذا يكون تسليمها جزئيًا أيضًا. أما العروض الشقيقة (وسلاسلها التابعة) التي لم يحدث فيها استثناء فتُكتَب بالكامل، ويُكتَب إلى الجدول المصدر كالمعتاد. ونظرًا لأن `INSERT` يُبلِغ عن النجاح، فلن يتلقى العميل أي إشارة إلى الفشل ولن تُفعَّل أي إعادة محاولة تلقائية؛ لذا لا تستخدم هذا الإعداد إلا عندما يجب ألا تُحجَب عمليات الكتابة إلى الجدول المصدر بسبب مشكلات في جهة العرض (على سبيل المثال، جداول `system.*_log`).

  تكون القيمة الافتراضية لـ `materialized_views_ignore_errors` هي `true` بالنسبة إلى جداول `system.*_log`.
</Note>

إذا حددت `POPULATE`، فستُدرَج بيانات الجدول الموجودة مسبقًا في العرض عند إنشائه، كما لو كنت تنفذ `CREATE TABLE ... AS SELECT ...`. وإلا، فسيقتصر الاستعلام على البيانات المُدرجة في الجدول بعد إنشاء العرض. نحن **لا نوصي** باستخدام `POPULATE`، لأن البيانات المُدرجة في الجدول أثناء إنشاء العرض لن تُدرج فيه.

<Note>
  نظرًا إلى أن `POPULATE` يعمل مثل `CREATE TABLE ... AS SELECT ...`، فله القيود التالية:

  * غير مدعوم مع Replicated database
  * غير مدعوم في ClickHouse Cloud

  وبدلًا من ذلك، يمكن استخدام `INSERT ... SELECT` منفصل.
</Note>

يمكن أن يحتوي استعلام `SELECT` على `DISTINCT` و`GROUP BY` و`ORDER BY` و`LIMIT`. لاحظ أن التحويلات المقابلة تُنفَّذ بشكل مستقل على كل كتلة من البيانات المُدرجة. فعلى سبيل المثال، إذا كان `GROUP BY` مضبوطًا، تُجمَّع البيانات أثناء الإدراج، ولكن فقط ضمن حزمة واحدة من البيانات المُدرجة. ولن تُجمَّع البيانات لاحقًا. والاستثناء هو عند استخدام `ENGINE` ينفذ تجميع البيانات بشكل مستقل، مثل `SummingMergeTree`.

إذا كان العرض المادي يستخدم البنية `TO [db.]name`، فيمكنك `DETACH` العرض، ثم تشغيل `ALTER` على الجدول الهدف، ثم `ATTACH` العرض الذي فُصل (`DETACH`) سابقًا.

لاحظ أن العرض المادي يتأثر بإعداد [optimize\_on\_insert](/ar/reference/settings/session-settings#optimize_on_insert). إذ تُدمَج البيانات قبل إدراجها في العرض.

تبدو العروض مثل الجداول العادية. فعلى سبيل المثال، تُدرَج في نتيجة استعلام `SHOW TABLES`.

لحذف عرض، استخدم [DROP VIEW](/ar/reference/statements/drop#drop-view). مع أن `DROP TABLE` يعمل مع VIEW أيضًا.

<div id="sql_security">
  ## أمان SQL
</div>

يتيح لك `DEFINER` و`SQL SECURITY` تحديد مستخدم ClickHouse الذي سيُستخدم عند تنفيذ الاستعلام الأساسي للعرض.
لـ `SQL SECURITY` ثلاث قيم مسموح بها: `DEFINER` أو `INVOKER` أو `NONE`. ويمكنك تحديد أي مستخدم موجود أو `CURRENT_USER` في عبارة `DEFINER`.

يوضح الجدول التالي الصلاحيات المطلوبة لكل مستخدم لكي يتمكن من إجراء `SELECT` من العرض.
لاحظ أنه بغض النظر عن خيار `SQL SECURITY`، يبقى من الضروري في جميع الحالات امتلاك `GRANT SELECT ON <view>` للقراءة منه.

| خيار أمان SQL   | العرض                                                               | العرض المادي                                                                                                      |
| --------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `DEFINER alice` | يجب أن يمتلك `alice` صلاحية `SELECT` على جدول المصدر الخاص بالعرض.  | يجب أن يمتلك `alice` صلاحية `SELECT` على جدول المصدر الخاص بالعرض وصلاحية `INSERT` على الجدول الهدف الخاص بالعرض. |
| `INVOKER`       | يجب أن يمتلك المستخدم صلاحية `SELECT` على جدول المصدر الخاص بالعرض. | لا يمكن تحديد `SQL SECURITY INVOKER` للعروض المادية.                                                              |
| `NONE`          | -                                                                   | -                                                                                                                 |

<Note>
  يُعد الخيار `SQL SECURITY NONE` خيارًا Deprecated. سيتمكن أي مستخدم لديه صلاحية إنشاء عروض باستخدام `SQL SECURITY NONE` من تنفيذ أي query عشوائي.
  لذلك، يلزم وجود `GRANT ALLOW SQL SECURITY NONE TO <user>` لإنشاء عرض باستخدام هذا الخيار.
</Note>

إذا لم يتم تحديد `DEFINER`/`SQL SECURITY`، فستُستخدم القيم الافتراضية:

* `SQL SECURITY`: `INVOKER` للعروض العادية و`DEFINER` للعروض المادية ([قابل للتهيئة عبر الإعدادات](/ar/reference/settings/session-settings#default_normal_view_sql_security))
* `DEFINER`: `CURRENT_USER` ([قابل للتهيئة عبر الإعدادات](/ar/reference/settings/session-settings#default_view_definer))

إذا جرى Attach لعرض بدون تحديد `DEFINER`/`SQL SECURITY`، فستكون القيمة الافتراضية هي `SQL SECURITY NONE` للعرض المادي و`SQL SECURITY INVOKER` للعرض العادي.

لتغيير أمان SQL لعرض موجود، استخدم

```sql theme={null}
ALTER TABLE MODIFY SQL SECURITY { DEFINER | INVOKER | NONE } [DEFINER = { user | CURRENT_USER }]
```

<div id="examples">
  ### أمثلة
</div>

```sql theme={null}
CREATE VIEW test_view
DEFINER = alice SQL SECURITY DEFINER
AS SELECT ...
```

```sql theme={null}
CREATE VIEW test_view
SQL SECURITY INVOKER
AS SELECT ...
```

<div id="live-view">
  ## Live View
</div>

هذه الميزة مُهمَلة وسيتم إزالتها لاحقًا.

لراحتك، يمكنك العثور على الوثائق القديمة [هنا](https://pastila.nl/?00f32652/fdf07272a7b54bda7e13b919264e449f.md)

<div id="refreshable-materialized-view">
  ## العرض المادي القابل للتحديث
</div>

```sql theme={null}
CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
REFRESH [EVERY|AFTER interval [OFFSET interval]]
[RANDOMIZE FOR interval]
[DEPENDS ON [db.]name [, [db.]name [, ...]]]
[SETTINGS name = value [, name = value [, ...]]]
[APPEND]
[TO[db.]name] [(columns)] [ENGINE = engine]
[EMPTY]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'comment']
```

حيث إن `interval` عبارة عن سلسلة من الفترات البسيطة:

```sql theme={null}
number SECOND|MINUTE|HOUR|DAY|WEEK|MONTH|YEAR
```

يجب أن يحدِّد بند `REFRESH` واحدًا على الأقل من `EVERY` أو `AFTER` أو `DEPENDS ON`. ويُرفض استخدام `REFRESH` المجرّد (من دون أيٍّ من هذه العناصر). كما أن `REFRESH DEPENDS ON ...` من دون `EVERY`/`AFTER` هو اختصار لـ `REFRESH AFTER 0 SECOND DEPENDS ON ...`؛ راجع [تبعيات التحديث](#refresh-dependencies) أدناه.

يشغِّل الاستعلام المقابل دوريًا ويخزّن نتيجته في جدول.

* إذا تم تحديد `APPEND`، فإن كل عملية تحديث تُدرِج صفوفًا في الجدول من دون حذف الصفوف الموجودة. ولا تكون عملية الإدراج ذرّية، تمامًا مثل استعلام `INSERT INTO ... SELECT` العادي.
* بخلاف ذلك، يستبدل كل تحديث محتويات الجدول السابقة بشكل ذرّي.

الاختلافات عن العروض المادية العادية غير القابلة للتحديث:

* لا يوجد مشغّل إدراج. عند إدراج بيانات جديدة في الجدول المحدد في `SELECT`، لا يتم تمريرها تلقائيًا إلى العرض المادي القابل للتحديث. وبدلًا من ذلك، لا يحدث إدراج البيانات إلا أثناء تشغيل عمليات التحديث الدورية أو اليدوية.
* لا توجد قيود على استعلام `SELECT`. دوال الجداول (مثل `url()`)، والعروض، وUNION، وJOIN، كلها مسموح بها.

<Note>
  الإعدادات الموجودة في جزء `REFRESH ... SETTINGS` من الاستعلام هي إعدادات التحديث (مثل `refresh_retries`)، وهي مختلفة عن الإعدادات العادية (مثل `max_threads`). ويمكن تحديد الإعدادات العادية باستخدام `SETTINGS` في نهاية الاستعلام.
</Note>

<div id="refresh-schedule">
  ### جدولة التحديث
</div>

أمثلة على جداول التحديث:

```sql theme={null}
REFRESH EVERY 1 DAY -- every day, at midnight (UTC)
REFRESH EVERY 1 MONTH -- on 1st day of every month, at midnight
REFRESH EVERY 1 MONTH OFFSET 5 DAY 2 HOUR -- on 6th day of every month, at 2:00 am
REFRESH EVERY 2 WEEK OFFSET 5 DAY 15 HOUR 10 MINUTE -- every other Saturday, at 3:10 pm
REFRESH EVERY 30 MINUTE -- at 00:00, 00:30, 01:00, 01:30, etc
REFRESH AFTER 30 MINUTE -- 30 minutes after the previous refresh completes, no alignment with time of day
-- REFRESH AFTER 1 HOUR OFFSET 1 MINUTE -- syntax error, OFFSET is not allowed with AFTER
REFRESH EVERY 1 WEEK 2 DAYS -- every 9 days, not on any particular day of the week or month;
                            -- specifically, when day number (since 1969-12-29) is divisible by 9
REFRESH EVERY 5 MONTHS -- every 5 months, different months each year (as 12 is not divisible by 5);
                       -- specifically, when month number (since 1970-01) is divisible by 5
```

يقوم `RANDOMIZE FOR` بضبط وقت كل عملية تحديث عشوائيًا، على سبيل المثال:

```sql theme={null}
REFRESH EVERY 1 DAY OFFSET 2 HOUR RANDOMIZE FOR 1 HOUR -- every day at random time between 01:30 and 02:30
```

يمكن تشغيل عملية تحديث واحدة فقط في كل مرة لعرض معيّن. على سبيل المثال، إذا كان عرض يحتوي على `REFRESH EVERY 1 MINUTE` يستغرق دقيقتين لإجراء التحديث، فسيُحدَّث كل دقيقتين فقط. وإذا أصبح بعد ذلك أسرع وبدأ التحديث خلال 10 ثوانٍ، فسيعود إلى التحديث كل دقيقة. (وعلى وجه الخصوص، لن يُحدَّث كل 10 ثوانٍ لتعويض تحديثات فائتة متراكمة — إذ لا يوجد أصلًا مثل هذا التراكم.)

عادةً ما يبدأ أول تحديث فور إنشاء الـ materialized view: إذ يكون الوقت منذ آخر تحديث لانهائيًا، لذا يشير أي schedule إلى أن وقت التحديث قد حان الآن. إذا تم تحديد `EMPTY`، فسيتم تخطي هذا التحديث الأولي، وسيحدث أول تحديث في الوقت المجدول التالي؛ فعلى سبيل المثال، مع `EVERY 1 HOUR` سيحدث أول تحديث عند نهاية الساعة الحالية.

<div id="in-replicated-db">
  ### في قاعدة بيانات Replicated
</div>

إذا كان العرض المادي القابل للتحديث موجودًا في [قاعدة بيانات Replicated](/ar/reference/engines/database-engines/replicated)، فإن النُسخ المتماثلة تتنسّق فيما بينها بحيث لا تنفّذ التحديث في كل وقت مجدول إلا نسخة متماثلة واحدة فقط. ويُشترط استخدام محرك الجداول [ReplicatedMergeTree](/ar/reference/engines/table-engines/mergetree-family/replication)، حتى تتمكن جميع النُسخ المتماثلة من رؤية البيانات الناتجة عن التحديث.

في وضع `APPEND`، يمكن تعطيل التنسيق باستخدام `SETTINGS all_replicas = 1`. وهذا يجعل النُسخ المتماثلة تنفّذ عمليات التحديث بشكل مستقل عن بعضها البعض. وفي هذه الحالة، لا يكون ReplicatedMergeTree مطلوبًا.

في الوضع غير `APPEND`، لا يُدعَم إلا التحديث المنسَّق. أما إذا أردت تحديثًا غير منسَّق، فاستخدم قاعدة بيانات `Atomic` واستعلام `CREATE ... ON CLUSTER` لإنشاء عروض مادية قابلة للتحديث على جميع النُسخ المتماثلة.

يتم التنسيق عبر Keeper. ويُحدَّد مسار znode بواسطة إعداد الخادم [default\_replica\_path](/ar/reference/settings/server-settings/settings#default_replica_path).

<div id="refresh-dependencies">
  ### تبعيات إعادة التحديث
</div>

`DEPENDS ON` يزامن عمليات إعادة التحديث بين الجداول المختلفة:

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH EVERY 1 HOUR DEPENDS ON dependency [...]
```

لن يبدأ تحديث العرض التابع إلا بعد اكتمال تحديث جميع العروض التي يعتمد عليها.

لإجراء التحديث مباشرةً بعد تحديث عرض آخر:

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH AFTER 0 SECOND DEPENDS ON dependency [...]
```

أو بشكلٍ مكافئ:

```sql theme={null}
CREATE MATERIALIZED VIEW dependent REFRESH DEPENDS ON dependency [...]
```

<Note>
  لا تعمل `DEPENDS ON` إلا بين العروض المادية القابلة للتحديث. وعلى وجه الخصوص، إذا كان عرض التبعية يستخدم `TO <table>`، فتأكد من استخدام اسم العرض لا اسم الجدول. وإذا كانت قائمة `DEPENDS ON` تتضمن جدولًا عاديًا أو عرضًا غير قابل للتحديث أو تحتوي على خطأ مطبعي، فلن يتم تحديث العرض أبدًا، وستظهر حالته `MissingDependencies` في `system.view_refreshes`. ويمكن تغيير التبعيات أو إزالتها باستخدام `ALTER`، راجع [تغيير معلمات التحديث](#changing-refresh-parameters).
</Note>

<div id="using-depends-on-for-consistent-propagation-latency">
  #### استخدام `DEPENDS ON` لتحقيق زمن انتشار متسق
</div>

إذا كان كلا العرضين يستخدم `REFRESH EVERY` بالفترة نفسها، فستُطبَّق التبعية في كل فترة زمنية.

على سبيل المثال، افترض أن العرضين X وY يستخدمان كلاهما `REFRESH EVERY 1 HOUR`، وأن Y يقرأ من جدول المخرجات الخاص بـ X. من دون تبعيات، سيرى Y عادةً بيانات X الناتجة عن عملية `refresh` الخاصة بالساعة السابقة. ومع `DEPENDS ON X`، لن تبدأ عملية `refresh` الخاصة بـ Y عند الساعة 11:00 إلا بعد اكتمال عملية `refresh` الخاصة بـ X عند الساعة 11:00.

```text theme={null}
           10:00            11:00            12:00
           │                │                │
  X:        [run]┐           [run]┐           [run]┐
                 │                │                │
  Y:             └►[run]          └►[run]          └►[run]
```

قد يتخطّى كلٌّ من التبعية والتابع فتراتٍ زمنيةً بصورة مستقلة إذا استغرقت عمليات التحديث وقتًا أطول من فترة التحديث. ولا يوجد ما يضمن أن يُحدَّث التابع مرةً واحدةً بالضبط لكل تحديث للتبعية.

```text theme={null}
           10:00          11:00          12:00          13:00
           │              │              │              |
  X:        [run]┐         [run]┐         [run]┐         [run]┐
                 │              └────┐    (Y skips 12:00)     └───┐
  Y:             └►[10:00 ru------un]└►[11:00 ru---------------un]└►[13:00 run]
```

<div id="using-depends-on-for-batched-stream-processing">
  #### استخدام `DEPENDS ON` في معالجة التدفق على دفعات
</div>

إذا لم يُستخدَم `REFRESH EVERY`، فسيُحدَّث العرض التابع X إذا كانت جميع تبعياته قد تحدّثت مرة واحدة على الأقل منذ آخر تحديث لـ X. ويضيف `REFRESH AFTER T` تأخيرًا: إذ سيبدأ العنصر التابع التحديث بعد مرور مدة T على اكتمال تحديث التبعية.

التبعيات الدائرية مسموح بها ومفيدة. تأمّل هذا الرسم البياني للعروض المادية القابلة للتحديث:

1. يأخذ X دفعة من الصفوف من تدفقٍ ما ويضعها في جدول.
2. ثم يقرأ كلٌّ من Y وZ من ذلك الجدول، ويُجريان عمليات تجميع مختلفة، ويضيفان النتائج إلى جداول أخرى.
3. بعد اكتمال معالجة الدفعة بالكامل، يأخذ X الدفعة التالية، وتتكرر الدورة.

```text theme={null}
            source
               │
               ▼
          ┌─────────┐
     ┌───►│    X    │◄───┐
     │    └──┬───┬──┘    │
  DEPENDS    │   │    DEPENDS
    ON       ▼   ▼      ON
     │      ┌─┐ ┌─┐      │
     └──────┤Y│ │Z├──────┘
            └─┘ └─┘
```

مثال كامل:

```sql theme={null}
CREATE TABLE current_batch (t UInt64, v Int64) ENGINE ReplicatedMergeTree ORDER BY t;
CREATE TABLE batch_log (max_t UInt64, n Int64, v_sum Int64, processed_at DateTime64) ENGINE ReplicatedMergeTree ORDER BY max_t;
CREATE TABLE stats (h UInt64, n UInt64) ENGINE ReplicatedSummingMergeTree ORDER BY h;

-- (system.numbers stands in for a data source with monotonically increasing timestamps or sequence numbers)
CREATE MATERIALIZED VIEW current_batch_v REFRESH EVERY 10 SECOND DEPENDS ON batch_log_v, stats_v TO current_batch AS SELECT number as t, number * 10 as v FROM system.numbers WHERE number > (SELECT max(max_t) FROM batch_log) LIMIT 100;

CREATE MATERIALIZED VIEW batch_log_v REFRESH DEPENDS ON current_batch_v APPEND TO batch_log AS SELECT max(t) as max_t, count() as n, sum(v) as v_sum, now64() as processed_at FROM current_batch;

CREATE MATERIALIZED VIEW stats_v REFRESH DEPENDS ON current_batch_v APPEND TO stats AS SELECT cityHash64(v) % 20 as h, count() as n FROM current_batch GROUP BY h;

-- Must trigger initial refresh manually.
SYSTEM REFRESH VIEW current_batch_v;
```

تعمل السلاسل الأطول أيضًا.

لا يعمل هذا جيدًا إلا عندما يكون تنسيق التحديث مفعّلًا، أي عندما تكون العروض في قاعدة بيانات Replicated أو Shared. ومن دون التنسيق، تؤدي إعادة تشغيل الخادم إلى كسر الحلقة، مما يتطلب تنفيذ `SYSTEM REFRESH VIEW` يدويًا بعد كل إعادة تشغيل بدلًا من تنفيذه مرة واحدة فقط بعد إنشاء العروض.

<div id="refresh-settings">
  ### إعدادات التحديث
</div>

إعدادات التحديث المتاحة:

* `refresh_retries` - عدد مرات إعادة المحاولة إذا فشل استعلام التحديث بسبب استثناء. إذا فشلت جميع محاولات إعادة المحاولة، فانتقل إلى وقت التحديث المجدول التالي. تعني القيمة 0 عدم إعادة المحاولة، وتعني القيمة -1 إعادة المحاولة بلا حدود. القيمة الافتراضية: 2.
* `refresh_retry_initial_backoff_ms` - مدة التأخير قبل أول إعادة محاولة، إذا لم تكن قيمة `refresh_retries` صفراً. تتضاعف مدة التأخير مع كل إعادة محاولة لاحقة، حتى `refresh_retry_max_backoff_ms`. القيمة الافتراضية: 100 مللي ثانية.
* `refresh_retry_max_backoff_ms` - الحد الأقصى للزيادة الأسية في مدة التأخير بين محاولات التحديث. القيمة الافتراضية: 60000 مللي ثانية (دقيقة واحدة).
* `all_replicas` - في [قاعدة بيانات Replicated](/ar/reference/engines/database-engines/replicated) مع `APPEND`، يحدّد ما إذا كانت جميع النسخ المتماثلة تُحدَّث بشكل مستقل، أو ما إذا كانت نسخة متماثلة واحدة فقط تُجري التحديث في كل وقت مجدول. لا يمكن تغيير هذا الإعداد بعد إنشاء العرض. القيمة الافتراضية: `false`.

<div id="changing-refresh-parameters">
  ### تغيير معلمات التحديث
</div>

يمكن تغيير معلمات التحديث لعرض مادي قابل للتحديث موجود باستخدام [`ALTER TABLE ... MODIFY REFRESH`](/ar/reference/statements/alter/view#alter-table--modify-refresh-statement):

```sql theme={null}
ALTER TABLE [db.]name MODIFY REFRESH EVERY|AFTER ... [RANDOMIZE FOR ...] [DEPENDS ON ...] [SETTINGS ...]
```

الجدولة (`EVERY` أو `AFTER`) إلزامية: تستبدل التعليمة دائمًا *جميع* مَعلمات التحديث — الجدولة، و`RANDOMIZE FOR`، و`DEPENDS ON`، وإعدادات التحديث — بما هو محدد. وأي عنصر يُغفَل يُعاد تعيينه إلى قيمته الافتراضية (بالنسبة إلى الإعدادات) أو يُزال (بالنسبة إلى التبعيات والعشوائية).

<Note>
  * لتغيير إعدادات التحديث فقط (مثلًا `refresh_retries`)، أعِد ذكر الجدولة الحالية:

    ```sql theme={null}
    ALTER TABLE rmv MODIFY REFRESH EVERY 1 HOUR SETTINGS refresh_retries = 5;
    ```

  * لا يدعم `ALTER TABLE ... MODIFY SETTING refresh_retries = ...` العروض المادية؛ ويجب تنفيذ ذلك عبر `MODIFY REFRESH`.

  * لا تتمّ إضافة `APPEND` أو إزالته.

  * لا يمكن تغيير الإعداد `all_replicas` بعد الإنشاء.
</Note>

أمثلة:

```sql theme={null}
-- Change the schedule, drop existing settings and dependencies.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE;

-- Change the schedule and tune retry behavior.
ALTER TABLE rmv MODIFY REFRESH EVERY 30 MINUTE
SETTINGS refresh_retries = 5,
         refresh_retry_initial_backoff_ms = 500,
         refresh_retry_max_backoff_ms = 60000;

-- Keep the dependency while changing the period.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR DEPENDS ON other_rmv;

-- Drop the dependency by omitting `DEPENDS ON`.
ALTER TABLE rmv MODIFY REFRESH EVERY 6 HOUR;
```

<div id="other-operations">
  ### عمليات أخرى
</div>

تتوفر حالة جميع العروض المادية القابلة للتحديث في الجدول [`system.view_refreshes`](/ar/reference/system-tables/view_refreshes). ويعرض هذا الجدول تحديدًا تقدّم التحديث (إذا كان جاريًا)، ووقت آخر تحديث ووقت التحديث التالي، ورسالة الاستثناء إذا فشل التحديث.

لإيقاف التحديثات أو بدئها أو تشغيلها أو إلغائها يدويًا، استخدم [`SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW`](/ar/reference/statements/system#managing-refreshable-materialized-views).

للانتظار حتى يكتمل التحديث، استخدم [`SYSTEM WAIT VIEW`](/ar/reference/statements/system#wait-view). ويكون هذا مفيدًا بشكل خاص عند انتظار التحديث الأولي بعد إنشاء العرض.

<Note>
  معلومة طريفة: يُسمح لاستعلام التحديث بالقراءة من العرض الذي يجري تحديثه، مع الاطّلاع على نسخة البيانات السابقة للتحديث. وهذا يعني أنه يمكنك تنفيذ لعبة الحياة لكونواي: [https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==](https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==)
</Note>

<div id="window-view">
  ## Window View
</div>

<Info>
  هذه ميزة تجريبية وقد تتغير في الإصدارات القادمة على نحوٍ غير متوافق مع الإصدارات السابقة. لتمكين استخدام Window View واستعلام `WATCH`، استخدم الإعداد [allow\_experimental\_window\_view](/ar/reference/settings/session-settings#allow_experimental_window_view). أدخل الأمر `set allow_experimental_window_view = 1`.
</Info>

```sql theme={null}
CREATE WINDOW VIEW [IF NOT EXISTS] [db.]table_name [TO [db.]table_name] [INNER ENGINE engine] [ENGINE engine] [WATERMARK strategy] [ALLOWED_LATENESS interval_function] [POPULATE]
AS SELECT ...
GROUP BY time_window_function
[COMMENT 'comment']
```

يمكن لـ window view تجميع البيانات حسب النافذة الزمنية وإخراج النتائج عندما تصبح النافذة جاهزة للإرسال. كما تخزّن نتائج التجميع الجزئية في جدول داخلي (أو محدد) لتقليل زمن الاستجابة، ويمكنها دفع نتيجة المعالجة إلى جدول محدد أو إرسال إشعارات دفع باستخدام الاستعلام `WATCH`.

يشبه إنشاء window view إنشاء `MATERIALIZED VIEW`. وتحتاج window view إلى محرك تخزين داخلي لتخزين البيانات الوسيطة. ويمكن تحديد التخزين الداخلي باستخدام العبارة `INNER ENGINE`، وستستخدم window view المحرك `AggregatingMergeTree` بوصفه المحرك الداخلي الافتراضي.

عند إنشاء window view بدون `TO [db].[table]`، يجب تحديد `ENGINE` — أي محرك الجدول المستخدم لتخزين البيانات.

<div id="time-window-functions">
  ### دوال النافذة الزمنية
</div>

تُستخدم [دوال النافذة الزمنية](/ar/reference/functions/regular-functions/time-window-functions) للحصول على حدَّي النافذة السفلي والعلوي للسجلات. يجب استخدام window view مع إحدى دوال النافذة الزمنية.

<div id="time-attributes">
  ### سمات الوقت
</div>

يدعم Window view نمطَي **وقت المعالجة** و**وقت الحدث**.

يتيح **وقت المعالجة** لـ Window view إنتاج النتائج استنادًا إلى وقت الجهاز المحلي، ويُستخدم افتراضيًا. وهو أبسط مفهوم للوقت، لكنه لا يوفّر الحتمية. يمكن تعريف سمة وقت المعالجة من خلال تعيين `time_attr` في دالة النافذة الزمنية إلى عمود في جدول، أو باستخدام الدالة `now()`. ينشئ الاستعلام التالي Window view باستخدام وقت المعالجة.

```sql theme={null}
CREATE WINDOW VIEW wv AS SELECT count(number), tumbleStart(w_id) as w_start from date GROUP BY tumble(now(), INTERVAL '5' SECOND) as w_id
```

**وقت الحدث** هو الوقت الذي وقع فيه كل حدث على الجهاز الذي أصدره. وعادةً ما يكون هذا الوقت مضمّنًا في السجلات عند إنشائها. وتتيح معالجة وقت الحدث الحصول على نتائج متسقة حتى عند وصول الأحداث بترتيب غير متسق أو متأخر. وتدعم ميزة window view معالجة وقت الحدث باستخدام صياغة `WATERMARK`.

توفّر window view ثلاث استراتيجيات للعلامة المائية:

* `STRICTLY_ASCENDING`: تُصدر علامة مائية تساوي أكبر طابع زمني تمّت ملاحظته حتى الآن. ولا تُعد الصفوف التي تحمل طابعًا زمنيًا أصغر من أكبر طابع زمني متأخرة.
* `ASCENDING`: تُصدر علامة مائية تساوي أكبر طابع زمني تمّت ملاحظته حتى الآن ناقص 1. ولا تُعد الصفوف التي تحمل طابعًا زمنيًا مساويًا لأكبر طابع زمني أو أصغر منه متأخرة.
* `BOUNDED`: WATERMARK=INTERVAL. تُصدر علامات مائية تساوي أكبر طابع زمني تمّت ملاحظته مطروحًا منه التأخير المحدد.

الاستعلامات التالية أمثلة على إنشاء window view باستخدام `WATERMARK`:

```sql theme={null}
CREATE WINDOW VIEW wv WATERMARK=STRICTLY_ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=INTERVAL '3' SECOND AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
```

افتراضيًا، تُطلق النافذة نتيجتها عند وصول العلامة المائية، وتُسقَط العناصر التي تصل متأخرة عنها. يدعم Window View معالجة الأحداث المتأخرة من خلال ضبط `ALLOWED_LATENESS=INTERVAL`. ومثال على التعامل مع التأخر هو:

```sql theme={null}
CREATE WINDOW VIEW test.wv TO test.dst WATERMARK=ASCENDING ALLOWED_LATENESS=INTERVAL '2' SECOND AS SELECT count(a) AS count, tumbleEnd(wid) AS w_end FROM test.mt GROUP BY tumble(timestamp, INTERVAL '5' SECOND) AS wid;
```

لاحظ أن العناصر المنبعثة من إطلاق متأخر يجب التعامل معها على أنها نتائج محدَّثة لحساب سابق. وبدلًا من الإطلاق عند نهاية النوافذ، سيُطلِق window view فورًا عند وصول الحدث المتأخر. وبالتالي، سيؤدي ذلك إلى ظهور مخرجات متعددة للنافذة نفسها. يحتاج المستخدمون إلى مراعاة هذه النتائج المكررة أو إزالة تكرارها.

يمكنك تعديل استعلام `SELECT` الذي جرى تحديده في window view باستخدام تعليمة `ALTER TABLE ... MODIFY QUERY`. يجب أن تكون بنية البيانات الناتجة عن استعلام `SELECT` الجديد مماثلة لبنية استعلام `SELECT` الأصلي، سواء وُجد بند `TO [db.]name` أم لم يوجد. لاحظ أن البيانات في النافذة الحالية ستُفقد لأن الحالة الوسيطة لا يمكن إعادة استخدامها.

<div id="monitoring-new-windows">
  ### مراقبة النوافذ الجديدة
</div>

تدعم ميزة window view استعلام [WATCH](/ar/reference/statements/watch) لمراقبة التغييرات، أو يمكنك استخدام صياغة `TO` لإخراج النتائج إلى جدول.

```sql theme={null}
WATCH [db.]window_view
[EVENTS]
[LIMIT n]
[FORMAT format]
```

يمكن تحديد `LIMIT` لتعيين عدد التحديثات التي سيتم تلقيها قبل إنهاء الاستعلام. ويمكن استخدام العبارة `EVENTS` للحصول على صيغة مختصرة من استعلام `WATCH`، بحيث ستحصل بدلًا من نتيجة الاستعلام على أحدث علامة مائية للاستعلام فقط.

<div id="settings-1">
  ### الإعدادات
</div>

* `window_view_clean_interval`: فاصل تنظيف Window View بالثواني لتحرير البيانات القديمة. سيحتفظ النظام بالنوافذ التي لم تُطلق بالكامل وفقًا لوقت النظام أو إعداد `WATERMARK`، وسيُحذف ما عدا ذلك من البيانات.
* `window_view_heartbeat_interval`: فاصل نبضات الحياة بالثواني للإشارة إلى أن استعلام watch لا يزال نشطًا.
* `wait_for_window_view_fire_signal_timeout`: المهلة الزمنية لانتظار إشارة إطلاق Window View في معالجة وقت الحدث.

<div id="example">
  ### مثال
</div>

لنفترض أننا نريد حساب عدد سجلات النقرات كل 10 ثوانٍ في جدول سجلات يُسمى `data`، ويكون هيكل الجدول كما يلي:

```sql theme={null}
CREATE TABLE data ( `id` UInt64, `timestamp` DateTime) ENGINE = Memory;
```

أولًا، ننشئ window view بنافذة متعاقبة ذات interval قدره 10 ثوانٍ:

```sql theme={null}
CREATE WINDOW VIEW wv as select count(id), tumbleStart(w_id) as window_start from data group by tumble(timestamp, INTERVAL '10' SECOND) as w_id
```

ثم نستخدم الاستعلام `WATCH` للحصول على النتائج.

```sql theme={null}
WATCH wv
```

عند إدراج السجلات في الجدول `data`،

```sql theme={null}
INSERT INTO data VALUES(1,now())
```

يجب أن يعرض استعلام `WATCH` النتائج كما يلي:

```text theme={null}
┌─count(id)─┬────────window_start─┐
│         1 │ 2020-01-14 16:56:40 │
└───────────┴─────────────────────┘
```

بدلًا من ذلك، يمكننا توجيه المخرجات إلى جدول آخر باستخدام صيغة `TO`.

```sql theme={null}
CREATE WINDOW VIEW wv TO dst AS SELECT count(id), tumbleStart(w_id) as window_start FROM data GROUP BY tumble(timestamp, INTERVAL '10' SECOND) as w_id
```

يمكن العثور على أمثلة إضافية ضمن الاختبارات ذات الحالة في ClickHouse (وهي تحمل هناك الاسم `*window_view*`).

<div id="window-view-usage">
  ### استخدامات Window View
</div>

تكون Window View مفيدة في السيناريوهات التالية:

* **المراقبة**: تجميع سجلات المقاييس وحسابها بحسب الوقت، ثم إخراج النتائج إلى جدول الهدف. ويمكن أن تستخدم لوحة المعلومات جدول الهدف بوصفه الجدول المصدر.
* **التحليل**: تجميع البيانات تلقائيًا ومعالجتها مسبقًا ضمن النافذة الزمنية. وقد يكون ذلك مفيدًا عند تحليل عدد كبير من السجلات. وتُلغي المعالجة المسبقة العمليات الحسابية المتكررة عبر استعلامات متعددة وتقلل زمن استجابة الاستعلامات.

<div id="related-content">
  ## محتوى مرتبط
</div>

* مدونة: [العمل مع بيانات السلاسل الزمنية في ClickHouse](https://clickhouse.com/blog/working-with-time-series-data-and-functions-ClickHouse)
* مدونة: [بناء حل Observability باستخدام ClickHouse - الجزء 2 - التتبعات](https://clickhouse.com/blog/storing-traces-and-spans-open-telemetry-in-clickhouse)

<div id="temporary-views">
  ## عروض مؤقتة
</div>

يدعم ClickHouse **عروض مؤقتة** بالخصائص التالية (على غرار الجداول المؤقتة حيثما ينطبق ذلك):

* **بعمر الجلسة**
  لا يوجد عرض مؤقت إلا طوال مدة الجلسة الحالية. وتُحذف تلقائيًا عند انتهاء الجلسة.

* **بدون قاعدة بيانات**
  **لا يمكنك** إلحاق عرض مؤقت باسم قاعدة بيانات. فهي توجد خارج قواعد البيانات (ضمن نطاق الجلسة).

* **غير مُكرّرة / بدون ON CLUSTER**
  الكائنات المؤقتة محلية بالنسبة إلى الجلسة، و**لا يمكن** إنشاؤها باستخدام `ON CLUSTER`.

* **حلّ الأسماء**
  إذا كان لكائن مؤقت (جدول أو طريقة عرض) الاسم نفسه لكائن دائم، وأشار استعلام إلى الاسم **من دون** قاعدة بيانات، فسيُستخدم الكائن **المؤقت**.

* **كائن منطقي (بدون تخزين)**
  لا يخزّن عرض مؤقت سوى نص `SELECT` الخاص بها (وتستخدم داخليًا تخزين `View`). وهي لا تحتفظ بالبيانات ولا تقبل `INSERT`.

* **عبارة `ENGINE`**
  **لا** تحتاج إلى تحديد `ENGINE`؛ وإذا تم توفيره على هيئة `ENGINE = View`، فسيتم تجاهله أو التعامل معه باعتباره طريقة العرض المنطقية نفسها.

* **الأمان / الامتيازات**
  يتطلب إنشاء عرض مؤقت الامتياز `CREATE TEMPORARY VIEW`، والذي يُمنح ضمنيًا بواسطة `CREATE VIEW`.

* **SHOW CREATE**
  استخدم `SHOW CREATE TEMPORARY VIEW view_name;` لطباعة DDL الخاص بعرض مؤقت.

<div id="temporary-views-syntax">
  ### الصيغة
</div>

```sql theme={null}
CREATE TEMPORARY VIEW [IF NOT EXISTS] view_name AS <select_query>
```

`OR REPLACE` **غير مدعوم** للعروض المؤقتة (تماشيًا مع الجداول المؤقتة). إذا كنت بحاجة إلى “استبدال” عرض مؤقت، فاحذفها ثم أنشئها من جديد.

<div id="examples">
  ### أمثلة
</div>

أنشئ جدولًا مؤقتًا كمصدر، ثم أنشئ فوقه عرضًا مؤقتًا:

```sql theme={null}
CREATE TEMPORARY TABLE t_src (id UInt32, val String);
INSERT INTO t_src VALUES (1, 'a'), (2, 'b');

CREATE TEMPORARY VIEW tview AS
SELECT id, upper(val) AS u
FROM t_src
WHERE id <= 2;

SELECT * FROM tview ORDER BY id;
```

اعرض تعريفه (DDL):

```sql theme={null}
SHOW CREATE TEMPORARY VIEW tview;
```

احذفه:

```sql theme={null}
DROP TEMPORARY VIEW IF EXISTS tview;  -- temporary views are dropped with TEMPORARY TABLE syntax
```

<div id="temporary-views-limitations">
  ### غير المسموح به / القيود
</div>

* `CREATE OR REPLACE TEMPORARY VIEW ...` → **غير مسموح** (استخدم `DROP` + `CREATE`).
* `CREATE TEMPORARY MATERIALIZED VIEW ...` / `WINDOW VIEW` → **غير مسموح**.
* `CREATE TEMPORARY VIEW db.view AS ...` → **غير مسموح** (من دون محدِّد قاعدة بيانات).
* `CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...` → **غير مسموح** (الكائنات المؤقتة محلية على مستوى الجلسة).
* `POPULATE`, `REFRESH`, `TO [db.table]`, المحركات الداخلية، وجميع البنود الخاصة بـ MV → **لا تنطبق** على العروض المؤقتة.

<div id="temporary-views-distributed-notes">
  ### ملاحظات حول الاستعلامات الموزعة
</div>

إن **العرض** المؤقت ليس سوى تعريف؛ ولا توجد أي بيانات يمكن تمريرها. وإذا كان العرض المؤقت يشير إلى **جداول** مؤقتة (مثل `Memory`)، فيمكن إرسال بياناتها إلى الخوادم البعيدة أثناء تنفيذ الاستعلامات الموزعة، تمامًا كما هو الحال مع الجداول المؤقتة.

<div id="temporary-views-distributed-example">
  #### مثال
</div>

```sql theme={null}
-- A session-scoped, in-memory table
CREATE TEMPORARY TABLE temp_ids (id UInt64) ENGINE = Memory;

INSERT INTO temp_ids VALUES (1), (5), (42);

-- A session-scoped view over the temp table (purely logical)
CREATE TEMPORARY VIEW v_ids AS
SELECT id FROM temp_ids;

-- Replace 'test' with your cluster name.
-- GLOBAL JOIN forces ClickHouse to *ship* the small join-side (temp_ids via v_ids)
-- to every remote server that executes the left side.
SELECT count()
FROM cluster('test', system.numbers) AS n
GLOBAL ANY INNER JOIN v_ids USING (id)
WHERE n.number < 100;

```
