سؤال

لدي عبارة تحدد السلسلة الفرعية لـ Charindex كما يلي:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE 
CHARINDEX('ABC', StringField) > 5

عندما أقوم بتشغيل العبارة أعلاه في استعلام تحديد، يتم إرجاع النتائج على ما يرام.عندما أقوم بتشغيل العبارة أعلاه في طريقة عرض مفهرسة مرتبطة بالمخطط، أحصل على هذا الخطأ:

Invalid length parameter passed to the LEFT or SUBSTRING function

لحل المشكلة سأكتب دالة للحصول على الحد الأقصى لـ CharIndex و0 لإزالة احتمالات القيمة السالبة.ولكن هل يعرف أحد لماذا لا تقوم جملة المكان بتصفية عبارة التحديد؟

هل كانت مفيدة؟

المحلول

لأن ترتيب العمليات خلف الكواليس في الاستعلام غير مضمون.

أعتقد أنه إذا قمت بفحص خطة التنفيذ، فسوف ترى أنها تقوم بإجراء كلا الفحصين بالتوازي - وذلك لأنه لا يمكن لأي من العمليتين استخدام فهرس!

يحتاج SQL إلى تحميل كل صف من هذا الحقل في الذاكرة على أي حال، لذلك يقوم بمعالجته لكلا المعيارين في نفس الوقت.

يمكنك المحاولة WITH (MAXDOP(1)) كتلميح للاستعلام لمعرفة ما إذا كان ذلك يمنع المشكلة من الظهور، أو يمكنك إجراء تحديد فرعي لفرض أمر التنفيذ:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
FROM (
      SELECT Stringfield 
      FROM Table 
      WHERE CHARINDEX('ABC', StringField) > 5
      ) as [X]

لقد واجهت مشكلة مماثلة مرة واحدة عندما كنت أتحقق لمعرفة ما إذا كان الحقل رقميًا أم لا PATINDEX وكان أحد الأعمدة في وجهة نظري هو تحويل هذا إلى int - لقد حصلت على أخطاء في التحويل لأن المحرك كان يقوم بتحويل كل صف لأن المرشحات الخاصة بي لم تكن قابلة لـ SARGable.

نصائح أخرى

يعد هذا حلاً قبيحًا ولكن ربما يمكنك القيام بشيء مثل هذا:

DECLARE @x TABLE(StringField VARCHAR(32));

INSERT @x SELECT 'ABC'
UNION ALL SELECT 'A'
UNION ALL SELECT 'AAAAAAAABC';

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

SELECT SUBSTRING(StringField,
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 1 END,
    CHARINDEX('ABC', StringField) - 
    CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 0 END)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;

كلا العائد:

---
AAA

لكنني أظن أنه سيتم السماح بهذا الأخير من وجهة نظرك.إنه أمر قبيح ولكن لسوء الحظ ما لم تقم بتفريغ البيانات التي تمت تصفيتها إلى جدول #temp أولاً (أو حاول معرفة ما إذا كان MAXDOP يزيل المشكلة بشكل موثوق) لن يكون لديك الكثير من التحكم في ترتيب المعالجة.

هناك فكرة أخرى تتمثل في محاولة وضع عمود محسوب في الجدول (لكنني لست متأكدًا من أن ذلك سيساعد إذا كنت تحاول إنشاء طريقة عرض مفهرسة - فقد تظل هناك تعقيدات).أو لاستخدام فهرس تمت تصفيته مع هذا التعبير، بدلاً من طريقة العرض المفهرسة.قد يكون هناك العديد من "الحلول" إذا كنا نعرف الغرض من العرض المفهرس وإصدار SQL Server الذي تستخدمه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top