Sqlserver
 sql >> डेटाबेस >  >> RDS >> Sqlserver

डुप्लीकेट के बिना निकटतम मूल्य के साथ बाएं शामिल हों

सीटीई और विंडोिंग फ़ंक्शन का उपयोग करके एक सेट-आधारित समाधान नीचे दिया गया है।

ranked_matches CTE TableA . में प्रत्येक पंक्ति के लिए निकटतम मिलान रैंक प्रदान करता है TableB . में प्रत्येक पंक्ति के लिए निकटतम मिलान रैंक के साथ , index . का उपयोग करके टाई ब्रेकर के रूप में मूल्य।

best_matches CTE ranked_matches . से पंक्तियां लौटाता है जिनके पास दोनों रैंकिंग के लिए सर्वश्रेष्ठ रैंक (रैंक वैल्यू 1) है।

अंत में, बाहरी क्वेरी LEFT JOIN . का उपयोग करती है TableA . से करने के लिए best_matches TableA . को शामिल करने के लिए CTE क्लोज़ मैच को पहले ही असाइन किए जाने के कारण जिन पंक्तियों को सर्वश्रेष्ठ मिलान नहीं दिया गया था।

ध्यान दें कि यह आपके नमूना परिणामों में इंगित अनुक्रमणिका 3 TableA पंक्ति के लिए एक मिलान नहीं देता है। इस पंक्ति के लिए क्लोज मैच टेबलबी इंडेक्स 3 है, 83 का अंतर है। हालांकि, टेबलबी पंक्ति टेबलए इंडेक्स 2 पंक्ति के करीब है, 14 का अंतर है, इसलिए इसे पहले ही असाइन किया गया था। कृपया अपने प्रश्न को स्पष्ट करें यदि यह वह नहीं है जो आप चाहते हैं। मुझे लगता है कि इस तकनीक को तदनुसार बदला जा सकता है।

CREATE TABLE dbo.TableA(
      [index] int NOT NULL
        CONSTRAINT PK_TableA PRIMARY KEY
    , value int
    );
CREATE TABLE dbo.TableB(
      [index] int NOT NULL
        CONSTRAINT PK_TableB PRIMARY KEY
    , value int
    );
INSERT  INTO dbo.TableA
        ( [index], value )
VALUES  ( 1, 123 ),
        ( 2, 245 ),
        ( 3, 342 ),
        ( 4, 456 ),
        ( 5, 608 );

INSERT  INTO dbo.TableB
        ( [index], value )
VALUES  ( 1, 152 ),
        ( 2, 159 ),
        ( 3, 259 );

WITH 
      ranked_matches AS (
        SELECT 
              a.[index] AS a_index
            , a.value AS a_value
            , b.[index] b_index
            , b.value AS b_value
            , RANK() OVER(PARTITION BY a.[index] ORDER BY ABS(a.Value - b.value), b.[index]) AS a_match_rank
            , RANK() OVER(PARTITION BY b.[index] ORDER BY ABS(a.Value - b.value), a.[index]) AS b_match_rank
        FROM dbo.TableA AS a
        CROSS JOIN dbo.TableB AS b
    )
    , best_matches AS (
        SELECT
              a_index
            , a_value
            , b_index
            , b_value
        FROM ranked_matches
        WHERE
                a_match_rank = 1
            AND b_match_rank= 1
    )
SELECT
      TableA.[index] AS a_index
    , TableA.value AS a_value
    , best_matches.b_index
    , best_matches.b_value
FROM dbo.TableA
LEFT JOIN best_matches ON
    best_matches.a_index = TableA.[index]
ORDER BY
    TableA.[index];

संपादित करें:

हालांकि यह विधि सीटीई का उपयोग करती है, रिकर्सन का उपयोग नहीं किया जाता है और इसलिए 32 के रिकर्सन तक सीमित नहीं है। हालाँकि, प्रदर्शन के दृष्टिकोण से यहाँ सुधार की गुंजाइश हो सकती है।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. एकाधिक तालिकाओं से माइक्रोसॉफ्ट एसक्यूएल सर्वर में एक ही कॉलम नाम का चयन करें

  2. मैं उन सभी कर्मचारियों को कैसे पुनः प्राप्त कर सकता हूँ जिनकी आयु एक महीने में 21 वर्ष होगी?

  3. वसंत में SimpleJDBCCall का उपयोग करके संग्रहीत प्रक्रिया के बहु तालिका परिणाम कैसे प्राप्त करें?

  4. लॉगिन विफल। लॉगिन एक अविश्वसनीय डोमेन से है और इसका उपयोग विंडोज प्रमाणीकरण के साथ नहीं किया जा सकता है

  5. डेटाबेस प्रोजेक्ट बनाते समय 'गलत सेट विकल्प' त्रुटि