प्रत्येक श्रेणी के लिए शीर्ष 10 रिकॉर्ड का चयन करें


207

मैं प्रत्येक अनुभाग से एक क्वेरी में शीर्ष 10 रिकॉर्ड वापस करना चाहता हूं। क्या कोई इसे करने में मदद कर सकता है? अनुभाग तालिका के स्तंभों में से एक है।

डेटाबेस SQL ​​सर्वर 2005 है। मैं दर्ज की गई तारीख से शीर्ष 10 को वापस करना चाहता हूं। अनुभाग व्यवसाय, स्थानीय और सुविधा हैं। एक विशेष तिथि के लिए मैं केवल शीर्ष (10) व्यावसायिक पंक्तियाँ (सबसे हाल की प्रविष्टि), शीर्ष (10) स्थानीय पंक्तियाँ और शीर्ष (10) सुविधाएँ चाहता हूँ।


क्या इनमें से कोई जवाब आपके काम आया?
काइल डेलानी

3
मुझे लगता है कि हम कभी नहीं जान पाएंगे ...
डेनी

12 साल हो गए हैं और हमें नहीं पता कि उनमें से कोई काम करता है या नहीं।
सुगंध

जवाबों:


221

यदि आप SQL 2005 का उपयोग कर रहे हैं, तो आप ऐसा कुछ कर सकते हैं ...

SELECT rs.Field1,rs.Field2 
    FROM (
        SELECT Field1,Field2, Rank() 
          over (Partition BY Section
                ORDER BY RankCriteria DESC ) AS Rank
        FROM table
        ) rs WHERE Rank <= 10

यदि आपकी रैंकक्रिटेरिया में संबंध हैं तो आप 10 से अधिक पंक्तियों को वापस कर सकते हैं और मैट का समाधान आपके लिए बेहतर हो सकता है।


31
यदि आप वास्तव में सिर्फ शीर्ष 10 चाहते हैं, तो इसे रैंक () के बजाय रोवनम्बर () में बदलें। तब कोई संबंध नहीं।
माइक एल

3
यह काम करता है, लेकिन यह ध्यान रखें कि रैंक () को क्वेरी प्लानर द्वारा पूर्ण तालिका प्रकार में बदल दिए जाने की संभावना है यदि कोई इंडेक्स नहीं है जो पहली कुंजी रैंकक्रिटेरिया है। इस मामले में आप अलग-अलग वर्गों का चयन करके बेहतर माइलेज प्राप्त कर सकते हैं और रैंकक्रिटेरिया डेस द्वारा दिए गए शीर्ष 10 को चुनने के लिए आवेदन कर सकते हैं।
जो किरेन

बहुत बढ़िया जवाब! मुझे लगभग वही मिला जो मुझे चाहिए था। मैंने समाप्त किया DENSE_RANKजिसके साथ नंबरिंग में कोई अंतराल नहीं है। +1
माइकल स्ट्रैमल

1
@Facbed यह मेज पर सिर्फ एक उपनाम है।
डारेल मिलर

15
Sql सर्वर का उपयोग करने वाले किसी के लिए, माइक L द्वारा उल्लिखित रोवनंबर () फ़ंक्शन ROW_NUMBER () है।
23

99

T-SQL में, मैं करूँगा:

WITH TOPTEN AS (
    SELECT *, ROW_NUMBER() 
    over (
        PARTITION BY [group_by_field] 
        order by [prioritise_field]
    ) AS RowNo 
    FROM [table_name]
)
SELECT * FROM TOPTEN WHERE RowNo <= 10

2
: कृपया अपने समाधान के बारे में अधिक वर्णनात्मक बनें। संदर्भ: उत्तर कैसे दें
पूछें

क्या CTE में चुनिंदा क्वेरी में क्लॉज़ हो सकता है?
टाहा

1
@ तो हाँ यह कर सकते हैं
KindaTechy

1
यद्यपि आप कहते हैं कि "टी-एसक्यूएल में" यह ROW_NUMBERफ़ंक्शन को लागू करने वाले किसी भी डेटाबेस के लिए काम करता है । उदाहरण के लिए, मैंने इस समाधान का उपयोग SQLite में किया है।
टोनी

