الانتقال إلى المحتوى الرئيسي
يمثل هذا النوع union من أنواع بيانات أخرى. ويعني النوع Variant(T1, T2, ..., TN) أن كل صف من هذا النوع يحتوي على قيمة من النوع T1 أو T2 أو … أو TN، أو لا يحتوي على أيٍّ منها (القيمة NULL). لا يهم ترتيب الأنواع المتداخلة: Variant(T1, T2) = Variant(T2, T1). يمكن أن تكون الأنواع المتداخلة أي أنواع باستثناء Nullable(…) و LowCardinality(Nullable(…)) و Variant(…).
لا يُنصح باستخدام أنواع متشابهة كبدائل (على سبيل المثال، أنواع رقمية مختلفة مثل Variant(UInt32, Int64) أو أنواع تاريخ مختلفة مثل Variant(Date, DateTime))، لأن التعامل مع قيم من هذه الأنواع قد يؤدي إلى التباس. افتراضيًا، سيؤدي إنشاء نوع Variant من هذا النوع إلى حدوث استثناء، لكن يمكن تمكينه باستخدام الإعداد allow_suspicious_variant_types

إنشاء نوع Variant

استخدام النوع Variant في تعريف عمود الجدول:
باستخدام CAST مع الأعمدة العادية:
استخدام الدالتين if/multiIf عندما لا تكون للوسيطات نوعٌ مشترك (يجب تفعيل الإعداد use_variant_as_common_type لاستخدامهما):
استخدام الدالتين ‘array/map’ إذا لم يكن لعناصر array أو لقيم map نوعٌ مشترك (يجب أن يكون الإعداد use_variant_as_common_type مُمكّنًا لهذا الغرض):

قراءة أنواع Variant المتداخلة كأعمدة فرعية

يدعم النوع Variant قراءة نوع متداخل واحد من عمود Variant باستخدام اسم النوع كعمود فرعي. لذلك، إذا كان لديك العمود variant Variant(T1, T2, T3)، فيمكنك قراءة عمود فرعي من النوع T2 باستخدام الصياغة variant.T2. وسيكون نوع هذا العمود الفرعي Nullable(T2) إذا كان T2 يمكن أن يوجد داخل Nullable، وإلا فسيكون T2. وسيكون هذا العمود الفرعي بنفس حجم عمود Variant الأصلي، وسيحتوي على قيم NULL (أو قيم فارغة إذا تعذر وجود T2 داخل Nullable) في جميع الصفوف التي لا يكون فيها عمود Variant الأصلي من النوع T2. يمكن أيضًا قراءة الأعمدة الفرعية لـ Variant باستخدام الدالة variantElement(variant_column, type_name). أمثلة:
لمعرفة نوع Variant المُخزَّن في كل صف، يمكن استخدام الدالة variantType(variant_column). تُرجع هذه الدالة القيمة Enum التي تحتوي على اسم نوع Variant لكل صف (أو 'None' إذا كانت قيمة الصف NULL). مثال:

التحويل بين عمود من نوع Variant والأعمدة الأخرى

هناك 4 عمليات تحويل ممكنة يمكن إجراؤها لعمود من النوع Variant.

تحويل عمود String إلى عمود Variant

يتم التحويل من String إلى Variant عبر تحليل قيمة من النوع Variant انطلاقًا من القيمة النصية:
لتعطيل التحليل أثناء التحويل من String إلى Variant، يمكنك إيقاف الإعداد cast_string_to_dynamic_use_inference:

تحويل عمود عادي إلى عمود Variant

يمكن تحويل عمود عادي من النوع T إلى عمود Variant يحتوي على هذا النوع:
ملاحظة: تتم دائمًا عملية التحويل من النوع String عبر التحليل، وإذا كنت بحاجة إلى تحويل عمود String إلى النوع الفرعي String ضمن Variant من دون تحليل، فيمكنك القيام بما يلي:

تحويل عمود Variant إلى عمود عادي

يمكن تحويل عمود Variant إلى عمود عادي. في هذه الحالة، ستُحوَّل جميع قيم Variant المتداخلة إلى النوع الهدف:

تحويل Variant إلى Variant آخر

يمكن تحويل عمود Variant إلى عمود Variant آخر، ولكن فقط إذا كان عمود Variant الوجهة يتضمن جميع الأنواع المتداخلة الموجودة في Variant الأصلي:

قراءة النوع Variant من البيانات

تدعم جميع التنسيقات النصية (TSV وCSV وCustomSeparated وValues وJSONEachRow وغيرها) قراءة النوع Variant. وأثناء تحليل البيانات، يحاول ClickHouse إدراج القيمة في النوع الفرعي الأنسب ضمن Variant. مثال:

مقارنة قيم النوع Variant

