> ## 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.

> تعرّف على كيفية ربط pg_clickhouse بـ ClickHouse وإجراء استعلامات على مجموعة بيانات تجريبية لسيارات الأجرة في مدينة نيويورك.

# دليل pg_clickhouse التعليمي

<div id="overview">
  ## نظرة عامة
</div>

يعتمد هذا الدليل التعليمي على \[دليل ClickHouse التعليمي]، لكنه يُجري جميع استعلاماته عبر
pg\_clickhouse.

<div id="start-clickhouse">
  ## ابدأ ClickHouse
</div>

أولًا، أنشئ قاعدة بيانات في ClickHouse إذا لم تكن لديك قاعدة بيانات بالفعل. ومن أسرع الطرق
للبدء استخدام Docker image:

```sh theme={null}
docker run -d --network host --name clickhouse -p 8123:8123 -p9000:9000 --ulimit nofile=262144:262144 clickhouse
docker exec -it clickhouse clickhouse-client
```

<div id="create-a-table">
  ## إنشاء جدول
</div>

لنستفد من \[دليل ClickHouse التعليمي] لإنشاء قاعدة بيانات بسيطة باستخدام مجموعة بيانات سيارات الأجرة
في مدينة نيويورك:

```sql theme={null}
CREATE DATABASE taxi;
CREATE TABLE taxi.trips
(
    trip_id UInt32,
    vendor_id Enum8(
        '1'      =  1, '2'      =  2, '3'      =  3, '4'      =  4,
        'CMT'    =  5, 'VTS'    =  6, 'DDS'    =  7, 'B02512' = 10,
        'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14,
        ''       = 15
    ),
    pickup_date Date,
    pickup_datetime DateTime,
    dropoff_date Date,
    dropoff_datetime DateTime,
    store_and_fwd_flag UInt8,
    rate_code_id UInt8,
    pickup_longitude Float64,
    pickup_latitude Float64,
    dropoff_longitude Float64,
    dropoff_latitude Float64,
    passenger_count UInt8,
    trip_distance Float64,
    fare_amount Decimal(10, 2),
    extra Decimal(10, 2),
    mta_tax Decimal(10, 2),
    tip_amount Decimal(10, 2),
    tolls_amount Decimal(10, 2),
    ehail_fee Decimal(10, 2),
    improvement_surcharge Decimal(10, 2),
    total_amount Decimal(10, 2),
    payment_type Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),
    trip_type UInt8,
    pickup FixedString(25),
    dropoff FixedString(25),
    cab_type Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),
    pickup_nyct2010_gid Int8,
    pickup_ctlabel Float32,
    pickup_borocode Int8,
    pickup_ct2010 String,
    pickup_boroct2010 String,
    pickup_cdeligibil String,
    pickup_ntacode FixedString(4),
    pickup_ntaname String,
    pickup_puma UInt16,
    dropoff_nyct2010_gid UInt8,
    dropoff_ctlabel Float32,
    dropoff_borocode UInt8,
    dropoff_ct2010 String,
    dropoff_boroct2010 String,
    dropoff_cdeligibil String,
    dropoff_ntacode FixedString(4),
    dropoff_ntaname String,
    dropoff_puma UInt16
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(pickup_date)
ORDER BY pickup_datetime;
```

<div id="add-the-data-set">
  ## أضِف مجموعة البيانات
</div>

ثم استورد البيانات:

```sql theme={null}
INSERT INTO taxi.trips
SELECT * FROM s3(
    'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/trips_{1..2}.gz',
    'TabSeparatedWithNames', "
    trip_id UInt32,
    vendor_id Enum8(
        '1'      =  1, '2'      =  2, '3'      =  3, '4'      =  4,
        'CMT'    =  5, 'VTS'    =  6, 'DDS'    =  7, 'B02512' = 10,
        'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14,
        ''       = 15
    ),
    pickup_date Date,
    pickup_datetime DateTime,
    dropoff_date Date,
    dropoff_datetime DateTime,
    store_and_fwd_flag UInt8,
    rate_code_id UInt8,
    pickup_longitude Float64,
    pickup_latitude Float64,
    dropoff_longitude Float64,
    dropoff_latitude Float64,
    passenger_count UInt8,
    trip_distance Float64,
    fare_amount Decimal(10, 2),
    extra Decimal(10, 2),
    mta_tax Decimal(10, 2),
    tip_amount Decimal(10, 2),
    tolls_amount Decimal(10, 2),
    ehail_fee Decimal(10, 2),
    improvement_surcharge Decimal(10, 2),
    total_amount Decimal(10, 2),
    payment_type Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),
    trip_type UInt8,
    pickup FixedString(25),
    dropoff FixedString(25),
    cab_type Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),
    pickup_nyct2010_gid Int8,
    pickup_ctlabel Float32,
    pickup_borocode Int8,
    pickup_ct2010 String,
    pickup_boroct2010 String,
    pickup_cdeligibil String,
    pickup_ntacode FixedString(4),
    pickup_ntaname String,
    pickup_puma UInt16,
    dropoff_nyct2010_gid UInt8,
    dropoff_ctlabel Float32,
    dropoff_borocode UInt8,
    dropoff_ct2010 String,
    dropoff_boroct2010 String,
    dropoff_cdeligibil String,
    dropoff_ntacode FixedString(4),
    dropoff_ntaname String,
    dropoff_puma UInt16
") SETTINGS input_format_try_infer_datetimes = 0
```

تأكد من أنه يمكننا إجراء استعلام عليه، ثم الخروج من البرنامج العميل:

```sql theme={null}
SELECT count() FROM taxi.trips;
quit
```

<div id="install-pg_clickhouse">
  ### تثبيت pg\_clickhouse
</div>

أنشئ pg\_clickhouse وثبّته من [PGXN] أو [GitHub]. أو شغّل حاوية
Docker باستخدام \[image pg\_clickhouse]، التي تضيف ببساطة
pg\_clickhouse إلى \[image Postgres في Docker]:

```sh theme={null}
docker run -d --network host --name pg_clickhouse -e POSTGRES_PASSWORD=my_pass \
       -d ghcr.io/clickhouse/pg_clickhouse:18
```

<div id="connect-pg_clickhouse">
  ### ربط pg\_clickhouse
</div>

الآن، اتصل بـ Postgres:

```sh theme={null}
docker exec -it pg_clickhouse psql -U postgres
```

ثم أنشئ pg\_clickhouse:

```sql theme={null}
CREATE EXTENSION pg_clickhouse;
```

أنشئ خادمًا خارجيًا باستخدام اسم المضيف والمنفذ واسم قاعدة بيانات ClickHouse الخاصة بك.

```sql theme={null}
CREATE SERVER taxi_srv FOREIGN DATA WRAPPER clickhouse_fdw
       OPTIONS(driver 'binary', host 'localhost', dbname 'taxi');
```

هنا اخترنا استخدام برنامج التشغيل الثنائي، الذي يستخدم بروتوكول ClickHouse
الثنائي. ويمكنك أيضًا استخدام برنامج التشغيل "http"، الذي يستخدم واجهة HTTP.

بعد ذلك، اربط مستخدم PostgreSQL بمستخدم ClickHouse. وأبسط طريقة للقيام بذلك
هي تعيين مستخدم PostgreSQL الحالي إلى مستخدم بعيد على الخادم
الخارجي:

```sql theme={null}
CREATE USER MAPPING FOR CURRENT_USER SERVER taxi_srv
       OPTIONS (user 'default');
```

يمكنك أيضًا تحديد خيار `password`.

الآن، أضِف جدول سيارات الأجرة؛ فقط استورد جميع الجداول من قاعدة بيانات
ClickHouse البعيدة إلى مخطط Postgres:

```sql theme={null}
CREATE SCHEMA taxi;
IMPORT FOREIGN SCHEMA taxi FROM SERVER taxi_srv INTO taxi;
```

والآن يُفترض أن يكون الجدول قد تم استيراده: في [psql]، استخدم `\det+` لعرضه:

