FIND_IN_SET () बनाम IN ()


125

मेरे डेटाबेस में 2 टेबल हैं। एक ऑर्डर के लिए है, और एक कंपनियों के लिए है।

आदेशों में यह संरचना है:

OrderID     |     attachedCompanyIDs
------------------------------------
   1                     1,2,3
   2                     2,4

और कंपनी की यह संरचना है:

CompanyID      |        name
--------------------------------------
    1                 Company 1
    2                 Another Company
    3                 StackOverflow
    4                 Nothing

ऑर्डर की कंपनियों के नाम पाने के लिए, मैं इस तरह से एक प्रश्न कर सकता हूं:

SELECT name FROM orders,company
WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)

वह क्वेरी ठीक काम करती है, लेकिन निम्नलिखित क्वेरी नहीं करती है।

SELECT name FROM orders,company
WHERE orderID = 1 AND companyID IN (attachedCompanyIDs)

पहली क्वेरी क्यों काम करती है लेकिन दूसरी नहीं?

पहला क्वेरी रिटर्न:

name
---------------
Company 1
Another Company
StackOverflow

दूसरी क्वेरी केवल रिटर्न:

name
---------------
Company 1

ऐसा क्यों है, पहली क्वेरी सभी कंपनियों को क्यों लौटाती है, लेकिन दूसरी क्वेरी पहले वाली को ही लौटाती है?


3
संलग्नकॉग्निड्स एक बड़ी स्ट्रिंग है, इसलिए mysql इस कंपनी को पूर्णांक बनाने के लिए इसका पता लगाने की कोशिश करता है
Haim Evgi

मुझे लगता है कि यह सबसे अच्छा उदाहरण है mysqltutorial.org/mysql-find_in_set
Shurvir Mori

जवाबों:


100
SELECT  name
FROM    orders,company
WHERE   orderID = 1
        AND companyID IN (attachedCompanyIDs)

attachedCompanyIDsएक अदिश मान है जिसे INT(प्रकार companyID) में डाला जाता है ।

कलाकार केवल पहले गैर-अंक (आपके मामले में एक अल्पविराम) तक की संख्या देता है।

इस प्रकार,

companyID IN ('1,2,3')  companyID IN (CAST('1,2,3' AS INT))  companyID IN (1)

में PostgreSQL, आप स्ट्रिंग को सरणी में डाल सकते हैं (या इसे पहले स्थान पर सरणी के रूप में संग्रहीत कर सकते हैं):

SELECT  name
FROM    orders
JOIN    company
ON      companyID = ANY (('{' | attachedCompanyIDs | '}')::INT[])
WHERE   orderID = 1

और यह भी एक सूचकांक का उपयोग करेगा companyID

दुर्भाग्य से, यह काम नहीं करता है MySQLक्योंकि उत्तरार्द्ध सरणियों का समर्थन नहीं करता है।

