سؤال

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

إنني أتطلع إلى كتابة استعلام للعثور على الكائنات التي تطابق مجموعة معينة من العلامات.لنفترض أن لدي البيانات التالية (بتنسيق [object] -> [tags]*)

apple -> fruit red food
banana -> fruit yellow food
cheese -> yellow food
firetruck -> vehicle red

إذا كنت أرغب في مطابقة (الأحمر)، فيجب أن أحصل على تفاحة وعربة إطفاء.إذا كنت أرغب في مطابقة (الفاكهة، الطعام) فيجب أن أحصل على (التفاح، الموز).

كيف أكتب استعلام SQL أفعل ما أريد؟

@ جيريمي روتين،

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

ثانيًا، مشكلتي هي أنني بحاجة إلى الحصول على جميع الكائنات التي تطابق جميع العلامات.استبدال OR الخاص بك بـ AND مثل ذلك:

SELECT object WHERE tag = 'fruit' AND tag = 'food';

لا يعطي أي نتائج عند التشغيل.

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

المحلول

منح:

  • جدول الكائنات (معرف المفتاح الأساسي)
  • جدول علامات الكائنات (مفاتيح خارجية objectId، tagid)
  • جدول العلامات (معرف المفتاح الأساسي)

    SELECT distinct o.*
      from object o join objecttags ot on o.Id = ot.objectid
                    join tags t on ot.tagid = t.id
     where t.Name = 'fruit' or t.name = 'food';
    

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

إذا كنت ترغب حقًا في القيام بذلك وفي هذه الحالة، فستحتاج إلى group by, ، و أ having count = <number of ors> في استفسارك على سبيل المثال.

  SELECT distinct o.name, count(*) as count
    from object o join objecttags ot on o.Id = ot.objectid
                  join tags t on ot.tagid = t.id
   where t.Name = 'fruit' or t.name = 'food'
group by o.name
  having count = 2;

نصائح أخرى

يا إلهي ربما أخطأت في تفسير تعليقك الأصلي.

أسهل طريقة للقيام بذلك في SQL هي أن يكون لديك ثلاثة جداول:

1) Tags ( tag_id, name )
2) Objects (whatever that is)
3) Object_Tag( tag_id, object_id )

وبعد ذلك، يمكنك طرح أي سؤال تريده بشأن البيانات بسرعة وسهولة وكفاءة (شريطة أن تقوم بالفهرسة بشكل مناسب).إذا كنت تريد أن تكون مميزًا، فيمكنك السماح بالعلامات متعددة الكلمات أيضًا (هناك طريقة أنيقة، وطريقة أقل أناقة، على ما أعتقد).

أفترض أن هذا هو ما لديك، لذلك سيعمل SQL أدناه:

الطريقة الحرفية:

    SELECT obj 
      FROM object
     WHERE EXISTS( SELECT * 
                     FROM tags 
                    WHERE tag = 'fruit' 
                      AND oid = object_id ) 
       AND EXISTS( SELECT * 
                     FROM tags 
                    WHERE tag = 'Apple'
                      AND oid = object_id )

هناك أيضًا طرق أخرى يمكنك القيام بها، مثل:

SELECT oid
  FROM tags
 WHERE tag = 'Apple'
INTERSECT
SELECT oid
  FROM tags
 WHERE tag = 'Fruit'

@ كايل:يجب أن يكون استعلامك أشبه بما يلي:

SELECT object WHERE tag IN ('fruit', 'food');

كان استعلامك يبحث عن صفوف حيث كانت العلامة عبارة عن فاكهة وطعام، وهو أمر مستحيل رؤيته لأن الحقل يمكن أن يحتوي على قيمة واحدة فقط، وليس كلاهما في نفس الوقت.

اجمع بين اقتراح Steve M. واقتراح Jeremy، وستحصل على سجل واحد يحتوي على ما تبحث عنه:

select object
from tblTags
where tag = @firstMatch
and (
       @secondMatch is null 
       or 
       (object in (select object from tblTags where tag = @secondMatch)
     )

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

أوصي بالمخطط التالي.

Objects: objectID, objectName
Tags: tagID, tagName
ObjectTag: objectID,tagID

مع الاستعلام التالي.

select distinct
    objectName
from
    ObjectTab ot
    join object o
        on o.objectID = ot.objectID
    join tabs t
        on t.tagID = ot.tagID
where
    tagName in ('red','fruit')

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

 apple -> fruit
 apple -> red
 apple -> food
 banana -> fruit
 banana -> yellow
 banana -> food

ثم يمكنك فقط

 SELECT object WHERE tag = 'fruit' OR tag = 'food';

إذا كنت تريد حقًا القيام بذلك بطريقتك، فيمكنك القيام بذلك على النحو التالي:

 SELECT object WHERE tag LIKE 'red' OR tag LIKE '% red' OR tag LIKE 'red %' OR tag LIKE '% red %';
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top