SQL से परिणामों का एक पृष्ठ कैसे वापस करें?

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

क्लाइंट को पूरी तालिका लाने और फिर क्लाइंट पर डेटा फ़िल्टर किए बिना इस पैटर्न को लागू करने के लिए एक अच्छा एल्गोरिदम क्या है। आप केवल उन रिकॉर्ड्स को कैसे लाते हैं जिन्हें आप उपयोगकर्ता को प्रदर्शित करना चाहते हैं?

क्या LINQ समाधान को सरल बनाता है?

0
ro fr bn
पेजिंग SQL सर्वर 2005 परिणाम के संभावित डुप्लिकेट
जोड़ा लेखक Lukas Eder, स्रोत

8 उत्तर

एमएस एसक्यूएल सर्वर 2005 और ऊपर, ROW_NUMBER() काम करने लगता है :

टी-एसक्यूएल: ROW_NUMBER() के साथ पेजिंग

DECLARE @PageNum AS INT;
DECLARE @PageSize AS INT;
SET @PageNum = 2;
SET @PageSize = 10;

WITH OrdersRN AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS RowNum
          ,OrderID
          ,OrderDate
          ,CustomerID
          ,EmployeeID
      FROM dbo.Orders
)

SELECT * 
  FROM OrdersRN
 WHERE RowNum BETWEEN (@PageNum - 1) * @PageSize + 1 
                  AND @PageNum * @PageSize
 ORDER BY OrderDate
         ,OrderID;
0
जोड़ा
ROW_NUMBER() पेजिंग इम्यूलेशन, या SQL सर्वर 2012 का <�कोड> ऑफसेट .. FETCH खंड उच्च पृष्ठ संख्याओं के लिए काफी धीमा हो सकता है: 4guysfromrolla.com/webtech/042606-1.shtml । उस स्थिति में, विधि ढूंढना एक बेहतर विकल्प हो सकता है, क्योंकि यह लगातार समय में पेजिंग की अनुमति देता है।
जोड़ा लेखक Lukas Eder, स्रोत

ओरेकल समाधान:

select * from (
    select a.*, rownum rnum from (
        YOUR_QUERY_GOES_HERE -- including the order by
    ) a
    where rownum <= MAX_ROW
 ) where rnum >= MIN_ROW
0
जोड़ा

दरअसल, LINQ में छोड़ें और ले जाएं, जिन्हें चुनने के लिए जोड़ा जा सकता है कि कौन से रिकॉर्ड प्राप्त किए जाते हैं।

उनको जांचें।

For DB: Pagination In SQL Server 2005

0
जोड़ा

There is a discussion about this Here

इस तकनीक को 78 एमएस में 150,000 लाइन डेटाबेस से पृष्ठ संख्या 100,000 मिलती है

ऑप्टिमाइज़र ज्ञान और सेट ROWCOUNT का उपयोग करके, अनुरोध किए गए पृष्ठ में पहला कर्मचारी आईडी प्रारंभिक बिंदु के लिए स्थानीय चर में संग्रहीत है। इसके बाद, @maximumRows में अनुरोध किए गए रिकॉर्ड्स की अधिकतम संख्या में SET ROWCOUNT। यह परिणाम को अधिक कुशल तरीके से सेट करने की अनुमति देता है। इस विधि का उपयोग तालिका में पूर्व-मौजूदा इंडेक्स का लाभ भी लेता है क्योंकि यह सीधे आधार तालिका में जाता है, न कि स्थानीय रूप से बनाई गई तालिका में।

मुझे डर है कि मैं यह निर्णय लेने में सक्षम नहीं हूं कि यह वर्तमान स्वीकृत उत्तर से बेहतर है या नहीं।

0
जोड़ा
एक और बहुत तेज़ दृष्टिकोण विधि ढूंढना है, जो निरंतर समय में पगनेट करने की अनुमति देता है (शायद 78ms से भी तेज)
जोड़ा लेखक Lukas Eder, स्रोत

डेटाबेस में पेजिनेशन करने के अनिवार्य रूप से दो तरीके हैं (मुझे लगता है कि आप SQL सर्वर का उपयोग कर रहे हैं):

ऑफसेट का उपयोग करना