आपको यह लेख रोचक लग सकता है (देखें #2):

अपडेट करें:

यदि अल्पविराम से अलग की गई सूची में मानों की संख्या पर कुछ उचित सीमा है (जैसे, इससे अधिक नहीं 5), तो आप इस क्वेरी का उपयोग करने का प्रयास कर सकते हैं:

SELECT  name
FROM    orders
CROSS JOIN
        (
        SELECT  1 AS pos
        UNION ALL
        SELECT  2 AS pos
        UNION ALL
        SELECT  3 AS pos
        UNION ALL
        SELECT  4 AS pos
        UNION ALL
        SELECT  5 AS pos
        ) q
JOIN    company
ON      companyID = CAST(NULLIF(SUBSTRING_INDEX(attachedCompanyIDs, ',', -pos), SUBSTRING_INDEX(attachedCompanyIDs, ',', 1 - pos)) AS UNSIGNED)

3
स्पष्टीकरण के लिए धन्यवाद। मुझे पता नहीं लगा कि संलग्नक फील्ड एक INT में डाली गई है। क्या MySQL में इसके आसपास कोई रास्ता है? FIND_IN_SETकाम करता है, लेकिन अनुक्रमित का उपयोग नहीं करता है, और कंपनी की तालिका में बहुत सारी जानकारी के साथ धीमा हो सकता है।
रॉकेट हज़रत

1
क्या आप उस अपडेट की व्याख्या कर सकते हैं? वास्तव में यह क्या करता है, क्योंकि यह काम करने लगता है।
रॉकेट हज़मत

1
@Rocket: यह posशुरुआत से आइटम स्ट्रिप्स करता है CVSऔर बाकी को पूर्णांक में कास्ट करता है।
क्वासोनि

9
Thumbs up (y) for10 things in MySQL (that won’t work as expected)
NullPointer

@Quassnoi, आप क्यों लिखते हैं CROSS JOIN? क्या वे सब MySQL में एक जैसे नहीं हैं ?
पचेरियर

13

संलग्नकॉग्निड्स एक बड़ी स्ट्रिंग है, इसलिए mysql इस कंपनी में अपने पूर्णांक के लिए कंपनी खोजने की कोशिश करता है

जब आप का उपयोग करें जहां में

तो अगर comapnyid = 1:

companyID IN ('1,2,3')

यह सच है

लेकिन अगर नंबर 1 पहले स्थान पर नहीं है

 companyID IN ('2,3,1')

इसकी वापसी झूठी है


3

सभी संबंधित कंपनियों का नाम प्राप्त करने के लिए, विशेष आईडी के आधार पर नहीं।

SELECT 
    (SELECT GROUP_CONCAT(cmp.cmpny_name) 
    FROM company cmp 
    WHERE FIND_IN_SET(cmp.CompanyID, odr.attachedCompanyIDs)
    ) AS COMPANIES
FROM orders odr

1

क्योंकि दूसरी क्वेरी आईडी के 1 या 2 या 3 के साथ पंक्तियों की तलाश कर रही है, पहली क्वेरी को कंपनी में मौजूद अल्पविराम सीमांकित मानों में से एक की तलाश है,

और यहाँ एक और समस्या यह है कि आप टेबल में शामिल नहीं हो रहे हैं एक आम कुंजी में जहाँ आप पंक्तियों का एक म्यूटेशन प्राप्त करने जा रहे हैं = काउंट (टेबल 1) * काउंट (टेबल 2);

आपकी समस्या वास्तव में मेरे उत्तर के भाग 2 के साथ मौजूद है। (आपकी दूसरी क्वेरी के साथ)


मैं दिखा रहा हूँ की तुलना में दोनों तालिकाओं में अधिक पंक्तियाँ हैं। दोनों तालिकाओं में, आपके द्वारा लॉग इन की गई उपयोगकर्ता की आईडी, उस सहायता पर शामिल होगी?
रॉकेट हज़मत

यदि आपकी पहली क्वेरी अपेक्षित परिणाम नहीं दे रही है तो आपको केवल कुछ भी बदलने की आवश्यकता है। यदि पहली क्वेरी आपके द्वारा इच्छित परिणाम लौटा रही है तो वास्तव में कोई समस्या नहीं है। मुझे लगा कि आप बस उत्सुक थे कि 2 समान परिणाम क्यों नहीं दिखाते हैं।
सुपरफरो नोव

@ सुपरफ़्रो, मैं इस बात से उत्सुक हूं कि 2 समान परिणाम क्यों नहीं दिखाते हैं।
रॉकेट हज़मत

आपकी दूसरी क्वेरी एक IN (मान) का उपयोग कर रही है, जहां 'मान' भाग तालिका से आता है, और इसकी एक स्ट्रिंग। स्ट्रिंग का मूल्यांकन एक बूल सच के रूप में किया जा रहा है = 1 जिसके कारण यह केवल पहली पंक्ति दिखाता है।
सुपरफरो

1
यदि आप प्रदर्शन के बारे में चिंतित हैं, तो आपको संभवतः अपने डेटाबेस संरचना को बदलने के बारे में सोचना चाहिए। आप एक संयुक्त तालिका जोड़ सकते हैं जिसमें 2 मान होते हैं, ऑर्डर तालिका में कॉमा सीमांकित सूची का उपयोग करने के बजाय order_ID और company_ID। यह आपको कंपनी से बाएं नाम सेलेक्ट करने का आदेश देगा। यह अनुक्रमित का उपयोग करेगा।
सुपरफ्रो

-1

मुझे बताएं कि FIND_IN_SET का उपयोग कब करें और IN का उपयोग कब करें।

आइए टेबल ए लेते हैं जिसमें "सहायता", "एनाम" नाम के कॉलम हैं। आइए टेबल बी लेते हैं जिसमें "बोली", "bname", "एड्स" नाम के कॉलम हैं।

अब नीचे तालिका ए और टेबल बी में डमी मान हैं।

तालिका ए

अनाम को सहायता

1 सेब

2 केला

3 आम

टेबल बी

बोली bname एड्स

1 सेब 1,2

2 केला 2,1

3 आम 3,1,2

enter code here

Case1: यदि आप टेबल बी से वे रिकॉर्ड प्राप्त करना चाहते हैं, जिसमें एड्स कॉलम में 1 मान मौजूद है तो आपको FIND_IN_SET का उपयोग करना होगा।

क्वेरी: FIND_IN_SET (Aaid, b.aids) पर A JOIN B से सेलेक्ट करें जहां A.aid = 1;

Case2: यदि आप तालिका से उन अभिलेखों को प्राप्त करना चाहते हैं जिनमें सहायता कॉलम में 1 या 2 या 3 मान मौजूद है तो आपको IN का उपयोग करना होगा।

प्रश्न: A JOIN B ON A.aid IN (b.aids) से चुनें *;

अब यहाँ पर आपको बताया गया है कि आपको mysql query के माध्यम से क्या चाहिए।


यह प्रश्न पहले से ही हल था। इसके अलावा, मुझे नहीं लगता कि आपका दूसरा उदाहरण, IN के साथ, काम करता है ... मूल रूप से वह समस्या थी जिसे मैं शुरुआत में हल करने की कोशिश कर रहा था।
रॉकेट हज़मत

-2
SELECT o.*, GROUP_CONCAT(c.name) FROM Orders AS o , Company.c
    WHERE FIND_IN_SET(c.CompanyID , o.attachedCompanyIDs) GROUP BY o.attachedCompanyIDs

6
एसओ में आपका स्वागत है! स्पष्टीकरण के बिना कोड शायद ही कभी सहायक होता है। इस मामले में यह "क्यों ...?" सवाल का जवाब देने की कोशिश भी नहीं करता है। कृपया यह भी ध्यान दें कि इस विशेष प्रश्न में पहले से ही एक स्वीकृत उत्तर है जो एक अच्छी तरह से प्राप्त (> 80 वोट!) उत्तर देता है। एक नए उपयोगकर्ता के रूप में अनुत्तरित प्रश्नों और / या स्वयं अच्छे प्रश्नों पर ध्यान केंद्रित करना सबसे अच्छा हो सकता है।
cfi
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.