จะใช้ 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.