จะใช้ LIMIT กับ SQL Server ได้อย่างไร?


130

ฉันมีคำถามนี้กับ MySQL:

select * from table1 LIMIT 10,20

ฉันจะทำสิ่งนี้กับ SQL Server ได้อย่างไร


อาจซ้ำกันได้ของLIMIT 10..20 ใน SQL Server
— assylias

13
เนื่องจากคำถามนี้ถูกถามก่อนคำถามอื่นจะไม่ซ้ำหรือไม่
— Tab Alleman

คำตอบ:


127

เริ่มต้น SQL SERVER 2005 คุณสามารถทำได้ ...

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 10 AND 20;

หรืออะไรทำนองนี้สำหรับรุ่นปี 2000 และต่ำกว่า ...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC

6
แบบสอบถามที่ 2 ล้มเหลวหากคุณมีเช่น 14 แถวในตาราง ให้แถวที่ 5 ถึง 14 แต่คุณต้องการแถวที่ 11 ถึง 14 โดยทั่วไปแล้วจะล้มเหลวสำหรับ "หน้า" สุดท้ายของผลลัพธ์เว้นแต่ว่าแถวทั้งหมดจะมีขนาด "หน้า" หลายขนาด
— Bill Karwin

147
เรื่องง่ายๆแบบนี้ต้องทำให้ MS ยากขนาดนี้อีกแล้ว!
— Martin

นี่คือสิ่งที่ใช้ได้ผลสำหรับฉันใน SQL Server Management Studio 2017: SELECT * FROM [dbo] <insert tableName here> WHERE @@ ROWCOUNT BETWEEN <insert min here> and <insert max here>
— Artorias2718

ยอดเยี่ยมมันใช้งานได้เหมือนมีเสน่ห์ใน MS SQL Server 2017 select Statement
— PatsonLeaner

58

Clunky แต่ก็ใช้ได้ผล

SELECT TOP 10 * FROM table WHERE id NOT IN (SELECT TOP 10 id FROM table ORDER BY id) FROM table ORDER BY id

การละเว้นข้อ LIMIT ของ MSSQL ถือเป็นความผิดทางอาญา IMO คุณไม่ควรต้องทำวิธีแก้ปัญหาแบบนี้


คุณมีคำแนะนำอื่นให้เลี่ยงสิ่งนี้หรือไม่?
— Bigballs

ฉันทำ Googling หลายครั้งในครั้งสุดท้ายที่ต้องจัดการกับ MSSQL และนี่คือทางออกที่ดีที่สุดที่ฉันพบ ไม่ถูกใจ แต่ได้ผล
— ceejayoz

โซลูชันนี้ใช้ได้เฉพาะเมื่อชุดผลลัพธ์มีคอลัมน์ที่ไม่ซ้ำกัน ไม่ใช่วิธีแก้ปัญหาทั่วไปในการเลียนแบบ LIMIT สำหรับข้อความค้นหาใด ๆ
— Bill Karwin

1
ตอนนี้ฉันรู้สึกไม่แน่ใจเหมือนกัน ... อย่างไรก็ตามในกรณีของฉันฉันถูกหลอก ... มันจะเป็นความผิดทางอาญามากขึ้นเมื่อเรียกว่า 'ผู้เชี่ยวชาญ' dba ตัดสินใจว่าคีย์เฉพาะที่ไม่จำเป็นในตาราง ... ตารางใด ๆ ... อย่าแม้แต่จะพูดถึงเรื่องของคีย์ต่างประเทศและข้อ จำกัด !
— Andrew Rollings

ปัญหาของข้อนี้คือมันไม่สามารถจัดการกับ WHERE clauses ได้เป็นอย่างดี ... ฉันจะลองใช้ temp table เพราะมันไม่ได้ผลสำหรับฉัน
— ขนมที่น่ารังเกียจ

37

เริ่มต้นด้วย SQL SERVER 2012 คุณสามารถใช้คำสั่ง OFFSET FETCH:

USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader 
ORDER BY SalesOrderID
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
GO

http://msdn.microsoft.com/en-us/library/ms188385(v=sql.110).aspx

สิ่งนี้อาจทำงานไม่ถูกต้องเมื่อลำดับโดยไม่ซ้ำกัน

ถ้าแบบสอบถามถูกแก้ไขเป็น ORDER BY OrderDate ชุดผลลัพธ์ที่ส่งคืนจะไม่เป็นไปตามที่คาดไว้


การใช้ "with" ใช้เวลาเพียงครึ่งเดียวในการค้นหาให้เสร็จ - ดูคำตอบของ @Leon Tayson ฉันไม่รู้ว่า Microsoft ทำอะไรให้มันช้าขนาดนั้น
— isHuman

1
เหตุใดจึงไม่เป็นคำตอบที่ยอมรับ เราอยู่ในปี 2018เพราะร้องไห้ออกมาดัง ๆ !
— Skipper

1
@Skipper ขวา อันที่ยอมรับยังคงใช้งานได้ ลองโหวตอันนี้เพื่อสะท้อนการอัปเดต
— kronn

