نقل SAP Business One من SQL Server إلى HANA: كيف تحوّل الاستعلامات والتقارير وعمليات البحث المنسّق

بقلم زين عباس, كودينوفا · آخر تحديث

الإجابة المختصرةيستخدم HANA لغة SQL بأسلوب ANSI، لذلك تحتاج معظم استعلامات SAP Business One إلى تغييرات صغيرة لكنها صارمة: ضع أسماء الأعمدة بين علامتي اقتباس (T0."CardCode")، واستبدل ISNULL بـ IFNULL، و GETDATE بـ CURRENT_TIMESTAMP، و DATEADD و DATEDIFF بـ ADD_DAYS و DAYS_BETWEEN، و CONVERT بـ TO_NVARCHAR، وعلامة + بـ || عند دمج النصوص. تتحول الاستعلامات البسيطة في دقائق. أما الإجراءات المخزنة والجداول المؤقتة و SBO_SP_TransactionNotification فيجب إعادة كتابتها بلغة SQLScript واختبارها على البيانات نفسها.

لماذا تتعطل استعلاماتك على HANA

عندما تنقل شركة نظام SAP Business One من Microsoft SQL Server إلى SAP HANA، تنتقل البيانات بسلاسة. أما SQL المخصص فلا. الاستعلامات المحفوظة، والتنبيهات، وعمليات البحث المنسّق، وأوامر تقارير Crystal، وكود SQL في الإضافات، وإجراء الإشعار بالحركات (Transaction Notification)، كلها مكتوبة بلغة T-SQL. و HANA لا يتحدث T-SQL.

معظم التغييرات صغيرة. المشكلة أنها كثيرة، وعلامة اقتباس واحدة منسية توقف الاستعلام كله. يسرد هذا الدليل التغييرات التي نجريها في أغلب الأحيان، بالترتيب الذي نراجعها به.

1. ضع كل اسم عمود بين علامتي اقتباس

هذا هو التغيير الذي يوقع الجميع أولًا. يحوّل HANA الأسماء غير المقتبسة إلى أحرف كبيرة. وأسماء أعمدة SAP Business One بأحرف مختلطة: CardCode و DocTotal و U_MyField. لذلك يصبح T0.CardCode هو T0.CARDCODE، ولا يجده HANA.

الحل هو علامتا اقتباس مزدوجتان حول الاسم:

SELECT T0."DocNum", T0."CardCode", T0."DocTotal"
FROM "OINV" T0
WHERE T0."CANCELED" = 'N'

تنتج عن ذلك قاعدتان:

  • علامتا الاقتباس المزدوجتان تعنيان معرّفًا. وعلامتا الاقتباس المفردتان تعنيان نصًا. في SQL Server كان يمكنك أحيانًا أن تفلت بكتابة "N". أما في HANA فإن "N" عمود اسمه N، فيفشل الاستعلام.
  • الأسماء المستعارة تُقتبس أيضًا إذا أردت الحفاظ على حالة أحرفها: AS "Customer Name".

2. استبدل الدوال الشائعة

هذه دوال T-SQL التي نراها في كل قاعدة بيانات SAP B1 تقريبًا، ومقابلاتها في HANA.

SQL Server ‏(T-SQL)SAP HANAملاحظة
ISNULL(T0.Comments, '')IFNULL(T0."Comments", '')COALESCE تعمل على الاثنين
GETDATE()CURRENT_TIMESTAMPاستخدم CURRENT_DATE للتاريخ فقط
DATEADD(day, 30, T0.DocDate)ADD_DAYS(T0."DocDate", 30)وكذلك ADD_MONTHS و ADD_YEARS
DATEDIFF(day, T0.DocDueDate, GETDATE())DAYS_BETWEEN(T0."DocDueDate", CURRENT_DATE)ترتيب المعاملات نفسه: من، إلى
CONVERT(varchar, T0.DocDate, 103)TO_NVARCHAR(T0."DocDate", 'DD/MM/YYYY')نص التنسيق يحل محل رقم النمط
T0.CardCode + ' - ' + T0.CardNameT0."CardCode" || ' - ' || T0."CardName"علامة + تجمع الأرقام فقط في HANA
SELECT TOP 10 ...SELECT TOP 10 ... أو LIMIT 10TOP تعمل في HANA
#Temp / SELECT INTOمتغير جدول أو CREATE LOCAL TEMPORARY TABLEيحتاج SQLScript
SELECT GETDATE()SELECT CURRENT_TIMESTAMP FROM DUMMYيحتاج HANA إلى جملة FROM
RIGHT(REPLICATE('0', 8) + T0.CardCode, 8)LPAD(T0."CardCode", 8, '0')الحشو بالأصفار؛ وRPAD يحشو من اليمين. وREPLICATE('-', 10) وحدها تصبح LPAD('', 10, '-')