```pgsql theme={null}
taxi=# \det+ taxi.*
                                       List of foreign tables
 Schema | Table |  Server  |                        FDW options                        | Description
--------+-------+----------+-----------------------------------------------------------+-------------
 taxi   | trips | taxi_srv | (database 'taxi', table_name 'trips', engine 'MergeTree') | [null]
(1 row)
```

تم بنجاح! استخدم `\d` لإظهار جميع الأعمدة:

```pgsql theme={null}
taxi=# \d taxi.trips
                                   Foreign table "taxi.trips"
        Column         |           Type           | Collation | Nullable | Default | FDW options
-----------------------+--------------------------+-----------+----------+---------+-------------
 trip_id               | bigint                   |           | not null |         |
 vendor_id             | text                     |           | not null |         |
 pickup_date           | date                     |           | not null |         |
 pickup_datetime       | timestamp with time zone |           | not null |         |
 dropoff_date          | date                     |           | not null |         |
 dropoff_datetime      | timestamp with time zone |           | not null |         |
 store_and_fwd_flag    | smallint                 |           | not null |         |
 rate_code_id          | smallint                 |           | not null |         |
 pickup_longitude      | double precision         |           | not null |         |
 pickup_latitude       | double precision         |           | not null |         |
 dropoff_longitude     | double precision         |           | not null |         |
 dropoff_latitude      | double precision         |           | not null |         |
 passenger_count       | smallint                 |           | not null |         |
 trip_distance         | double precision         |           | not null |         |
 fare_amount           | numeric(10,2)            |           | not null |         |
 extra                 | numeric(10,2)            |           | not null |         |
 mta_tax               | numeric(10,2)            |           | not null |         |
 tip_amount            | numeric(10,2)            |           | not null |         |
 tolls_amount          | numeric(10,2)            |           | not null |         |
 ehail_fee             | numeric(10,2)            |           | not null |         |
 improvement_surcharge | numeric(10,2)            |           | not null |         |
 total_amount          | numeric(10,2)            |           | not null |         |
 payment_type          | text                     |           | not null |         |
 trip_type             | smallint                 |           | not null |         |
 pickup                | character varying(25)    |           | not null |         |
 dropoff               | character varying(25)    |           | not null |         |
 cab_type              | text                     |           | not null |         |
 pickup_nyct2010_gid   | smallint                 |           | not null |         |
 pickup_ctlabel        | real                     |           | not null |         |
 pickup_borocode       | smallint                 |           | not null |         |
 pickup_ct2010         | text                     |           | not null |         |
 pickup_boroct2010     | text                     |           | not null |         |
 pickup_cdeligibil     | text                     |           | not null |         |
 pickup_ntacode        | character varying(4)     |           | not null |         |
 pickup_ntaname        | text                     |           | not null |         |
 pickup_puma           | integer                  |           | not null |         |
 dropoff_nyct2010_gid  | smallint                 |           | not null |         |
 dropoff_ctlabel       | real                     |           | not null |         |
 dropoff_borocode      | smallint                 |           | not null |         |
 dropoff_ct2010        | text                     |           | not null |         |
 dropoff_boroct2010    | text                     |           | not null |         |
 dropoff_cdeligibil    | text                     |           | not null |         |
 dropoff_ntacode       | character varying(4)     |           | not null |         |
 dropoff_ntaname       | text                     |           | not null |         |
 dropoff_puma          | integer                  |           | not null |         |
Server: taxi_srv
FDW options: (database 'taxi', table_name 'trips', engine 'MergeTree')
```

الآن نفّذ استعلامًا على الجدول:

```pgsql theme={null}
 SELECT count(*) FROM taxi.trips;
   count
 ---------
  1999657
 (1 row)
```

لاحظ مدى سرعة تنفيذ الاستعلام. يقوم pg\_clickhouse بتمرير الاستعلام بالكامل،
بما في ذلك دالة التجميع `COUNT()`، لذا يُنفَّذ على ClickHouse ولا
يُعيد إلى Postgres إلا صفًا واحدًا. استخدم [EXPLAIN] لمعاينة ذلك:

