طريقة بسيطة لإنشاء شكل "قياسي" لخادم SQL للتعبير؟

StackOverflow https://stackoverflow.com/questions/1206514

  •  05-07-2019
  •  | 
  •  

سؤال

يتعلق هذا بالأعمدة المحسوبة والقيود الافتراضية (وربما تعبيرات أخرى) في SQL Server 2005 (أو أعلاه). كلاهما يستخدمون تعبيرًا تعسفيًا لتوليد قيمة ، على سبيل المثال (year+1) بالنسبة لعمود محسوب يمثل "العام المقبل" (من الواضح أن هذا مثال بسيط وغبي).

ما أحاول القيام به: أريد أن أكون قادرًا على تحديد ما إذا كان العمود المحسوب (أو القيد الافتراضي) في بعض الجدول يتطابق مع التعريف المقصود ، حيث يتم تعريف الأخير في مخطط تم إنشاؤه بواسطة البرامج والذي تم استخدامه لإنشاء الجدول. يمكنني الحصول على تعريف عمود محسوب باستخدام sp_helptext, وتعريف القيد الافتراضي من sys.default_constraints عرض الكتالوج.

ما أواجه مشكلة في: التعبيرات التي أعود إليها من المصادر المذكورة أعلاه هي في شكل طبيعي/قياسي لا يتطابق مع النموذج المستخدم لإنشاء العمود/القيد. في المثال أعلاه ، تقوم SQL بتطبيع التعبير إلى ([year]+(1)). لذلك ، لن تحدد مقارنة السلسلة البسيطة بين هذا النموذج والشكل الأصلي بشكل موثوق ما إذا كانت هي نفسها.

الحلول التي فكرت بها بالفعل:

  • قم بإنشاء التعبيرات الأصلية حتى تتطابق مع نموذج SQL. هذا يتطلب معرفة القواعد التي تستخدمها SQL لإنشاء شكلها ، والتي لم يتم توثيقها ، لذلك ليس حلاً رائعًا.
  • تحليل كلا النماذج في asts وقارن تلك. أنا بالفعل AST للشكل الأصلي ، لكن ليس لدي محلل ، وأفضل عدم كتابة واحدة.
  • قم بإنشاء جدول مؤقت وأضف عمودًا محسوبًا باستخدام التعبير الأصلي ، ثم اقرأ التعبير الطبيعي مرة أخرى. سيكون هذا موثوقًا به إلى حد ما ، لكنه يشعر بالقلق ، لأنه من الناحية النظرية يجب أن تكون هذه المقارنة عملية للقراءة فقط.

هل يمكن لأي شخص التفكير في خيار جيد آخر للتعامل مع هذا؟ آمل أن يعرف شخص ما بعض أداة تصحيح الأخطاء/التشخيص التي ستبصق تعبير الإدخال في الشكل الطبيعي/القياسي.

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

المحلول

سأضيف أيضًا ، أن "تطبيع" التعبير في بعض الأحيان لا يضيف فقط قوسين ، ولكنه يغير أيضًا بعض التعبيرات بطريقة مختلفة تمامًا!

على سبيل المثال في MS SQL 2008 Express ، قمت بإنشاء افتراضي مع التعبير التالي:

year(getdate()) + 1

لكن خادم SQL يغيره ليكون

(datepart(year,getdate())+(1))

لذلك ، لا أعتقد أن أي نوع من القواعد أو التعبيرات العادية ستحل مشكلتك بنسبة 100 ٪ من الحالات ، لذلك أوصيك بدمج عدة طرق

1) أولاً وقبل كل شيء ، أعتقد أنه في حالتك هناك عدد محدود من القيود النموذجية ، والتي عادة ما تكون موجودة في معظم قواعد البيانات. كقاعدة عامة ، هناك getDate () ، والتعبيرات الرقمية المستمرة (0) ، (1). يمكنك الحصول على جدول لتلك القيود النموذجية التي ستساعدك على مطابقة التعبيرات المتوقعة والحقيقية.

2) ثم يمكنك تجربة قاعدة بسيطة للغاية لتضمين جميع أسماء الحقول في [] قوسين وجميع الثوابت وعمليات الرياضيات في () ، لذلك سيكون لديك سنة + 1 تحولت إلى ([السنة] + (1)). أفترض أن هذا يمكن القيام به مع تعبيرات منتظمة.

3) بالنسبة لجميع الحالات التي لم تتمكن فيها من مقارنة النتائج المتوقعة والفعلية باستخدام الطريقة الأولى أو الثانية ، ستفعل ما اقترحته - إنشاء جدول مؤقت ومقارنة النتائج.


تحرير 04.Aug:

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

أما بالنسبة للقيود الافتراضية للأعمدة ، ونهج إنشاء/إسقاط الافتراضات بشكل ديناميكي من أجل الحصول على نموذجها الطبيعي ، إليك رمز C# بسيط باستخدام Microsoft.sqlserver.management.smo مكتبة. سأقترح إنشاء TEST_TABLE مع الأعمدة inttest int و varchartest varchar (1) و datetimetest dateTime وما إلى ذلك - أي فقط عمود واحد لكل نوع. في هذه الحالة ، ستقوم بإنشاء/إسقاط الإعدادات الافتراضية ولكن لن تضطر إلى إنشاء جدول وأعمدة إسقاط وهذا سيزيد من الأداء.

سيتابع رمز C# (قم بتضمين استخدام Microsoft.sqlserver.management.smo ؛)

        Server server = new Server("localhost\\SQLEXPRESS");
        Database db = server.Databases["test"];
        Table t = db.Tables["test_defaults"];
        //here should be some logic to select column name depending on default data type
        //for example for DateTime defaults we will use "DateTimeTest" column
        Column c = t.Columns["DateTimeTest"];

        //clean up previous results if they exist
        DefaultConstraint constr = c.DefaultConstraint;
        if (constr != null) constr.Drop();

        //create new constraint
        constr = c.AddDefaultConstraint();
        constr.Text = "getdate()";
        constr.Create();
        //after refresh we will have a new text
        constr.Refresh();
        string result = constr.Text;

        //drop it if we don't need it
        constr.Drop();

نصائح أخرى

أشعر أنه يجب أن يكون هناك إجابة من خلال الاتصال بـ DAC (بحيث يمكنك الاستعلام عن جداول النظام) ، لكن لا يمكنني في الواقع معرفة كيفية عمل الوظيفة "Object_definition".

قد يكون هذا سؤالًا لشخص مثل Kalen Delaney ، لمعرفة ما إذا كانت هناك وظيفة عامة يتم تحليل هذه الأشياء.

روب

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

إذا لم يكن هذا ما تبحث عنه (إلى جانب أنه غير نظيف تمامًا) ، فأخبرني ويمكنني ضبطه حسب الحاجة.

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