যোগদানের ক্ষেত্রে সর্বাধিক মান নির্বাচন করতে জিজ্ঞাসা করুন


13


আমার ব্যবহারকারীদের একটি টেবিল রয়েছে:

|Username|UserType|Points|
|John    |A       |250   |
|Mary    |A       |150   |
|Anna    |B       |600   |

এবং স্তর

|UserType|MinPoints|Level  |
|A       |100      |Bronze |
|A       |200      |Silver |
|A       |300      |Gold   |
|B       |500      |Bronze |

এবং আমি প্রতিটি ব্যবহারকারীর জন্য স্তর পেতে একটি অনুসন্ধান খুঁজছি। এর লাইন ধরে কিছু:

SELECT *
FROM Users U
INNER JOIN (
    SELECT TOP 1 Level, U.UserName
    FROM Levels L
    WHERE L.MinPoints < U.Points
    ORDER BY MinPoints DESC
    ) UL ON U.Username = UL.Username

ফলাফলগুলি এমন হবে:

|Username|UserType|Points|Level  |
|John    |A       |250   |Silver |
|Mary    |A       |150   |Bronze |
|Anna    |B       |600   |Bronze |

কার্সারের সাহায্য না নিয়ে আমি কীভাবে এটি করতে পারি সে সম্পর্কে কারও কি কোন ধারণা বা পরামর্শ আছে?

উত্তর:


15

আপনার বিদ্যমান ক্যোয়ারী এমন কোনও কিছুর নিকটে যা আপনি ব্যবহার করতে পারেন তবে কয়েকটি পরিবর্তন করে আপনি সহজেই ফলাফলটি পেতে পারেন। APPLYঅপারেটরটি ব্যবহার করতে এবং প্রয়োগ করতে আপনার ক্যোয়ারী পরিবর্তন করে CROSS APPLY। এটি আপনার প্রয়োজনীয়তা পূরণ করে এমন সারিটি ফিরিয়ে দেবে। আপনি ব্যবহার করতে পারেন এমন একটি সংস্করণ এখানে:

SELECT 
  u.Username, 
  u.UserType,
  u.Points,
  lv.Level
FROM Users u
CROSS APPLY
(
  SELECT TOP 1 Level
  FROM Levels l
  WHERE u.UserType = l.UserType
     and l.MinPoints < u.Points
  ORDER BY l.MinPoints desc
) lv;

এখানে একটি ডেমো সহ একটি এসকিউএল ফিডল । এটি একটি ফলাফল উত্পাদন করে:

| Username | UserType | Points |  Level |
|----------|----------|--------|--------|
|     John |        A |    250 | Silver |
|     Mary |        A |    150 | Bronze |
|     Anna |        B |    600 | Bronze |

3

নিম্নলিখিত সমাধানটি একটি সাধারণ টেবিল এক্সপ্রেশন ব্যবহার করে যা Levelsটেবিলটি একবার স্ক্যান করে । এই স্ক্যানে, "পরবর্তী" পয়েন্ট স্তরগুলি LEAD()উইন্ডো ফাংশনটি ব্যবহার করে পাওয়া যায় , সুতরাং আপনার MinPoints(সারি থেকে) এবং MaxPoints( MinPointsবর্তমানের জন্য পরবর্তী UserType) রয়েছে।

এর পরে, আপনি কেবল সাধারণ টেবিল অভিব্যক্তি যোগ দিতে পারেন, lvls, উপর UserTypeএবং MinPoints/ MaxPointsপরিসীমা, যেমন:

WITH lvls AS (
    SELECT UserType, MinPoints, [Level],
           LEAD(MinPoints, 1, 99999) OVER (
               PARTITION BY UserType
               ORDER BY MinPoints) AS MaxPoints
    FROM Levels)

SELECT U.*, L.[Level]
FROM Users AS U
INNER JOIN lvls AS L ON
    U.UserType=L.UserType AND
    L.MinPoints<=U.Points AND
    L.MaxPoints> U.Points;

