it-swarm.asia

مطابقة عمود واحد بقيم متعددة بدون جدول الانضمام الذاتي في MySQL

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

user_id     question_id     answer_value  
Sally        1               Pooch  
Sally        2               Peach  
John         1               Pooch  
John         2               Duke

ونريد العثور على المستخدمين الذين يجيبون عن "Pooch" للسؤال 1 و "Peach" للسؤال 2 ، فإن SQL التالية (من الواضح) لن تعمل:

select user_id 
from answers 
where question_id=1 
  and answer_value = 'Pooch'
  and question_id=2
  and answer_value='Peach'

فكرتي الأولى كانت الانضمام إلى الجدول لكل إجابة نبحث عنها:

select a.user_id 
from answers a, answers b 
where a.user_id = b.user_id
  and a.question_id=1
  and a.answer_value = 'Pooch'
  and b.question_id=2
  and b.answer_value='Peach'

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

select user_id, count(question_id) 
from answers 
where (
       (question_id=2 and answer_value = 'Peach') 
    or (question_id=1 and answer_value = 'Pooch')
      )
group by user_id 
having count(question_id)>1

ومع ذلك ، نريد أن يتمكن المستخدمون من أخذ نفس الاستبيان مرتين ، لذا من المحتمل أن يكون لديهم إجابتان للسؤال 1 في جدول الإجابات.

لذا ، أنا الآن في حيرة. ما هي أفضل طريقة للتعامل مع هذا؟ شكر!

14
Christopher Armstrong

كنا ننضم الى user_id من الجدول answers في سلسلة من الصلات للحصول على بيانات من جداول أخرى ، ولكن عزل جدول الإجابات SQL وكتابته بعبارات بسيطة ساعدني في تحديد الحل:

SELECT user_id, COUNT(question_id) 
FROM answers 
WHERE
  (question_id = 2 AND answer_value = 'Peach') 
  OR (question_id = 1 AND answer_value = 'Pooch')
GROUP by user_id 
HAVING COUNT(question_id) > 1

كنا نستخدم بدون داع استعلام فرعي ثان.

5
Christopher Armstrong

لقد وجدت طريقة ذكية للقيام بهذا الاستعلام دون الانضمام إلى الذات.

لقد قمت بتشغيل هذه الأوامر في MySQL 5.5.8 لنظام التشغيل Windows وحصلت على النتائج التالية:

use test
DROP TABLE IF EXISTS answers;
CREATE TABLE answers (user_id VARCHAR(10),question_id INT,answer_value VARCHAR(20));
INSERT INTO answers VALUES
('Sally',1,'Pouch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duke');
INSERT INTO answers VALUES
('Sally',1,'Pooch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duck');

SELECT user_id,question_id,GROUP_CONCAT(DISTINCT answer_value) given_answers
FROM answers GROUP BY user_id,question_id;

+---------+-------------+---------------+
| user_id | question_id | given_answers |
+---------+-------------+---------------+
| John    |           1 | Pooch         |
| John    |           2 | Duke,Duck     |
| Sally   |           1 | Pouch,Pooch   |
| Sally   |           2 | Peach         |
+---------+-------------+---------------+

يكشف هذا العرض أن جون أعطى إجابتين مختلفتين للسؤال 2 وأعطت سالي إجابتين مختلفتين للسؤال 1.

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

SELECT user_id,question_id,given_answers,
(LENGTH(given_answers) - LENGTH(REPLACE(given_answers,',','')))+1 multianswer_count
FROM (SELECT user_id,question_id,GROUP_CONCAT(DISTINCT answer_value) given_answers
FROM answers GROUP BY user_id,question_id) A;

حصلت على هذا:

+---------+-------------+---------------+-------------------+
| user_id | question_id | given_answers | multianswer_count |
+---------+-------------+---------------+-------------------+
| John    |           1 | Pooch         |                 1 |
| John    |           2 | Duke,Duck     |                 2 |
| Sally   |           1 | Pouch,Pooch   |                 2 |
| Sally   |           2 | Peach         |                 1 |
+---------+-------------+---------------+-------------------+

الآن فقط قم بتصفية الصفوف حيث multianswer_count = 1 باستخدام استعلام فرعي آخر:

SELECT * FROM (SELECT user_id,question_id,given_answers,
(LENGTH(given_answers) - LENGTH(REPLACE(given_answers,',','')))+1 multianswer_count
FROM (SELECT user_id,question_id,GROUP_CONCAT(DISTINCT answer_value) given_answers
FROM answers GROUP BY user_id,question_id) A) AA WHERE multianswer_count > 1;

هذا ما حصلت عليه:

+---------+-------------+---------------+-------------------+
| user_id | question_id | given_answers | multianswer_count |
+---------+-------------+---------------+-------------------+
| John    |           2 | Duke,Duck     |                 2 |
| Sally   |           1 | Pouch,Pooch   |                 2 |
+---------+-------------+---------------+-------------------+

بشكل أساسي ، أجريت ثلاث عمليات مسح للجدول: 1 على الجدول الرئيسي ، 2 على الاستعلامات الفرعية الصغيرة. لا ينضم !!!

جربها !!!

8
RolandoMySQLDBA

أحب طريقة الانضمام ، بنفسي:

SELECT a.user_id FROM answers a
INNER JOIN answers a1 ON a1.question_id=1 AND a1.answer_value='Pooch'
INNER JOIN answers a2 ON a2.question_id=2 AND a2.answer_value='Peach'
GROUP BY a.user_id

تحديث بعد الاختبار باستخدام جدول أكبر (~ مليون صف) ، استغرقت هذه الطريقة وقتًا أطول بكثير من الطريقة OR البسيطة المذكورة في السؤال الأصلي.

7
Derek Downey

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

  • question_id ، answer_value ، user_id ؛ و
  • user_id و question_id و answer_value.

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

جرب الاستعلام باسم:

حدد a1.user_id من إجابات a1 
 WHERE a1.question_id = 1 AND a1.answer_value = 'Pooch' 
 INNER JOIN يجيب a2 ON a2.question_id = 2 
 و a2.answer_value = 'Peach' AND a1.user_id = a2.user_id

يجب أن يستخدم الجدول a1 الفهرس الأول. بناءً على توزيع البيانات ، قد يستخدم المُحسِّن أيًا من الفهرس. يجب استيفاء الاستعلام بأكمله من الفهارس.

4
BillThor

تتمثل إحدى طرق الاقتراب منه في الحصول على مجموعة فرعية من user_id واختبارها في المباراة الثانية:

SELECT user_id 
FROM answers 
WHERE question_id = 1 
AND answer_value = 'Pooch'
AND user_id IN (SELECT user_id FROM answers WHERE question_id=2 AND answer_value = 'Peach');

باستخدام هيكل رولاندو:

CREATE TABLE answers (user_id VARCHAR(10),question_id INT,answer_value VARCHAR(20));
INSERT INTO answers VALUES
('Sally',1,'Pouch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duke');
INSERT INTO answers VALUES
('Sally',1,'Pooch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duck');

عائدات:

mysql> SELECT user_id FROM answers WHERE question_id = 1 AND answer_value = 'Pooch' AND user_id IN (SELECT user_id FROM answers WHERE question_id=2 AND answer_value = 'Peach');
+---------+
| user_id |
+---------+
| Sally   |
+---------+
1 row in set (0.00 sec)
2
randomx