यह sql के साथ-साथ पोस्टग्रेट्स के लिए भी काम करता है। मैं तो बस "द्वारा [prioritise_field] desc आदेश" का इस्तेमाल किया था
Phun

35

यह SQL Server 2005 पर काम करता है (आपके स्पष्टीकरण को दर्शाने के लिए संपादित):

select *
from Things t
where t.ThingID in (
    select top 10 ThingID
    from Things tt
    where tt.Section = t.Section and tt.ThingDate = @Date
    order by tt.DateEntered desc
    )
    and t.ThingDate = @Date
order by Section, DateEntered desc

2
यह उन पंक्तियों के लिए काम नहीं करता है जहाँ अनुभाग शून्य है, हालाँकि। आपको "कहाँ (t..Section शून्य और t.Section शून्य है) या" t.S.Section = t.Section "कहने की आवश्यकता होगी
मैट हैमिल्टन

29
SELECT r.*
FROM
(
    SELECT
        r.*,
        ROW_NUMBER() OVER(PARTITION BY r.[SectionID] ORDER BY r.[DateEntered] DESC) rn
    FROM [Records] r
) r
WHERE r.rn <= 10
ORDER BY r.[DateEntered] DESC

उर्फ 'एम' के साथ तालिका क्या है?
चूने

@Chalky यह टाइपो है, होना चाहिए r। तय की।
लॉरंड

एक जादू की तरह काम किया। धन्यवाद!
रॉन नुनी

18

मैं इसे इस तरह से करता हूं:

SELECT a.* FROM articles AS a
  LEFT JOIN articles AS a2 
    ON a.section = a2.section AND a.article_date <= a2.article_date
GROUP BY a.article_id
HAVING COUNT(*) <= 10;

अद्यतन: ग्रुप बाय का यह उदाहरण केवल MySQL और SQLite में काम करता है, क्योंकि उन डेटाबेस डेटाबेस BY के संबंध में मानक SQL की तुलना में अधिक अनुमत हैं। अधिकांश SQL कार्यान्वयन के लिए आवश्यक है कि चयन सूची में सभी कॉलम जो कि एक समग्र अभिव्यक्ति का हिस्सा नहीं हैं, ग्रुप बीवाई में भी हैं।


1
क्या वह काम करता है? मुझे पूरा यकीन है कि आप "a.somecolumn चुनिंदा सूची में अमान्य हैं क्योंकि यह एक स्तंभ या समूह द्वारा समूह में समाहित नहीं है" # लेख को छोड़कर लेखों में हर कॉलम के लिए "
Blorgbeard

1
आपको अन्य स्तंभों को शामिल करने में सक्षम होना चाहिए जो कार्यात्मक रूप से GROUP BY में नामित कॉलम (s) पर निर्भर हैं। ऐसे कॉलम जो कार्यात्मक रूप से निर्भर नहीं हैं, अस्पष्ट हैं। लेकिन आप सही हैं, RDBMS कार्यान्वयन पर निर्भर करता है। यह MySQL में काम करता है लेकिन IIRC InterBase / Firebird में विफल रहता है।
बिल कार्विन

1
क्या इस मामले में यह काम करेगा कि शीर्ष एक खंड के लिए सभी ग्यारह रिकॉर्ड एक ही तिथि थे? वे सभी में 11 की गिनती होगी और परिणाम एक खाली सेट होगा।
अर्थ नोव

नहीं, यदि आपके पास एक ही तिथि है, तो आपको संबंधों को तोड़ने का कोई तरीका होना चाहिए। उदाहरण के लिए stackoverflow.com/questions/121387/… देखें ।
बिल कार्विन

1
@carlosgg, यदि लेखों में वर्गों के साथ कई-कई संबंध हैं, तो आपको लेखों को उनके अनुभागों में मैप करने के लिए एक प्रतिच्छेदन तालिका रखने की आवश्यकता होगी। तब आपकी क्वेरी को m2m संबंध के लिए एक प्रतिच्छेदन तालिका में शामिल होना होगा, और Article_id और अनुभाग द्वारा समूह। यह आपको आरंभ करना चाहिए, लेकिन मैं एक टिप्पणी में संपूर्ण समाधान नहीं लिखूंगा।
बिल कार्विन