```pgsql theme={null}
 EXPLAIN select count(*) from taxi.trips;
                    QUERY PLAN
 -------------------------------------------------
  Foreign Scan  (cost=1.00..-0.90 rows=1 width=8)
    Relations: Aggregate on (trips)
 (2 rows)
```

لاحظ أن "Foreign Scan" يظهر عند جذر الخطة، ما يعني أن
الاستعلام بأكمله دُفع إلى ClickHouse.

<div id="analyze-the-data">
  ## حلّل البيانات
</div>

شغّل بعض الاستعلامات لتحليل البيانات. اطّلع على الأمثلة التالية أو جرّب
استعلام SQL خاصًا بك.

* احسب متوسط مبلغ الإكرامية:

  ```sql theme={null}
  taxi=# \timing
  Timing is on.
  taxi=# SELECT round(avg(tip_amount), 2) FROM taxi.trips;
   round
  -------
    1.68
  (1 row)

  Time: 9.438 ms
  ```

* احسب متوسط التكلفة بناءً على عدد الركاب:

  ```pgsql theme={null}
  taxi=# SELECT
          passenger_count,
          avg(total_amount)::NUMERIC(10, 2) AS average_total_amount
      FROM taxi.trips
      GROUP BY passenger_count;
   passenger_count | average_total_amount
  -----------------+----------------------
                 0 |                22.68
                 1 |                15.96
                 2 |                17.14
                 3 |                16.75
                 4 |                17.32
                 5 |                16.34
                 6 |                16.03
                 7 |                59.79
                 8 |                36.40
                 9 |                 9.79
  (10 rows)

  Time: 27.266 ms
  ```

* احسب العدد اليومي لمرات الالتقاط في كل حي:

  ```pgsql theme={null}
  taxi=# SELECT
      pickup_date,
      pickup_ntaname,
      SUM(1) AS number_of_trips
  FROM taxi.trips
  GROUP BY pickup_date, pickup_ntaname
  ORDER BY pickup_date ASC LIMIT 10;
   pickup_date |         pickup_ntaname         | number_of_trips
  -------------+--------------------------------+-----------------
   2015-07-01  | Williamsburg                   |               1
   2015-07-01  | park-cemetery-etc-Queens       |               6
   2015-07-01  | Maspeth                        |               1
   2015-07-01  | Stuyvesant Town-Cooper Village |              44
   2015-07-01  | Rego Park                      |               1
   2015-07-01  | Greenpoint                     |               7
   2015-07-01  | Highbridge                     |               1
   2015-07-01  | Briarwood-Jamaica Hills        |               3
   2015-07-01  | Airport                        |             550
   2015-07-01  | East Harlem North              |              32
  (10 rows)

  Time: 30.978 ms
  ```

* احسب مدة كل رحلة بالدقائق، ثم جمّع النتائج حسب
  مدة الرحلة:

  ```pgsql theme={null}
  taxi=# SELECT
      avg(tip_amount) AS avg_tip,
      avg(fare_amount) AS avg_fare,
      avg(passenger_count) AS avg_passenger,
      count(*) AS count,
      round((date_part('epoch', dropoff_datetime) - date_part('epoch', pickup_datetime)) / 60) as trip_minutes
  FROM taxi.trips
  WHERE round((date_part('epoch', dropoff_datetime) - date_part('epoch', pickup_datetime)) / 60) > 0
  GROUP BY trip_minutes
  ORDER BY trip_minutes DESC
  LIMIT 5;
        avg_tip      |     avg_fare     |  avg_passenger   | count | trip_minutes
  -------------------+------------------+------------------+-------+--------------
                1.96 |                8 |                1 |     1 |        27512
                   0 |               12 |                2 |     1 |        27500
   0.562727272727273 | 17.4545454545455 | 2.45454545454545 |    11 |         1440
   0.716564885496183 | 14.2786259541985 | 1.94656488549618 |   131 |         1439
    1.00945205479452 | 12.8787671232877 | 1.98630136986301 |   146 |         1438
  (5 rows)

  Time: 45.477 ms
  ```