مثال كامل قبل التحويل وبعده، من استعلام نموذجي للفواتير المتأخرة:

-- SQL Server
SELECT TOP 50
  T0.DocNum,
  T0.CardCode + ' - ' + T0.CardName AS Customer,
  CONVERT(varchar, T0.DocDueDate, 103) AS DueDate,
  DATEDIFF(day, T0.DocDueDate, GETDATE()) AS DaysLate,
  ISNULL(T0.Comments, '') AS Comments
FROM OINV T0
WHERE T0.DocStatus = 'O'
  AND T0.DocDueDate < DATEADD(day, -30, GETDATE())
ORDER BY DaysLate DESC
-- SAP HANA
SELECT TOP 50
  T0."DocNum",
  T0."CardCode" || ' - ' || T0."CardName" AS "Customer",
  TO_NVARCHAR(T0."DocDueDate", 'DD/MM/YYYY') AS "DueDate",
  DAYS_BETWEEN(T0."DocDueDate", CURRENT_DATE) AS "DaysLate",
  IFNULL(T0."Comments", '') AS "Comments"
FROM "OINV" T0
WHERE T0."DocStatus" = 'O'
  AND T0."DocDueDate" < ADD_DAYS(CURRENT_DATE, -30)
ORDER BY "DaysLate" DESC

يمكنك لصق كود T-SQL الخاص بك في محوّل SQL إلى HANA المجاني لدينا للحصول على مسودة أولى لهذه التغييرات.

3. أبقِ معاملات B1 كما هي

الاستعلامات المحفوظة التي تطلب مدخلات من المستخدم تستخدم [%0] و [%1] وهكذا. يستبدلها SAP Business One قبل وصول SQL إلى قاعدة البيانات، فتبقى كما هي على HANA:

SELECT T0."DocNum", T0."DocDate", T0."DocTotal"
FROM "ORDR" T0
WHERE T0."DocDate" >= [%0]
  AND T0."DocDate" <= [%1]

وعمليات البحث المنسّق تعمل بالطريقة نفسها. المراجع مثل $[$38.1.0] أو $[ORDR."CardCode"] يملؤها العميل. ويجب تحويل SQL المحيط بها فقط. انتبه للاقتباس داخل مرجع الحقل: يتبع الجدول والعمود قواعد HANA نفسها.

4. الإجراءات المخزنة والجداول المؤقتة تحتاج SQLScript