16

यदि हम SQL सर्वर> = 2005 का उपयोग करते हैं, तो हम केवल एक चयन के साथ कार्य को हल कर सकते हैं :

declare @t table (
    Id      int ,
    Section int,
    Moment  date
);

insert into @t values
(   1   ,   1   , '2014-01-01'),
(   2   ,   1   , '2014-01-02'),
(   3   ,   1   , '2014-01-03'),
(   4   ,   1   , '2014-01-04'),
(   5   ,   1   , '2014-01-05'),

(   6   ,   2   , '2014-02-06'),
(   7   ,   2   , '2014-02-07'),
(   8   ,   2   , '2014-02-08'),
(   9   ,   2   , '2014-02-09'),
(   10  ,   2   , '2014-02-10'),

(   11  ,   3   , '2014-03-11'),
(   12  ,   3   , '2014-03-12'),
(   13  ,   3   , '2014-03-13'),
(   14  ,   3   , '2014-03-14'),
(   15  ,   3   , '2014-03-15');


-- TWO earliest records in each Section

select top 1 with ties
    Id, Section, Moment 
from
    @t
order by 
    case 
        when row_number() over(partition by Section order by Moment) <= 2 
        then 0 
        else 1 
    end;


-- THREE earliest records in each Section

select top 1 with ties
    Id, Section, Moment 
from
    @t
order by 
    case 
        when row_number() over(partition by Section order by Moment) <= 3 
        then 0 
        else 1 
    end;


-- three LATEST records in each Section

select top 1 with ties
    Id, Section, Moment 
from
    @t
order by 
    case 
        when row_number() over(partition by Section order by Moment desc) <= 3 
        then 0 
        else 1 
    end;

1
+1 यह सादगी के लिए मुझे पसंद है लेकिन क्या आप बता सकते हैं कि 0 या 1 रिटर्निंग क्लॉज में स्टेटमेंट के top 1साथ कैसे काम करता है ? caseorder by
सेरेस

3
शीर्ष 1 यहां TIES के साथ काम करता है। TIES के साथ का अर्थ है कि जब ORDER BY = 0 है, तब SELECT यह रिकॉर्ड लेता है (TOP 1 के कारण) और अन्य सभी जिनके पास ORDER BY = 0 है (क्योंकि TIES के साथ)
वादिम लोबोडा

9

यदि आप जानते हैं कि अनुभाग क्या हैं, तो आप कर सकते हैं:

select top 10 * from table where section=1
union
select top 10 * from table where section=2
union
select top 10 * from table where section=3

3
यह इसे करने का सबसे आसान तरीका होगा।
हेक्टर सोसा जूनियर

3
लेकिन यह अयोग्य होगा यदि आपके पास 150 है या यदि श्रेणियां दिन, सप्ताह, आदि के अनुसार परिवर्तनशील हैं
राफा बैरागान

1
ओपी को उद्धृत करने के लिए ज़रूर, लेकिन "अनुभाग व्यवसाय, स्थानीय और विशेषता हैं"। यदि आपके पास तीन स्थिर श्रेणियां हैं, तो यह करने का सबसे अच्छा तरीका है।
Blorgbeard

9

मुझे पता है कि यह धागा थोड़ा पुराना है, लेकिन मैं बस एक ही समस्या में टकरा रहा हूं (प्रत्येक श्रेणी से नवीनतम लेख का चयन करें) और यह वह समाधान है जिसके साथ मैं आया था:

WITH [TopCategoryArticles] AS (
    SELECT 
        [ArticleID],
        ROW_NUMBER() OVER (
            PARTITION BY [ArticleCategoryID]
            ORDER BY [ArticleDate] DESC
        ) AS [Order]
    FROM [dbo].[Articles]
)
SELECT [Articles].* 
FROM 
    [TopCategoryArticles] LEFT JOIN 
    [dbo].[Articles] ON
        [TopCategoryArticles].[ArticleID] = [Articles].[ArticleID]
WHERE [TopCategoryArticles].[Order] = 1

यह डारेल के समाधान के समान है, लेकिन आरएएनसी समस्या पर काबू पा लेता है जो इरादा से अधिक पंक्तियों को वापस कर सकता है।