* اعرض عدد مرات الالتقاط في كل حيّ، مقسّمًا حسب ساعات اليوم:

  ```pgsql theme={null}
  taxi=# SELECT
      pickup_ntaname,
      date_part('hour', pickup_datetime) as pickup_hour,
      SUM(1) AS pickups
  FROM taxi.trips
  WHERE pickup_ntaname != ''
  GROUP BY pickup_ntaname, pickup_hour
  ORDER BY pickup_ntaname, date_part('hour', pickup_datetime)
  LIMIT 5;
   pickup_ntaname | pickup_hour | pickups
  ----------------+-------------+---------
   Airport        |           0 |    3509
   Airport        |           1 |    1184
   Airport        |           2 |     401
   Airport        |           3 |     152
   Airport        |           4 |     213
  (5 rows)

  Time: 36.895 ms
  ```

* اضبط المنطقة الزمنية المعروضة على توقيت نيويورك، ثم استرجع الرحلات إلى مطاري LaGuardia أو JFK:

  ```pgsql theme={null}
  taxi=# SET timezone = 'America/New_York';
  SET
  taxi=# SELECT
      pickup_datetime,
      dropoff_datetime,
      total_amount,
      pickup_nyct2010_gid,
      dropoff_nyct2010_gid,
      CASE
          WHEN dropoff_nyct2010_gid = 138 THEN 'LGA'
          WHEN dropoff_nyct2010_gid = 132 THEN 'JFK'
      END AS airport_code,
      EXTRACT(YEAR FROM pickup_datetime) AS year,
      EXTRACT(DAY FROM pickup_datetime) AS day,
      EXTRACT(HOUR FROM pickup_datetime) AS hour
  FROM taxi.trips
  WHERE dropoff_nyct2010_gid IN (132, 138)
  ORDER BY pickup_datetime
  LIMIT 5;
      pickup_datetime     |    dropoff_datetime    | total_amount | pickup_nyct2010_gid | dropoff_nyct2010_gid | airport_code | year | day | hour
  ------------------------+------------------------+--------------+---------------------+----------------------+--------------+------+-----+------
   2015-06-30 20:04:14-04 | 2015-06-30 20:15:29-04 |        13.30 |                 -34 |                  132 | JFK          | 2015 |  30 |   20
   2015-06-30 20:09:42-04 | 2015-06-30 20:12:55-04 |         6.80 |                  50 |                  138 | LGA          | 2015 |  30 |   20
   2015-06-30 20:23:04-04 | 2015-06-30 20:24:39-04 |         4.80 |                -125 |                  132 | JFK          | 2015 |  30 |   20
   2015-06-30 20:27:51-04 | 2015-06-30 20:39:02-04 |        14.72 |                -101 |                  138 | LGA          | 2015 |  30 |   20
   2015-06-30 20:32:03-04 | 2015-06-30 20:55:39-04 |        39.34 |                  48 |                  138 | LGA          | 2015 |  30 |   20
  (5 rows)

  Time: 17.450 ms
  ```

<div id="create-a-dictionary">
  ## إنشاء قاموس
</div>

أنشئ قاموسًا مرتبطًا بجدول في خدمة ClickHouse الخاصة بك. يعتمد كلٌّ من
الجدول والقاموس على ملف CSV يحتوي على صف لكل
حيّ في مدينة نيويورك.

تُطابَق الأحياء مع أسماء الأحياء الإدارية الخمسة في مدينة نيويورك
(Bronx وBrooklyn وManhattan وQueens وStaten Island)،
بالإضافة إلى مطار Newark ‏(EWR).

فيما يلي مقتطف من ملف CSV الذي تستخدمه بصيغة جدول. يربط
العمود `LocationID` في الملف بالعمودين `pickup_nyct2010_gid` و
`dropoff_nyct2010_gid` في جدول الرحلات لديك:

| LocationID | Borough       | Zone                    | service\_zone |
| ---------: | ------------- | ----------------------- | ------------- |
|          1 | EWR           | Newark Airport          | EWR           |
|          2 | Queens        | Jamaica Bay             | Boro Zone     |
|          3 | Bronx         | Allerton/Pelham Gardens | Boro Zone     |
|          4 | Manhattan     | Alphabet City           | Yellow Zone   |
|          5 | Staten Island | Arden Heights           | Boro Zone     |

1. بينما لا تزال في Postgres، استخدم الدالة `clickhouse_raw_query` لإنشاء
   \[قاموس] في ClickHouse باسم `taxi_zone_dictionary` وملء
   القاموس من ملف CSV في S3:

   ```sql theme={null}
   SELECT clickhouse_raw_query($$
       CREATE DICTIONARY taxi.taxi_zone_dictionary (
           LocationID Int64 DEFAULT 0,
           Borough String,
           zone String,
           service_zone String
       )
       PRIMARY KEY LocationID
       SOURCE(HTTP(URL 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/taxi_zone_lookup.csv' FORMAT 'CSVWithNames'))
       LIFETIME(MIN 0 MAX 0)
       LAYOUT(HASHED_ARRAY())
   $$, 'host=localhost dbname=taxi');
   ```

<Note>
  يؤدي تعيين `LIFETIME` إلى 0 إلى تعطيل التحديثات التلقائية لتجنّب
  نقل بيانات غير ضروري إلى S3 bucket الخاص بنا. في حالات أخرى،
  قد تحتاج إلى تهيئته بشكل مختلف. لمزيد من التفاصيل، راجع [تحديث بيانات القاموس باستخدام
  LIFETIME](/ar/reference/statements/create/dictionary/lifetime).
</Note>

2. الآن استورده:

```sql theme={null}
    IMPORT FOREIGN SCHEMA taxi LIMIT TO (taxi_zone_dictionary)
    FROM SERVER taxi_srv INTO taxi;
```

3. تأكَّد من أنه يمكننا الاستعلام عنه:

```pgsql theme={null}
    taxi=# SELECT * FROM taxi.taxi_zone_dictionary limit 3;
     LocationID |  Borough  |                     Zone                      | service_zone
    ------------+-----------+-----------------------------------------------+--------------
             77 | Brooklyn  | East New York/Pennsylvania Avenue             | Boro Zone
            106 | Brooklyn  | Gowanus                                       | Boro Zone
            103 | Manhattan | Governor's Island/Ellis Island/Liberty Island | Yellow Zone
    (3 rows)
```

4. ممتاز. الآن استخدم الدالة `dictGet` لاسترجاع
   اسم حي إداري في استعلام. يجمع هذا الاستعلام عدد
   رحلات سيارات الأجرة لكل حي إداري التي تنتهي في أحد مطاري LaGuardia أو JFK:

```pgsql theme={null}
    taxi=# SELECT
            count(1) AS total,
            COALESCE(NULLIF(dictGet(
                'taxi.taxi_zone_dictionary', 'Borough',
                toUInt64(pickup_nyct2010_gid)
            ), ''), 'Unknown') AS borough_name
        FROM taxi.trips
        WHERE dropoff_nyct2010_gid = 132 OR dropoff_nyct2010_gid = 138
        GROUP BY borough_name
        ORDER BY total DESC;
     total | borough_name
    -------+---------------
     23683 | Unknown
      7053 | Manhattan
      6828 | Brooklyn
      4458 | Queens
      2670 | Bronx
       554 | Staten Island
        53 | EWR
    (7 rows)

    Time: 66.245 ms
```

يحسب هذا الاستعلام إجمالي عدد رحلات سيارات الأجرة لكل حي إداري التي تنتهي في
مطارَي LaGuardia أو JFK. لاحظ أن هناك عددًا كبيرًا من الرحلات التي
لا يكون فيها الحي الذي انطلقت منه الرحلة معروفًا.

<div id="perform-a-join">
  ## تنفيذ عملية join
</div>

اكتب بعض الاستعلامات التي تربط `taxi_zone_dictionary` بجدول `trips`
لديك.