अन्य ने समझाया है कि पृष्ठों को करने के लिए ROW_NUMBER() ओवर() रैंकिंग फ़ंक्शन का उपयोग कैसे किया जा सकता है। यह उल्लेखनीय है कि एसक्यूएल सर्वर 2012 ने आखिरकार एसक्यूएल मानक OFFSET के लिए समर्थन शामिल किया .. FETCH खंड:

SELECT first_name, last_name, score
FROM players
ORDER BY score DESC
OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY

यदि आप SQL Server 2012 का उपयोग कर रहे हैं और पिछड़ा-संगतता कोई समस्या नहीं है, तो आपको शायद इस खंड को प्राथमिकता देना चाहिए क्योंकि यह कोने मामलों में SQL सर्वर द्वारा अधिक बेहतर रूप से निष्पादित किया जाएगा।

SEEK विधि का उपयोग करना

एसक्यूएल में पेजिंग करने के लिए एक पूरी तरह से अलग, बहुत तेज, लेकिन कम ज्ञात तरीका है। इसे अक्सर यह ब्लॉग पोस्ट यहां

SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
   OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC

The @previousScore and @previousPlayerId values are the respective values of the last record from the previous page. This allows you to fetch the "next" page. If the ORDER BY direction is ASC, simply use > instead.

उपर्युक्त विधि के साथ, आप पहले 40 रिकॉर्ड प्राप्त किए बिना तुरंत पृष्ठ 4 पर कूद नहीं सकते हैं। लेकिन अक्सर, आप वैसे भी कूदना नहीं चाहते हैं। इसके बजाय, आपको एक बहुत तेज क्वेरी मिलती है जो आपके अनुक्रमण के आधार पर निरंतर समय में डेटा लाने में सक्षम हो सकती है। इसके अलावा, आपके पृष्ठ "स्थिर" रहते हैं, भले ही अंतर्निहित डेटा बदलता है (उदा। पृष्ठ 1 पर, जब आप पेज 4 पर हों)।

उदाहरण के लिए वेब अनुप्रयोगों में आलसी लोडिंग के दौरान पेजिंग को लागू करने का यह सबसे अच्छा तरीका है।

नोट, "तलाश विधि" को कीसेट पेजिंग भी कहा जाता है।

0
जोड़ा

मैं या तो LINQ का उपयोग करने की सिफारिश करता हूं, या कॉपी करने की कोशिश करता हूं जो यह करता है। मेरे पास एक ऐप है जहां मैं पेज किए गए डेटा को पुनर्प्राप्त करने के लिए LINQ Take और Skip विधियों का उपयोग करता हूं। कोड इस तरह कुछ दिखता है:

MyDataContext db = new MyDataContext();
var results = db.Products
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize);

SQL सर्वर प्रोफाइलर चलाना बताता है कि LINQ इस क्वेरी को SQL में परिवर्तित कर रहा है:

SELECT [ProductId], [Name], [Cost], and so on...
FROM (
    SELECT [ProductId], [Name], [Cost], [ROW_NUMBER]
    FROM (
       SELECT ROW_NUMBER() OVER (ORDER BY [Name]) AS [ROW_NUMBER], 
           [ProductId], [Name], [Cost]
       FROM [Products]
    )
    WHERE [ROW_NUMBER] BETWEEN 10 AND 20
)
ORDER BY [ROW_NUMBER]

सादे अंग्रेजी में:
1. अपनी पंक्तियों को फ़िल्टर करें और इच्छित क्रम में पंक्ति संख्या जोड़ने के लिए ROW_NUMBER फ़ंक्शन का उपयोग करें।
2. फ़िल्टर (1) केवल अपने पृष्ठ पर इच्छित पंक्ति संख्याओं को वापस करने के लिए।
3. पंक्ति संख्या से क्रमबद्ध करें (2), जो आप चाहते थे आदेश के समान है (इस मामले में, नाम से)।

0
जोड़ा
क्या आपको पता है कि क्यों LINQ वास्तविक SELECT कथन को दोगुना करता है? है (था?) कि कुछ SQL सर्वर संस्करण के लिए एक सूक्ष्म प्रदर्शन tweak? मुझे लगता है कि दूसरे स्तर को पहले स्तर के साथ विलय किया जा सकता है।
जोड़ा लेखक Lukas Eder, स्रोत

LINQ लैम्बडा अभिव्यक्तियों और अज्ञात कक्षाओं के साथ संयुक्त .NET 3.5 बेहद इस तरह की चीज़ को सरल बनाता है।