18

นี่เกือบจะซ้ำกับคำถามที่ฉันถามในเดือนตุลาคม: เลียนแบบคำสั่ง MySQL LIMIT ใน Microsoft SQL Server 2000

หากคุณใช้ Microsoft SQL Server 2000 ไม่มีวิธีแก้ปัญหาที่ดี คนส่วนใหญ่ต้องใช้การบันทึกผลลัพธ์ของแบบสอบถามในตารางชั่วคราวด้วยIDENTITYคีย์หลัก จากนั้นสอบถามกับคอลัมน์คีย์หลักโดยใช้BETWEENเงื่อนไข

หากคุณใช้ Microsoft SQL Server 2005 หรือใหม่กว่าคุณมีROW_NUMBER()ฟังก์ชันดังนั้นคุณจะได้รับผลลัพธ์เดียวกัน แต่หลีกเลี่ยงตารางชั่วคราว

SELECT t1.*
FROM (
    SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
    FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN @offset+1 AND @offset+@count;

นอกจากนี้คุณยังสามารถเขียนนี้เป็นแสดงออกตารางที่พบบ่อยตามที่แสดงใน @ ลีออง Tayson ของคำตอบ


ROW_NUMBER () OVER (ORDER BY) ได้รับคะแนนสำหรับความถูกต้องใน ANSI SQL: 2003 แม้ว่าการสนับสนุนใน DBMS นอกเหนือจาก SQL Server จะขาด ๆ หาย ๆ และมันก็ค่อนข้างน่าเบื่อแน่นอน ...
— bobince

@bobince: ปรากฎว่า Oracle, Microsoft SQL Server 2005, IBM DB2 และ PostgreSQL 8.4 รองรับฟังก์ชันหน้าต่างทั้งหมด ซึ่งครอบคลุมตลาด SQL ส่วนใหญ่ การสนับสนุนจะไม่แน่นอนหากคุณใช้ MySQL, SQLite หรือ DB รุ่นเก่าข้างต้น
— Bill Karwin

16

นี่คือวิธีที่ฉัน จำกัด ผลลัพธ์ใน MS SQL Server 2012:

SELECT * 
FROM table1
ORDER BY columnName
  OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

หมายเหตุ: OFFSETสามารถใช้ร่วมกับORDER BY .

เพื่ออธิบายสายรหัส OFFSET xx ROWS FETCH NEXT yy ROW ONLY

xxเป็นจำนวนบันทึก / แถวที่คุณต้องการที่จะเริ่มต้นจากการดึงในตารางคือ: ถ้ามี 40 ระเบียนในตารางที่ 1 รหัสดังกล่าวข้างต้นจะเริ่มดึงจากแถว 10

yyเป็นจำนวนของระเบียน / แถวที่คุณต้องการที่จะดึงจากตาราง

เพื่อสร้างจากตัวอย่างก่อนหน้านี้: หากตารางที่ 1 มี 40 ระเบียนและคุณเริ่มดึงจากแถว 10 และคว้าชุดถัดไปเป็น 10 (yy ) นั่นหมายความว่าโค้ดด้านบนจะดึงระเบียนจากตาราง 1 โดยเริ่มจากแถวที่ 10 และสิ้นสุดที่ 20 ดังนั้นจึงดึงแถวที่ 10 - 20

ตรวจสอบลิงค์สำหรับข้อมูลเพิ่มเติมเกี่ยวกับOFFSET


12
SELECT  *
FROM    (
        SELECT  TOP 20
                t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
        FROM    table1 t
        ORDER BY
                field1
        ) t
WHERE   rn > 10

ฉันเพิ่งตรวจสอบแล้ว SQL Server กลายเป็นว่าฉลาดพอที่จะหยุดเงื่อนไข ROW_NUMBER () หากมีคอลัมน์ที่จัดทำดัชนีในคำสั่ง ORDER BY
— Quassnoi

9

แบบสอบถาม MySQL LIMIT เชิงไวยากรณ์เป็นดังนี้:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

สิ่งนี้สามารถแปลเป็น Microsoft SQL Server เช่น

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

ตอนนี้คำถามของคุณselect * from table1 LIMIT 10,20จะเป็นดังนี้:

SELECT * FROM 
(
    SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table1
) a
WHERE rnum > 10 

2

นี่เป็นหนึ่งในเหตุผลที่ฉันพยายามหลีกเลี่ยงการใช้ MS Server ... แต่อย่างไรก็ตาม บางครั้งคุณก็ไม่มีตัวเลือก (เย้! และฉันต้องใช้เวอร์ชันที่ล้าสมัย !!)

คำแนะนำของฉันคือการสร้างตารางเสมือน:

จาก:

SELECT * FROM table

ถึง:

CREATE VIEW v_table AS    
    SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table

จากนั้นเพียงแค่สอบถาม:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

หากมีการเพิ่มหรือลบช่อง "แถว" จะอัปเดตโดยอัตโนมัติ

ปัญหาหลักของตัวเลือกนี้คือ ORDER BY ได้รับการแก้ไข ดังนั้นหากคุณต้องการคำสั่งอื่นคุณจะต้องสร้างมุมมองอื่น

UPDATE

มีปัญหาอีกอย่างในแนวทางนี้: หากคุณพยายามกรองข้อมูลของคุณจะไม่ได้ผลตามที่คาดไว้ ตัวอย่างเช่นหากคุณทำ:

SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20

WHERE จะ จำกัด เฉพาะข้อมูลที่อยู่ในแถวระหว่าง 10 ถึง 20 (แทนที่จะค้นหาชุดข้อมูลทั้งหมดและ จำกัด เอาต์พุต)


1

นี่เป็นแนวทางหลายขั้นตอนที่จะทำงานใน SQL2000

-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)

INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria

Select * FROM #foo where rowID > 10

1
SELECT 
    * 
FROM 
    (
        SELECT 
            top 20              -- ($a) number of records to show
            * 
        FROM
            (
                SELECT 
                    top 29      -- ($b) last record position
                    * 
                FROM 
                    table       -- replace this for table name (i.e. "Customer")
                ORDER BY 
                    2 ASC
            ) AS tbl1 
        ORDER BY 
            2 DESC
    ) AS tbl2 
ORDER BY 
    2 ASC;

-- Examples:

-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;

-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;

-- To calculate $b:
-- $b = ($a + position) - 1

-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;

เป็นทางออกที่ดีสำหรับฉัน
— Tyde

1

ต้องลอง. ในแบบสอบถามด้านล่างคุณสามารถดูจัดกลุ่มตามลำดับโดยข้ามแถวและ จำกัด แถว

select emp_no , sum(salary_amount) from emp_salary
Group by emp_no 
ORDER BY emp_no 
OFFSET 5 ROWS       -- Skip first 5 
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows

0
SELECT TOP 10 * FROM table;

ก็เหมือนกับ

SELECT * FROM table LIMIT 0,10;

นี่คือบทความเกี่ยวกับการใช้ Limit ใน MsSQLเป็นการอ่านที่ดีโดยเฉพาะความคิดเห็น


1
ขอบคุณ แต่ฉันต้องการบันทึกระหว่าง 10 ถึง 20 มีวิธีทำไหม
— Bigballs

5
คำตอบนี้ไม่ตอบสนองต่อคำถามต้นกำเนิด แต่จะมีประโยชน์ถ้าคนอย่างฉันต้องการทราบวิธีรับผลลัพธ์ N แรกและมาที่นี่ผ่าน Google และอื่น ๆ ...
— brianlmerritt


0

หาก ID ของคุณเป็นประเภทตัวระบุที่ไม่ซ้ำกันหรือ ID ของคุณในตารางไม่ได้รับการจัดเรียงคุณต้องทำเช่นนี้ด้านล่าง

select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5



รหัสจะเป็น

เลือก * จากขีด จำกัด 2,5

0

ใช้สิ่งนี้ได้ดีกว่าใน MSSQLExpress 2017

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

- ให้คอลัมน์ [Count] และกำหนดให้ทุกแถวมีการนับที่ไม่ซ้ำกันโดยไม่ต้องสั่งซื้อบางอย่างจากนั้นเลือกอีกครั้งที่คุณสามารถระบุขีด จำกัด ของคุณได้ .. :)


0

วิธีหนึ่งที่เป็นไปได้ที่จะได้รับผลลัพธ์ดังต่อไปนี้หวังว่านี่จะช่วยได้

declare @start int
declare @end int
SET @start = '5000';  -- 0 , 5000 ,
SET @end = '10000'; -- 5001, 10001
SELECT * FROM ( 
  SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
 ) a WHERE a.row > @start and a.row <= @end

0

ทางที่ง่าย

ข้อมูล MySQL:

SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'

MSSQL:

SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset' 
ROWS FETCH NEXT 'per_page' ROWS ONLY

ORDER BY เป็นข้อบังคับ


-2

ถ้าฉันจำไม่ผิด (เป็นเวลานานแล้วที่ฉันใช้ SQL Server) คุณอาจสามารถใช้สิ่งนี้ได้: (2005 ขึ้นไป)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

SQL Server 2012: Msg 207 ระดับ 16 สถานะ 1 บรรทัด 5 ชื่อคอลัมน์ไม่ถูกต้อง 'RowNum'
— e-info128

ดูเหมือนว่าคุณพิมพ์ผิดในคำสั่งของคุณที่ไหนสักแห่ง RowNum คือชื่อที่เรากำหนดให้กับนิพจน์ โพสต์ปัญหาของคุณกับแหล่งที่มาและชุมชนจะช่วยคุณ
— Kris

นี่ไม่ใช่ไวยากรณ์ที่ถูกต้อง คุณไม่สามารถอ้างอิงในWHEREนามแฝงที่กำหนดไว้ในSELECTประโยคระดับเดียวกัน
— ypercubeᵀᴹ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.