CTE सर का उपयोग क्यों करें? क्या यह मेमोरी खपत को कम करता है?
टोह

@ तोथा क्योंकि सीटीई सरल और समझने में आसान है
इंजीनियर

बहुत बढ़िया जवाब!! इसके JOINबजाय आंतरिक का उपयोग करके इसे अनुकूलित किया जा सकता है LEFT JOIN, क्योंकि TopCategoryArticlesबिना संबंधित Articleरिकॉर्ड के कभी भी रिकॉर्ड नहीं होगा ।
उल्टा इंजीनियर

6

निम्नलिखित की कोशिश की और यह संबंधों के साथ भी काम किया।

SELECT rs.Field1,rs.Field2 
FROM (
    SELECT Field1,Field2, ROW_NUMBER() 
      OVER (Partition BY Section
            ORDER BY RankCriteria DESC ) AS Rank
    FROM table
    ) rs WHERE Rank <= 10

5

यदि आप अनुभाग द्वारा समूहीकृत आउटपुट का उत्पादन करना चाहते हैं, तो प्रत्येक अनुभाग से केवल शीर्ष एन रिकॉर्ड को कुछ इस तरह प्रदर्शित करें:

SECTION     SUBSECTION

deer        American Elk/Wapiti
deer        Chinese Water Deer
dog         Cocker Spaniel
dog         German Shephard
horse       Appaloosa
horse       Morgan

... तो निम्नलिखित सभी SQL डेटाबेस के साथ बहुत उदारता से काम करना चाहिए। यदि आप शीर्ष 10 चाहते हैं, तो क्वेरी के अंत में 2 से 10 को बदल दें।

select
    x1.section
    , x1.subsection
from example x1
where
    (
    select count(*)
    from example x2
    where x2.section = x1.section
    and x2.subsection <= x1.subsection
    ) <= 2
order by section, subsection;

स्थापित करना:

create table example ( id int, section varchar(25), subsection varchar(25) );

insert into example select 0, 'dog', 'Labrador Retriever';
insert into example select 1, 'deer', 'Whitetail';
insert into example select 2, 'horse', 'Morgan';
insert into example select 3, 'horse', 'Tarpan';
insert into example select 4, 'deer', 'Row';
insert into example select 5, 'horse', 'Appaloosa';
insert into example select 6, 'dog', 'German Shephard';
insert into example select 7, 'horse', 'Thoroughbred';
insert into example select 8, 'dog', 'Mutt';
insert into example select 9, 'horse', 'Welara Pony';
insert into example select 10, 'dog', 'Cocker Spaniel';
insert into example select 11, 'deer', 'American Elk/Wapiti';
insert into example select 12, 'horse', 'Shetland Pony';
insert into example select 13, 'deer', 'Chinese Water Deer';
insert into example select 14, 'deer', 'Fallow';

जब मैं प्रत्येक अनुभाग के लिए सिर्फ पहला रिकॉर्ड चाहता हूं तो यह काम नहीं करता है। यह सभी अनुभाग समूहों को समाप्त करता है जिनके पास 1 से अधिक रिकॉर्ड हैं। मैंने 14 =
14

@ निल्स केवल तीन खंड मान हैं: हिरण, कुत्ता और घोड़ा। यदि आप क्वेरी को <= 1 में बदलते हैं, तो आपको प्रत्येक अनुभाग के लिए एक उपधारा मिलती है: हिरण के लिए अमेरिकन एल्क / वैपिटी, कुत्ते के लिए कॉकर स्पैनियल और घोड़े के लिए अप्पलोसा। ये भी वर्णक्रम में प्रत्येक खंड में पहला मान हैं। क्वेरी है मतलब अन्य मूल्यों के सभी को खत्म करने।
क्रेग

लेकिन जब मैं आपकी क्वेरी को चलाने का प्रयास करता हूं, तो यह सब कुछ समाप्त कर देता है क्योंकि गणना हर चीज के लिए> = 1 है। यह प्रत्येक अनुभाग के लिए पहली उपधारा को संरक्षित नहीं करता है। क्या आप <= 1 के लिए अपनी क्वेरी चलाने का प्रयास कर सकते हैं और मुझे बता सकते हैं कि क्या आपको प्रत्येक अनुभाग के लिए पहली उपधारा मिली है?
निल्स