উইন্ডো ফাংশনটি ব্যবহার করার সুবিধাটি হ'ল আপনি সমস্ত ধরণের পুনরাবৃত্ত সমাধানগুলি মুছে ফেলেন এবং নাটকীয়ভাবে পারফরম্যান্স উন্নত করুন। সেরা পারফরম্যান্সের জন্য, আপনি Levelsটেবিলে নিম্নলিখিত সূচকটি ব্যবহার করবেন :

CREATE UNIQUE INDEX ... ON Levels (UserType, MinPoints) INCLUDE ([Level]);

দ্রুত সাড়া দেওয়ার জন্য ধন্যবাদ। আপনার জিজ্ঞাসাটি আমাকে আমার সঠিক ফলাফলটি দেবে, তবে এটি "ক্রস অ্যাপ্লায়াই" ব্যবহার করে উপরে নীলফিটের উত্তর চেয়ে কিছুটা ধীর বলে মনে হচ্ছে। আমার নির্দিষ্ট ডেটাসেটের জন্য, আপনার সিটিই ব্যবহার করে সূচি ছাড়াই প্রায় 10 সেকেন্ড সময় লাগে এবং আপনি যে স্তরের উপর প্রস্তাবিত সূচকটি দিয়ে 7 সেকেন্ড সময় নেয়, সেখানে উপরের ক্রস এপ্লিকেশন ক্যোয়ারীটি 3 সেকেন্ডের (এমনকি কোনও সূচক ছাড়াও) লাগে
লাম্বো জয়পালান

@ ল্যাম্বো জয়পালান এই ক্যোয়ারীটি দেখে মনে হচ্ছে এটি কমপক্ষে ব্লুফিটের মতো দক্ষ should আপনি কি এই সঠিক সূচকটি যুক্ত করেছেন (এর সাথে INCLUDE)? এছাড়াও, আপনি কি একটি সূচক আছে Users (UserType, Points)? (এটি সাহায্য করতে পারে)
ypercubeᵀᴹ

এবং কত জন ব্যবহারকারী (সারণিতে সারি Users) আছেন এবং সেই টেবিলটি কত প্রশস্ত?
ypercubeᵀᴹ

2

কেন এটি কেবল প্রাথমিক পদক্ষেপগুলিই ব্যবহার করে না, অন্তর্ভুক্ত হয়ে যোগ দিন, গ্রুপ এবং ম্যাক্স দ্বারা:

SELECT   U1.*,
         L1.Level

FROM     Users AS U1

         INNER JOIN
         (
          SELECT   U2.Username,
                   MAX(L2.MinPoints) AS QualifyingMinPoints
          FROM     Users AS U2
                   INNER JOIN
                   Levels AS L2
                   ON U2.UserType = L2.UserType
          WHERE    L2.MinPoints <= U2.Points
          GROUP BY U2.Username
         ) AS Q
         ON U1.Username = Q.Username

         INNER JOIN
         Levels AS L1
         ON Q.QualifyingMinPoints = L1.MinPoints
            AND U1.UserType = L1.UserType
;

2

আমি মনে করি আপনি INNER JOINকোনও পারফরম্যান্স ইস্যুটি ব্যবহার করতে পারেন আপনি পরিবর্তে এটি ব্যবহার করতে পারেন - এই জাতীয় ফাংশন LEFT JOINসহ ROW_NUMBER():

SELECT 
    Username, UserType, Points, Level
FROM (
    SELECT u.*, l.Level,
      ROW_NUMBER() OVER (PARTITION BY u.Username ORDER BY l.MinPoints DESC) seq
    FROM 
        Users u INNER JOIN
        Levels l ON u.UserType = l.UserType AND u.Points >= l.MinPoints
    ) dt
WHERE
    seq = 1;

এসকিউএল ফিডল ডেমো

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