डेटाबेस पूछताछ:

var customers = from c in db.customers
                join p in db.purchases on c.CustomerID equals p.CustomerID
                where p.purchases > 5
                select c;

प्रति पृष्ठ रिकॉर्ड की संख्या:

customers = customers.Skip(pageNum * pageSize).Take(pageSize);

किसी भी कॉलम द्वारा छंटनी:

customers = customers.OrderBy(c => c.LastName);

सर्वर से केवल चयनित फ़ील्ड प्राप्त करना:

var customers = from c in db.customers
                join p in db.purchases on c.CustomerID equals p.CustomerID
                where p.purchases > 5
                select new
                {
                    CustomerID = c.CustomerID,
                    FirstName = c.FirstName,
                    LastName = c.LastName
                };

यह एक स्थाई रूप से टाइप की गई अनाम कक्षा बनाता है जिसमें आप इसकी गुणों तक पहुंच सकते हैं:

var firstCustomer = customer.First();
int id = firstCustomer.CustomerID;

प्रश्नों के परिणाम डिफ़ॉल्ट रूप से आलसी लोड होते हैं, इसलिए जब तक आपको वास्तव में डेटा की आवश्यकता नहीं होती तब तक आप डेटाबेस से बात नहीं कर रहे हैं। .NET में LINQ आपके द्वारा किए गए किसी भी बदलाव के डेटाकॉन्टेक्स्ट को रखकर अपडेट को बहुत सरल बनाता है, और केवल आपके द्वारा खेले जाने वाले फ़ील्ड को अपडेट कर रहा है।

0
जोड़ा
पहला बयान डीबी से सबकुछ वापस खींचने लगता है और फिर दूसरा कथन एक सबसेट प्राप्त करता है। क्या होगा यदि आप बस पहले स्थान पर एक सबसेट चाहते हैं? मेरे पास 90,000 पंक्तियां हैं और बस 10 पंक्तियों में से पेज 4 चाहते हैं।
जोड़ा लेखक Snowy, स्रोत
@ एससीएसयूबी LINQ अभिव्यक्ति आलसी लोड हैं, इसलिए पहली कॉल वास्तव में पहले कुछ भी नहीं करती है। आप ग्राहकों = ग्राहकों को कॉल कर सकते हैं। स्किप (30)। टेक (10) और यह केवल वही चीज़ वापस खींच लेगा जो आप चाहते हैं।
जोड़ा लेखक Adam Lassek, स्रोत

ऐसे कुछ समाधान हैं जिनका उपयोग मैं एमएस एसक्यूएल 2005 के साथ करता हूं।

उनमें से एक ROW_NUMBER() है। लेकिन, व्यक्तिगत रूप से, मुझे ROW_NUMBER() पसंद नहीं है क्योंकि यह बड़े परिणामों के लिए काम नहीं करता है (डीबी जो मैं काम करता हूं वह वास्तव में बड़ा है - 1TB डेटा दूसरे में हजारों प्रश्नों को चला रहा है - आपको पता है - बड़ी सोशल नेटवर्किंग साइट)।

यहां मेरा पसंदीदा समाधान है।

मैं टी-एसक्यूएल के छद्म कोड का उपयोग करूंगा।

आइए फोरनाम, उपनाम द्वारा क्रमबद्ध उपयोगकर्ताओं के दूसरे पृष्ठ को ढूंढें, जहां प्रत्येक पृष्ठ में 10 रिकॉर्ड होते हैं।

@page = 2 -- input parameter
@size = 10 -- can be optional input parameter

if @page < 1 then begin
    @page = 1 -- check page number
end
@start = (@page-1) * @size + 1 -- @page starts at record no @start

-- find the beginning of page @page
SELECT TOP (@start)
    @forename = forename,
    @surname = surname
    @id = id
FROM
    users
ORDER BY
    forename,
    surname,
    id -- to keep correct order in case of have two John Smith.

-- select @size records starting from @start
SELECT TOP (@size)
    id,
    forename,
    surname
FROM
    users
WHERE
    (forename = @forename and surname = @surname and id >= @id) -- the same name and surname, but bigger id
    OR (forename = @forename and surname > @surname) -- the same name, but bigger surname, id doesn't matter
    OR (forename > @forename) -- bigger forename, the rest doesn't matter
ORDER BY
    forename,
    surname,
    id
0
जोड़ा