@ निल्स हाय, मैंने स्क्रिप्ट्स से इस छोटे परीक्षण डेटाबेस को फिर से बनाया और क्वेरी का उपयोग करके <= 1 का भाग लिया, और इसने प्रत्येक अनुभाग से पहला उपधारा मान लौटाया। आप किस डेटाबेस सर्वर का उपयोग कर रहे हैं? वहाँ हमेशा एक मौका है कि यह आपकी पसंद के डेटाबेस से संबंधित है। मैंने इसे MySQL में सिर्फ इसलिए चलाया क्योंकि यह आसान था और यह उम्मीद के मुताबिक व्यवहार करता था। मुझे पूरा यकीन है कि जब मैंने इसे पहली बार किया था (मैं यह सुनिश्चित करना चाहता था कि मैंने वास्तव में डिबगिन के बिना क्या काम किया है), मुझे पूरा यकीन है कि मैंने इसे साइबेस SQL ​​एनीवेयर या एमएस एसक्यूएल सर्वर का उपयोग करके किया था।
क्रेग

यह मेरे लिए पूरी तरह से mysql में काम करता है। मैंने एक क्वेरी को थोड़ा बदल दिया, यह सुनिश्चित नहीं किया कि उसने उपक्षेत्र में varchar क्षेत्र के लिए <= का उपयोग क्यों किया .. मैंने इसे बदलकर x2.subsection = X1.subsection
Mahen Nakar

4

आपके लिए UNION ऑपरेटर काम कर सकता है? प्रत्येक अनुभाग के लिए एक चयन करें, फिर उन्हें एक साथ संयुक्त करें। हालांकि यह केवल निश्चित वर्गों के लिए काम करेगा।


4

क्यू) प्रत्येक समूह (ओरेकल) से शीर्ष एक्स रिकॉर्ड ढूँढना

SQL> select * from emp e 
  2  where e.empno in (select d.empno from emp d 
  3  where d.deptno=e.deptno and rownum<3)
  4  order by deptno
  5  ;

 EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO

  7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
  7839 KING       PRESIDENT            17-NOV-81       5000                    10
  7369 SMITH      CLERK           7902 17-DEC-80        800                    20
  7566 JONES      MANAGER         7839 02-APR-81       2975                    20
  7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
  7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30

6 पंक्तियों का चयन किया।



सवाल SQL सर्वर के बारे में था, ओरेकल का नहीं।
क्रेग

2

प्रश्न SQL सर्वर 2005 के बारे में था, ज्यादातर लोगों पर ले जाया गया है और यदि वे इस सवाल का पता करूँ, क्या हो सकता है अन्य स्थितियों में वरीय जवाब एक है का उपयोग करते हुए CROSS APPLYइस ब्लॉग पोस्ट में दर्शाया गया है

SELECT *
FROM t
CROSS APPLY (
  SELECT TOP 10 u.*
  FROM u
  WHERE u.t_id = t.t_id
  ORDER BY u.something DESC
) u

इस क्वेरी में 2 टेबल शामिल हैं। ओपी की क्वेरी में केवल 1 टेबल शामिल है, जिसके मामले में एक विंडो फ़ंक्शन आधारित समाधान अधिक कुशल हो सकता है।


1

आप इस दृष्टिकोण की कोशिश कर सकते हैं। यह क्वेरी प्रत्येक देश के 10 सबसे अधिक आबादी वाले शहरों को लौटाती है।

   SELECT city, country, population
   FROM
   (SELECT city, country, population, 
   @country_rank := IF(@current_country = country, @country_rank + 1, 1) AS country_rank,
   @current_country := country 
   FROM cities
   ORDER BY country, population DESC
   ) ranked
   WHERE country_rank <= 10;

यह समाधान एक परीक्षण के मामले में पारित नहीं करता है जब हमारे पास एक ही देश के रिकॉर्ड के साथ 9 समान जनसंख्या के साथ एक तालिका है, यह क्रम में सभी 9 उपलब्ध रिकॉर्ड को वापस करने के बजाय अशक्त देता है। इस मुद्दे को ठीक करने के लिए कोई सुझाव?
मोजगन माजूची
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.