هنا يتوقف البحث والاستبدال عن العمل. تستخدم إجراءات T-SQL متغيرات @variables وجداول #temp و SELECT INTO وحلقات WHILE والمؤشرات. أما إجراءات HANA فتُكتب بلغة SQLScript، ولها شكل مختلف:

  • تُعرَّف المتغيرات بـ DECLARE وتُقرأ ببادئة النقطتين: :lv_total.
  • تذهب النتائج الوسيطة عادةً إلى متغيرات جداول (lt_open = SELECT ...;)، لا إلى جداول مؤقتة.
  • يوجد في HANA جداول مؤقتة محلية (تُسمّى أيضًا بالعلامة #)، لكن يجب إنشاؤها أولًا بأعمدة صريحة. لا يوجد SELECT INTO #temp.
  • تنتهي كل جملة بفاصلة منقوطة.
-- SQLScript: open order value per customer
CREATE PROCEDURE "KN_OPEN_ORDERS" (IN p_from DATE)
LANGUAGE SQLSCRIPT AS
BEGIN
  lt_orders = SELECT "CardCode", "DocTotal"
              FROM "ORDR"
              WHERE "DocStatus" = 'O' AND "DocDate" >= :p_from;

  SELECT "CardCode", SUM("DocTotal") AS "OpenValue"
  FROM :lt_orders
  GROUP BY "CardCode";
END;

سكربتات T-SQL التي تشغّلها يدويًا وفي أعلاها DECLARE @x ليس لها مقابل مباشر في HANA خارج الإجراءات. ضعها داخل كتلة مجهولة DO BEGIN ... END;، التي تشغّل SQLScript مرة واحدة دون إنشاء إجراء:

-- T-SQL
DECLARE @from DATE = '2026-01-01';
SELECT CardCode, SUM(DocTotal) FROM ORDR WHERE DocDate >= @from GROUP BY CardCode;

-- SQLScript anonymous block
DO BEGIN
  DECLARE lv_from DATE := '2026-01-01';
  SELECT "CardCode", SUM("DocTotal") AS "Total"
  FROM "ORDR"
  WHERE "DocDate" >= :lv_from
  GROUP BY "CardCode";
END;

تدعم الكتل المجهولة الجمل نفسها التي يدعمها جسم الإجراء، لكن لا يمكن استخدامها داخل إجراء أو دالة.

الإجراءات المعتمدة كثيرًا على المؤشرات تستحق إعادة تصميمها كاستعلامات قائمة على المجموعات ما دمت تعمل عليها. فـ HANA يكافئ ذلك.

5. SBO_SP_TransactionNotification

على HANA، يأتي إجراء الإشعار بالحركات في SAP Business One كإجراء SQLScript. يستقبل المدخلات نفسها كما في السابق (نوع الكائن، ونوع الحركة، وأعمدة المفاتيح وقيمها)، ويعيد رمز الخطأ والرسالة في النهاية عبر SELECT ... FROM DUMMY. للاطلاع على قواعد كاملة جنبًا إلى جنب، راجع أمثلة TransactionNotification لـ SQL Server و HANA.

يجب إعادة كتابة كتل التحقق المكتوبة بـ T-SQL داخل هذا الإجراء. تبدو الكتلة النموذجية هكذا:

IF :object_type = '17' AND (:transaction_type = 'A' OR :transaction_type = 'U') THEN
  SELECT COUNT(*) INTO cnt
  FROM "ORDR"
  WHERE "DocEntry" = :list_of_cols_val_tab_del
    AND IFNULL("NumAtCard", '') = '';
  IF :cnt > 0 THEN
    error := 1;
    error_message := 'Customer reference is required';
  END IF;
END IF;

عرّف cnt في أعلى الإجراء. اجعل كل قاعدة صغيرة، واختبر الإضافة والتحديث كلًّا على حدة. عندما تمنع قاعدة مستندًا يرحّله تكامل ما، يفشل استدعاء DI API أو Service Layer ويعود نص رسالتك ضمن نص الخطأ؛ وقراءة ذلك مشروحة في رموز أخطاء DI API. خطأ صياغة واحد هنا يمنع كل مستند في الشركة، لذا انشره خارج ساعات العمل.

6. أوامر تقارير Crystal Reports

تقارير Crystal المبنية على SQL Server تستخدم غالبًا أمرًا (Command) (جملة SQL ملصقة) أو تستدعي إجراءً مخزنًا. وكلاهما يحمل T-SQL. لكل تقرير:

  1. حوّل SQL الأمر أو الإجراء إلى صياغة HANA.
  2. وجّه التقرير إلى مصدر بيانات HANA عبر Database > Set Datasource Location، باستخدام اتصال HANA وبيانات الدخول ومخطط الشركة.
  3. تحقق من أن حقول المعاملات ما زالت مرتبطة بمعاملات الأمر.
  4. اعرض معاينته في عميل SAP Business One على HANA وقارن الناتج بنسخة SQL Server.

التقارير المبنية على جداول عادية دون أوامر تحتاج عادةً الخطوة 2 فقط.

7. منهجية اختبار تكشف الأخطاء

الاستعلام المحوَّل الذي يعمل ليس هو نفسه الاستعلام المحوَّل الصحيح. دمج النصوص بعلامة + هو الفخ الكلاسيكي: في HANA قد يفشل، أو قد يحاول جمع القيم كأرقام. وتنسيقات التاريخ فخ آخر.

  1. الجرد أولًا. صدّر قائمة الاستعلامات المحفوظة (OUQR)، وعمليات البحث المنسّق (CSHS)، والتنبيهات، وتقارير Crystal، وإجراءات المستخدم، وإجراء الإشعار بالحركات. سجّل من يستخدم كلًّا منها. كثير منها لن يكون مستخدمًا ويمكن حذفه.
  2. حوّل على دفعات حسب النوع: الاستعلامات البسيطة، ثم البحث المنسّق، ثم التقارير، ثم الإجراءات.
  3. شغّل النسختين على نسخة من البيانات نفسها، SQL Server و HANA.
  4. قارن عدد الصفوف والإجماليات. إذا اختلفت مجاميع DocTotal أو الأعداد، فاعرف السبب قبل المتابعة.
  5. اختبر الحالات الحدّية. القيم الفارغة (NULL)، والمستندات الملغاة، والعملات الأجنبية، والمستندات التي تمتد عبر نهاية السنة.
  6. دع المستخدمين الرئيسيين يعتمدون التقارير التي يستخدمونها يوميًا.

كنقطة انطلاق، تحتوي مكتبة استعلامات SAP B1 لدينا على استعلامات شائعة مكتوبة بصياغتي T-SQL و HANA، ويسرّع محوّل SQL إلى HANA المرور الأول على استعلاماتك.

ما الذي تتوقعه

تستغرق الاستعلامات المحفوظة البسيطة دقائق لكل منها. وعمليات البحث المنسّق مشابهة. التقارير التي تحتوي على أوامر تستغرق وقتًا أطول بسبب الاختبار. أما الإجراءات المخزنة وإجراء الإشعار بالحركات فتستغرق الوقت الأطول وتحمل المخاطر الأكبر، لذا خطّط لها أولًا، لا أخيرًا.

إذا كنت تخطط للانتقال إلى HANA وتريد تحويل استعلاماتك وتقاريرك وعمليات التحقق واختبارها، تواصل مع كودينوفا مع قائمة بما لديك.

المصادر

خدمات ذات صلة

الأسئلة الشائعة

أسئلة شائعة

هل تعمل استعلامات SAP Business One على HANA دون تغيير؟

الأبسط منها فقط. أي استعلام يستخدم أسماء أعمدة بأحرف مختلطة دون اقتباس، أو ISNULL أو GETDATE أو DATEADD أو CONVERT أو علامة + للنصوص، سيفشل أو يعيد نتائج خاطئة على HANA. والاستعلامات المبنية بمولّد الاستعلامات تحتاج عادةً تغييرات أقل.

لماذا يقول HANA إن اسم العمود غير صالح مع أن العمود موجود؟

يحوّل HANA المعرّفات غير المقتبسة إلى أحرف كبيرة. أعمدة SAP Business One بأحرف مختلطة مثل CardCode، لذلك يجب كتابة T0."CardCode" بعلامتي اقتباس مزدوجتين. أسماء الجداول مثل OINV بأحرف كبيرة أصلًا، لكن اقتباسها أيضًا عادة آمنة.

هل تبقى معاملات [%0] في الاستعلامات المحفوظة صالحة على HANA؟

نعم. يعالج SAP Business One المعاملات بأسلوب [%0] و [%1] قبل وصول SQL إلى قاعدة البيانات، فتبقيها كما هي. يجب تغيير SQL المحيط بها فقط.

هل توجد أداة تحوّل T-SQL إلى HANA SQL تلقائيًا؟

نشرت SAP أداة Query Migration Tool على GitHub تحوّل جزءًا كبيرًا من T-SQL، لكن المشروع مؤرشف وتقول SAP إنه يجب مراجعة الناتج. ويتعامل محوّل SQL إلى HANA المجاني لدينا مع أنماط SAP B1 الشائعة. وفي الحالتين يجب أن يختبر شخص كل استعلام محوَّل.

ما أصعب جزء في الترحيل؟

الإجراءات المخزنة والجداول المؤقتة والمؤشرات (Cursors) و SBO_SP_TransactionNotification. هذه تحتاج إعادة كتابة صحيحة بلغة SQLScript، لا مجرد بحث واستبدال.

جاهز للبدء؟

أخبرنا بما تحتاجه. ستحصل على إجابة تقنية واضحة ونطاق عمل محدد وسعر ثابت، عادةً خلال 24 ساعة.