মাইএসকিউএলে স্ব-যোগদানের টেবিল ছাড়াই একাধিক মানের বিপরীতে একক কলামের মিল


14

আমাদের কাছে একটি টেবিল রয়েছে যা আমরা প্রশ্নের উত্তর সঞ্চয় করতে ব্যবহার করি। আমাদের এমন ব্যবহারকারীদের সন্ধান করতে হবে যার নির্দিষ্ট প্রশ্নের নির্দিষ্ট উত্তর রয়েছে। সুতরাং, যদি আমাদের টেবিলটিতে নিম্নলিখিত ডেটা থাকে:

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

এবং আমরা এমন ব্যবহারকারীদের সন্ধান করতে চাইছি যারা প্রশ্ন 1 এর জন্য 'পুচ' এবং 2 নং প্রশ্নের জন্য 'পীচ' উত্তর দিয়েছেন, নিম্নলিখিত এসকিউএল (স্পষ্টতই) কাজ করবে না:

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 প্রশ্নের দুটি উত্তর থাকতে পারে।

সুতরাং, এখন আমি একটি ক্ষতির মধ্যে আছি। এর কাছে যাওয়ার সর্বোত্তম উপায় কী? ধন্যবাদ!

উত্তর:


8

স্ব-যোগদান ছাড়া এই কোয়েরিটি করার একটি চতুর উপায় আমি পেয়েছি।

আমি উইন্ডোজের জন্য মাইএসকিউএল 5.5.8 এ এই কমান্ডগুলি চালিয়েছি এবং নিম্নলিখিত ফলাফল পেয়েছি:

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 |
+---------+-------------+---------------+-------------------+

এখন কেবল সারিগুলিকে ফিল্টার করুন যেখানে মাল্টানসওয়ার_কাউন্ট = 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 ছোট সাবকোয়্যারিতে 2। যোগ দেয় না !!!

একবার চেষ্টা করে দেখো !!!


1
আপনি নিজের উত্তরগুলিতে যে স্তরের প্রচেষ্টা করেছেন তা আমি সর্বদা কৃতজ্ঞ।
এলোমেলো

7

আমি নিজে যোগদানের পদ্ধতিটি পছন্দ করি:

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

আপডেট বৃহত্তর টেবিল (~ 1 মিলিয়ন ডলার) দিয়ে পরীক্ষা করার পরে, এই পদ্ধতিটি ORমূল প্রশ্নে উল্লিখিত সহজ পদ্ধতির চেয়ে উল্লেখযোগ্যভাবে বেশি সময় নিয়েছে ।


জবাবের জন্য ধন্যবাদ. সমস্যাটি হ'ল এটি সম্ভবত একটি বৃহত টেবিল হতে পারে এবং এতে 5-6 বার যোগ দেওয়ার অর্থ একটি বিশাল পারফরম্যান্স হিট নেওয়া, সঠিক?
ক্রিস্টোফার আর্মস্ট্রং

ভাল জিজ্ঞাসা। আমি এটি পরীক্ষা করার জন্য একটি টেস্টকেস লিখছি, কারণ আমি জানি না ... এটি হয়ে গেলে ফলাফল পোস্ট করবে
ডেরেক ডোনিয়ে

1
সুতরাং আমি এলোমেলো ব্যবহারকারী, প্রশ্ন / উত্তর জোড়া দিয়ে 1 মিলিয়ন সারি .োকালাম। যোগ দিন এখনও 557 সেকেন্ডে চলছে এবং আপনার ওআর কোয়েরি 1.84 সেকেন্ডে শেষ হয়েছে ... এখন কোনও কোণে বসতে চলেছে।
ডেরেক ডোনয়

টেস্ট টেবিলে আপনার কি সূচি রয়েছে? আপনি কয়েক মিলিয়ন সারির টেবিলটি স্ক্যান করে নিলে এটি কিছুটা ধীর হবে, সন্দেহ নেই :-)।
মারিয়ান

@ মারিয়ান হ্যাঁ, আমি একটি প্রশ্ন সূচক যুক্ত করেছি (প্রশ্ন_আইডি, উত্তর_মূল্য) সমস্যাটি হ'ল কার্ডিনালিটিটি অত্যন্ত কম, সুতরাং এটি খুব বেশি উপকারে আসে না (প্রতিটি যোগসূত্রিতে 100-200 সারি স্ক্যান করা হয়েছিল)
ডেরেক

5

আমরা যোগদান হয় user_idথেকে answersএকটি চেইন টেবিল অন্যান্য টেবিল থেকে তথ্য পেতে যোগদান এর, কিন্তু উত্তর টেবিল এসকিউএল আলাদা এবং এই ধরনের সহজ পদ এটা লেখার আমাকে সমাধান স্পট সাহায্য সহায়তা দিয়েছে,

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

আমরা অযথা দ্বিতীয় সাব-কোয়েরি ব্যবহার করছি।


আমি আপনার উত্তরটি পছন্দ করতে চাই
কিসস্পা

4

আপনার কাছে যদি ডেটার একটি বড় সেট থাকে তবে আমি দুটি সূচী করব:

  • প্রশ্ন_আইড, উত্তর_মূল্য, ব্যবহারকারী_আইডি; এবং
  • ব্যবহারকারী_দ, প্রশ্ন_ উত্তর, উত্তর_মূল্য।

যেভাবে ডেটা সাজানো হয়েছে তার জন্য আপনাকে একাধিকবার যোগদান করতে হবে। আপনি যদি জানেন যে কোন মানটির জন্য কোন প্রশ্নের পক্ষে কমপক্ষে সাধারণ আপনি ক্যোয়ারিকে কিছুটা গতি দিতে সক্ষম হতে পারেন তবে অনুকূলটি আপনার জন্য এটি করা উচিত should

কোয়েরিটি এখানে চেষ্টা করুন:

নির্বাচন করুন a1.user_id FROM এর উত্তর a1
যেখানে a1.question_id = 1 এবং a1.answer_value = 'পোচ'
INNER JOIN a2.Qtion_id = 2 এ a2 উত্তর দেয় 
   এবং a2.answer_value = 'পীচ' এবং a1.user_id = a2.user_id

সারণি এ 1 এর প্রথম সূচি ব্যবহার করা উচিত। ডেটা বিতরণের উপর নির্ভর করে অপ্টিমাইজারটি সূচকটি ব্যবহার করতে পারে। সম্পূর্ণ ক্যোয়ারী সূচকগুলি থেকে সন্তুষ্ট হওয়া উচিত।


2

এর কাছে যাওয়ার একটি উপায় হ'ল ব্যবহারকারীর_আইডির একটি উপসেট পাওয়া এবং দ্বিতীয় ম্যাচের জন্য এটি পরীক্ষা করা:

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)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.