لا يمكن مقارنة القيم من النوع Variant إلا بقيم من النوع Variant نفسه. بشكل افتراضي، تستخدم عوامل المقارنة التنفيذ الافتراضي لـ Variant، حيث تُطبَّق المقارنة على كل نوع فرعي على حدة. ويمكن تعطيل ذلك باستخدام الإعداد use_variant_default_implementation_for_comparisons = 0 لاستخدام قواعد المقارنة الأصلية لـ Variant الموضحة أدناه. ملاحظة: يستخدم ORDER BY دائمًا المقارنة الأصلية. قواعد المقارنة الأصلية لـ Variant: تُعرَّف نتيجة العامل < للقيمتين v1 ذات النوع الأساسي T1 وv2 ذات النوع الأساسي T2 من النوع Variant(..., T1, ... T2, ...) كما يلي:
  • إذا كان T1 = T2 = T، فستكون النتيجة v1.T < v2.T (أي ستتم مقارنة القيم الأساسية).
  • إذا كان T1 != T2، فستكون النتيجة T1 < T2 (أي ستتم مقارنة أسماء الأنواع).
أمثلة:
إذا كنت بحاجة إلى العثور على الصف ذي قيمة Variant محددة، يمكنك القيام بأحد الإجراءات التالية:
  • حوّل القيمة إلى نوع Variant المقابل:
  • قارن العمود الفرعي Variant بالنوع المطلوب:
قد يكون من المفيد أحيانًا إجراء فحص إضافي لنوع Variant، لأن الأعمدة الفرعية ذات الأنواع المعقدة مثل Array/Map/Tuple لا يمكن أن تكون ضمن Nullable، وستأخذ قيمًا افتراضية بدلًا من NULL في الصفوف ذات الأنواع المختلفة:
ملاحظة: تُعَدّ قيم Variant ذات الأنواع الرقمية المختلفة Variants مختلفة، ولا تُقارَن ببعضها بعضًا؛ بل تُقارَن أسماء أنواعها بدلًا من ذلك. مثال:
ملاحظة: افتراضيًا، لا يُسمح باستخدام النوع Variant في مفاتيح GROUP BY/ORDER BY. وإذا أردت استخدامه، فضع في اعتبارك قاعدة المقارنة الخاصة به وفعّل الإعدادين allow_suspicious_types_in_group_by/allow_suspicious_types_in_order_by.

دوال JSONExtract مع النوع Variant

تدعم جميع دوال JSONExtract* النوع Variant:

الدوال ذات الوسائط من نوع Variant

تدعم معظم الدوال في ClickHouse تلقائيًا الوسائط من النوع Variant من خلال التنفيذ الافتراضي لـ Variant. بدءًا من الإصدار 26.1، عندما تستقبل دالة لا تتعامل صراحةً مع أنواع Variant عمودًا من نوع Variant، فإن ClickHouse:
  1. يستخرج كل نوع فرعي من عمود Variant
  2. ينفّذ الدالة بشكل منفصل لكل نوع فرعي
  3. يدمج النتائج على النحو المناسب استنادًا إلى أنواع النتائج
يتيح لك ذلك استخدام الدوال العادية مع أعمدة Variant من دون الحاجة إلى معالجة خاصة. مثال:
يُطبَّق عامل المقارنة تلقائيًا على كل نوع ضمن Variant على حدة، مما يتيح التصفية على أعمدة Variant. سلوك نوع النتيجة: يعتمد نوع النتيجة على ما تعيده الدالة لكل نوع ضمن Variant:
  • أنواع نتائج مختلفة: Variant(T1, T2, ...)
  • عدم توافق الأنواع: NULL للأنواع غير المتوافقة ضمن Variant
معالجة الأخطاء: عندما يتعذر على دالة معالجة نوع فرعي، لا تُلتقط إلا الأخطاء المرتبطة بالأنواع (ILLEGAL_TYPE_OF_ARGUMENT, TYPE_MISMATCH, CANNOT_CONVERT_TYPE, NO_COMMON_TYPE)، وتكون النتيجة NULL لتلك الصفوف. أما الأخطاء الأخرى، مثل القسمة على صفر أو نفاد الذاكرة، فتُثار كالمعتاد لتجنّب إخفاء المشكلات الحقيقية بصمت.

سلوك عدم تطابق النوع

يتحكم الإعداد variant_throw_on_type_mismatch بما يحدث عند تطبيق دالة على عمود Variant وكان النوع الفعلي المخزَّن في أحد الصفوف غير متوافق مع الدالة:
  • true (الافتراضي) — إثارة استثناء (ILLEGAL_TYPE_OF_ARGUMENT) عند أول صف غير متوافق.
  • false — إرجاع NULL للصفوف غير المتوافقة مع الاحتفاظ بالنتيجة للصفوف المتوافقة.
مثال:
آخر تعديل في ٢٥ يونيو ٢٠٢٦