سؤال

وأواجه استعلام SQL (MSSQLSERVER) حيث يمكنني إضافة أعمدة إلى resultset وباستخدام subselects:

SELECT P.name, 
(select count(*) from cars C where C.type = 'sports') AS sportscars,
(select count(*) from cars C where C.type = 'family') AS familycars,
(select count(*) from cars C where C.type = 'business') AS businesscars
FROM people P
WHERE P.id = 1;

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

في المثال أعلاه، كل سجل في "الشعب" الجدول يحتوي أيضا على ثلاثة أعمدة إضافية: "wantsSportscar"، "wantsFamilycar" و "wantsBusinesscar". الآن ما أريد القيام به هو القيام فقط subselect كل عمود إضافي إذا المختلفة "يريد ....." تم تعيين حقل في الجدول الناس إلى "true". وبعبارة أخرى، أريد فقط أن تفعل subselect الأول إذا تم تعيين P.wantsSportscar إلى true لذلك شخص معين. ينبغي أن subselects الثاني والثالث يعمل بطريقة مشابهة.

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

من المهم أنه إذا كان الشخص ليست مهتمة في نوع معين من السيارات، أن العمود لهذا النوع لن يتم تضمين في resultset النهائي. مثال للتأكد من هذا واضح:

إذا شخص ويريد الرياضية وfamilycar، فإن النتيجة تتضمن الأعمدة "اسم"، "السيارات الرياضية" و "familycars".

إذا شخص B يريد businesscar، والنتيجة ستشمل الأعمدة "اسم" و "businesscar".

ولقد تم في محاولة لاستخدام تركيبات مختلفة مع IF، حالة والمشرقية البيانات، ولكن حتى الآن أنا لم تكن قادرة على الحصول على الحل الصحيح نحويا. لا أحد يعرف إذا كان ذلك ممكنا حتى؟ لاحظ أنه سيتم تخزين الاستعلام في إجراء مخزن.

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

المحلول

في قضيتك، وهناك تخطيطات العمود 8 ممكن وللقيام بذلك، وسوف تحتاج استعلامات منفصلة 8 (أو بناء الاستعلام بشكل حيوي).

وليس من الممكن لتغيير تخطيط resultset وفي استعلام واحد.

وبدلا من ذلك، قد تصميم الاستعلام الخاص بك كما يلي:

SELECT  P.name, 
        CASE WHEN wantssport = 1 THEN (select count(*) from cars C where C.type = 'sports') ELSE NULL END AS sportscars,
        CASE WHEN wantsfamily = 1 THEN (select count(*) from cars C where C.type = 'family') ELSE NULL END AS familycars,
        CASE WHEN wantsbusiness = 1 THEN (select count(*) from cars C where C.type = 'business') ELSE NULL END AS businesscars
FROM    people P
WHERE   P.id = 1

والتي سيتم تحديد NULL في العمود المناسب إذا كان الشخص لا يريدون ذلك، وتحليل هذه لNULL على جانب العميل.

لاحظ أن النموذج العلائقي يجيب على الاستفسارات من حيث relations.

في قضيتك، والعلاقة هي على النحو التالي: "يحتاج هذا الشخص هي satisifed مع هذا العدد الكبير من السيارات الرياضية، وهذا العديد من السيارات التجارية والعديد من هذه السيارات العائلية"

ونموذج علائقي يجيب دائما على هذا السؤال المحدد مع وجود علاقة الرباعية.

وانها لا تغفل أي من أعضاء العلاقة: بدلا من ذلك، فإنه يضع مجرد لهم NULL الذي هو وسيلة لSQL لإظهار أن عضوا في علاقة لم يتم تعريف، ينطبق أو ذات مغزى

.

نصائح أخرى

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

وكما قلت، أنا غير مألوف مع MS SQL Server ولكن انا التخمين سيكون هناك طريقة لتنفيذ SQL ديناميكي، وفي هذه الحالة يجب عليك البحث أنه منذ ذلك يجب أن تسمح لك لبناء استعلام أكثر مرونة.

وأنت قد تكون قادرة على فعل ما تريد عن طريق اختيار أولا القيم كصفوف منفصلة في جدول مؤقت، ثم القيام PIVOT على هذا الجدول (تحويل الصفوف إلى أعمدة).

<اقتباس فقرة>   

من المهم أنه إذا كان الشخص ليس   المهتمين في نوع معين من السيارات،   أن العمود لهذا النوع سوف لا   تدرج في resultset النهائي. ل   مثال للتأكد من هذا واضح:

وأنت لن تكون قادرة على القيام بذلك في SQL عادي. أقترح عليك أن مجرد جعل هذا NULL عمود أو ZERO.

إذا كنت تريد الاستعلام أن يكون ديناميكيا توسيع عندما تضاف السيارات الجديدة، ثم التمحور يمكن أن تساعدك بعض الشيء.

وهناك ثلاثة أسس كنت تريد أن تتعلم لجعل هذا العمل سهلا. الأول هو تطبيع البيانات، والثاني هو GROUP BY، والثالث هو PIVOT.

أولا، تطبيع البيانات. التصميم الخاص بك من الجدول الناس ليست في النموذج العادي الأول. الأعمدة "wantsports"، "wantfamily"، "wantbusiness" هي في الواقع مجموعة التكرار، على الرغم من أنها قد لا تبدو وكأنها واحدة. إذا يمكنك تعديل تصميم الجدول، سوف تجد أنه من المفيد لإنشاء جدول ثالث، يتيح نسميها "peoplewant"، مع اثنين من الأعمدة الرئيسية، personid وcartype. يمكنني الخوض في التفاصيل حول لماذا هذا التصميم سوف تكون أكثر مرونة وقوية إذا أردت، ولكن انا ذاهب لتخطي ذلك في الوقت الحالي.

في لGROUP BY. وهذا يسمح لك لإنتاج نتيجة لذلك تلخص كل مجموعة في صف واحد من النتيجة.

SELECT 
    p.name, 
    c.type, 
    c.count(*) as carcount
FROM people p, 
   INNER JOIN peoplewant pw ON p.id = pw.personid 
   INNER JOIN cars c on pw.cartype = c.type
WHERE
   p.id = 1
GROUP BY 
   p.name,
   c.type

وهذا (مجربة) الاستعلام يعطيك النتيجة التي تريدها، إلا أن نتيجة لديه صف منفصل لكل نوع السيارة يريد الشخص.

وأخيرا، PIVOT. الأداة PIVOT في نظم إدارة قواعد البيانات الخاصة بك يسمح لك لتحويل هذه النتيجة الى شكل حيث كان هناك واحد فقط صف الشخص، وهناك عمود منفصل لكل من يريد cartypes من قبل هذا الشخص. أنا لم تستخدم PIVOT نفسي، ولذا فإنني سأترك شخص آخر تحرير هذا الرد لتوفير مثال باستخدام PIVOT.

إذا كنت تستخدم نفس الأسلوب لاسترداد البيانات لعدة أشخاص في حملة واحدة، أن نضع في اعتبارنا أن تظهر على عمود لكل أراد النوع الذي يريد أي شخص، وسوف تظهر أصفار في النتيجة PIVOT للأشخاص الذين لا يريدون نوع السيارة التي هي في الأعمدة نتيجة.

وجاء فقط عبر هذه الوظيفة عن طريق جوجل للبحث، لذلك أنا أدرك أنني تأخرت إلى هذا الحزب من قبل بعض الشيء، ولكن .. متأكد من أن هذا هو حقا <م> ممكن القيام به ... إلا أنني لن أقترح فعلا القيام به على هذا النحو لانها تعتبر عادة ما يكون شيئا سيئا جدا (TM).

والحيوي SQL هو جوابك.

وقبل أن أقول كيف نفعل ذلك، أريد أن أستهل هذا مع، الديناميكية SQL هو شيء خطير جدا، إذا كنت لا التعقيم المدخلات الخاصة بك من التطبيق.

وهكذا، لذلك، والمضي قدما بحذر:

declare @sqlToExecute nvarchar(max);
declare @includeSportsCars bit;
declare @includeFamilyCars bit;
declare @includeBusinessCars bit;

set @includeBusinessCars = 1
set @includeFamilyCars = 1
set @includeSportsCars  = 1

set @sqlToExecute = 'SELECT P.name '

if @includeSportsCars = 1 
    set @sqlToExecute = @sqlToExecute + '(select count(*) from cars C where C.type = ''sports'') AS sportscars, ';
if @includeFamilyCars = 1
    set @sqlToExecute = @sqlToExecute + '(select count(*) from cars C where C.type = ''family'') AS familycars, ';
if @includeBusinessCars = 1
    set @sqlToExecute = @sqlToExecute + '(select count(*) from cars C where C.type = ''business'') AS businesscars '

set @sqlToExecute = @sqlToExecute + ' FROM people P WHERE P.id = 1;';

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