1. ابدأ بـ `JOIN` بسيط يعمل بطريقة مشابهة لاستعلام
   المطار السابق أعلاه:

   ```pgsql theme={null}
   taxi=# SELECT
       count(1) AS total,
       "Borough"
   FROM taxi.trips
   JOIN taxi.taxi_zone_dictionary
     ON trips.pickup_nyct2010_gid = toUInt64(taxi.taxi_zone_dictionary."LocationID")
   WHERE pickup_nyct2010_gid > 0
     AND dropoff_nyct2010_gid IN (132, 138)
   GROUP BY "Borough"
   ORDER BY total DESC;
    total | borough_name
   -------+---------------
     7053 | Manhattan
     6828 | Brooklyn
     4458 | Queens
     2670 | Bronx
      554 | Staten Island
       53 | EWR
   (6 rows)

   Time: 48.449 ms
   ```

<Note>
  لاحظ أن ناتج استعلام `JOIN` أعلاه مطابق لناتج استعلام `dictGet`
  أعلاه (باستثناء أن قيم `Unknown` غير متضمّنة). في الخلفية،
  يستدعي ClickHouse فعليًا الدالة `dictGet` من أجل
  القاموس `taxi_zone_dictionary`، لكن صياغة `JOIN` أكثر
  ألفةً لمطوري SQL.
</Note>

```pgsql theme={null}
    taxi=# explain SELECT
            count(1) AS total,
            "Borough"
        FROM taxi.trips
        JOIN taxi.taxi_zone_dictionary
          ON trips.pickup_nyct2010_gid = toUInt64(taxi.taxi_zone_dictionary."LocationID")
        WHERE pickup_nyct2010_gid > 0
          AND dropoff_nyct2010_gid IN (132, 138)
        GROUP BY "Borough"
        ORDER BY total DESC;
                                  QUERY PLAN
    -----------------------------------------------------------------------
     Foreign Scan  (cost=1.00..5.10 rows=1000 width=40)
       Relations: Aggregate on ((trips) INNER JOIN (taxi_zone_dictionary))
    (2 rows)
    Time: 2.012 ms
```

2. يُرجع هذا الاستعلام صفوفًا لأعلى 1000 رحلة من حيث قيمة
   الإكرامية، ثم يُجري INNER JOIN لكل صف مع القاموس:

   ```sql theme={null}
   taxi=# SELECT *
   FROM taxi.trips
   JOIN taxi.taxi_zone_dictionary
       ON trips.dropoff_nyct2010_gid = taxi.taxi_zone_dictionary."LocationID"
   WHERE tip_amount > 0
   ORDER BY tip_amount DESC
   LIMIT 1000;
   ```

<Note>
  بوجه عام، نتجنب استخدام `SELECT *` في PostgreSQL وClickHouse. يجب
  ألا تسترجع إلا الأعمدة التي تحتاج إليها فعليًا.
</Note>

[ClickHouse tutorial]: /get-started/quickstarts/tutorial "البرنامج التعليمي المتقدم لـ ClickHouse"

[psql]: https://www.postgresql.org/docs/current/app-psql.html "تطبيقات عميل PostgreSQL: psql"

[EXPLAIN]: https://www.postgresql.org/docs/current/sql-explain.html "أوامر SQL: EXPLAIN"

[dictionary]: /reference/statements/create/dictionary

[PGXN]: https://pgxn.org/dist/pg_clickhouse "pg_clickhouse على PGXN"

[GitHub]: https://github.com/ClickHouse/pg_clickhouse/releases "إصدارات pg_clickhouse على GitHub"

[pg_clickhouse image]: https://github.com/ClickHouse/pg_clickhouse/pkgs/container/pg_clickhouse "صورة OCI لـ pg_clickhouse على GitHub"

[Postgres image]: https://hub.docker.com/_/postgres "صورة OCI لـ Postgres على Docker Hub"

[Refreshing dictionary data using LIFETIME]: /reference/statements/create/dictionary/lifetime "مستندات ClickHouse: تحديث بيانات القاموس باستخدام LIFETIME"
