Làm cách nào để bạn chọn mọi hàng thứ n từ mysql


79

Tôi có một loạt giá trị trong cơ sở dữ liệu mà tôi cần kéo để tạo biểu đồ đường. Vì tôi không yêu cầu độ phân giải cao nên tôi muốn lấy mẫu lại dữ liệu bằng cách chọn mọi hàng thứ 5 từ cơ sở dữ liệu.

Câu trả lời:


84
SELECT * 
FROM ( 
    SELECT 
        @row := @row +1 AS rownum, [column name] 
    FROM ( 
        SELECT @row :=0) r, [table name] 
    ) ranked 
WHERE rownum % [n] = 1 

5
Ai đó có thể cung cấp thêm thông tin về cách thức hoạt động của nó? Ví dụ câu hỏi được hỏi cho mỗi hàng thứ 5 và không có đề cập đến số 5 trong câu trả lời.
Crazometer

4
@Crazometer thay thế [n]trong truy vấn bằng 5 để nhận mỗi hàng thứ 5.
Benjamin Manns

Để mở rộng điều này, điều gì sẽ xảy ra nếu bạn không muốn bắt đầu với hàng đầu tiên mà là hàng thứ 2 chẳng hạn?
HPWD

@HPWD bạn sẽ thay thế @row :=0với@row :=2
Binar Web

@BinarWeb không, bạn sẽ thay đổi = 1thành= 2
ysth

55

Bạn có thể thử mod 5 để lấy các hàng có ID là bội số của 5. (Giả sử bạn có một số loại cột ID tuần tự.)

select * from table where table.id mod 5 = 0;

19
Cũng giả sử bạn không có khoảng trống trong trình tự, do xóa hoặc quay lại.
Bill Karwin

3
Điều này sẽ hoạt động cho hầu hết các phần nhưng không giải thích cho các hàng đã xóa.
Corban Brook

2
Đơn giản và tuyệt vời cho một số thử nghiệm :-)
Rickard Liljeberg.

1
Điều này có ý nghĩa nếu lựa chọn của bạn truy xuất tất cả dữ liệu. Nếu bạn có các tiêu chí bổ sung trong lựa chọn của mình, thì rất khó để nói dữ liệu nào (nếu có) sẽ truy xuất.
j_kubik

24

Vì bạn đã nói rằng bạn đang sử dụng MySQL, bạn có thể sử dụng các biến người dùng để tạo đánh số hàng liên tục. Tuy nhiên, bạn phải đặt nó trong một bảng dẫn xuất (truy vấn con).

SET @x := 0;
SELECT *
FROM (SELECT (@x:=@x+1) AS x, mt.* FROM mytable mt ORDER BY RAND()) t
WHERE x MOD 5 = 0;

Tôi đã thêm ORDER BY RAND()để lấy mẫu ngẫu nhiên, thay vì cho phép mọi hàng thứ năm của bảng không có thứ tự đều có trong mẫu mỗi lần.


Một người dùng ẩn danh đã cố gắng chỉnh sửa điều này để thay đổi x MOD 5 = 0thành x MOD 5 = 1. Tôi đã thay đổi nó trở lại ban đầu của tôi.

Đối với bản ghi, người ta có thể sử dụng bất kỳ giá trị nào từ 0 đến 4 trong điều kiện đó và không có lý do gì để thích giá trị này hơn giá trị khác.


Tôi đã cập nhật câu trả lời của mình cho điều này, và bạn đã đánh bại tôi với nó! Tư duy tốt.
Josh Stodola

1
không may, làm chậm này xuống thực hiện bởi ít nhất x100 khi làm việc với nhiều mục
phil294

10
SET @a = 0;
SELECT * FROM t where (@a := @a + 1) % 2 = 0;

Điều này hoạt động hiệu quả để phân vùng một bảng tùy ý, chỉ đọc để xử lý song song các hàng và cú pháp siêu dễ đọc và dễ hiểu. Bạn chỉ cần thêm ORDER BY trên cột khóa chính để đảm bảo mỗi hàng chỉ được trả lại một lần.
humbads

2

Tôi đã tìm kiếm một cái gì đó như thế này. Câu trả lời của Taylor và Bill đã khiến tôi cải thiện ý tưởng của họ.

table data1 có các trường read_date, giá trị mà chúng ta muốn chọn mỗi bản ghi 2d từ một truy vấn giới hạn bởi phạm vi read_date, tên của bảng dẫn xuất là tùy ý và ở đây được gọi là DT

truy vấn:

 SET @row := 0;
  SELECT * FROM  ( SELECT @row := @row +1 AS rownum, read_date, value  FROM data1  
  WHERE  read_date>= 1279771200 AND read_date <= 1281844740 ) as DT WHERE MOD(rownum,2)=0

Cảm ơn, tôi đã tìm kiếm điều này. Tôi cần bằng cách nào đó để kiểm tra xem một cột nhất định trong bảng nhật ký cho các thủ tục được lưu trữ có cùng giá trị mỗi lần thứ hai hay không. Như 'proc bắt đầu', 'proc kết thúc'. Sql dưới đây sẽ cho kết quả là 1 nếu mọi thứ đều ổn. SET @row := 0; SELECT count(distinct Message) FROM ( SELECT @row := @row +1 AS rownum, Message FROM operations.EventLog WHERE LogTime > now() - interval 6 hour and ProcedureName = 'Do_CDR' ) as DT WHERE MOD(rownum,2)=0;
eigil

1

Bạn có thể sử dụng truy vấn này,

set @n=2; <!-- nth row -->
select * from (SELECT t.*, 
       @rowid := @rowid + 1 AS ID
  FROM TABLE t, 
       (SELECT @rowid := 0) dummy) A where A.ID mod @n = 0;

hoặc bạn có thể thay thế n bằng giá trị thứ n của bạn


1
SELECT *
FROM ( 
    SELECT @row := @row +1 AS rownum, posts.*
    FROM (
        SELECT @row :=0) r, posts
    ) ranked
WHERE rownum %3 = 1

nơi bài viết là bảng của tôi.


1

Nếu bạn đang sử dụng MariaDB 10.2, MySQL 8 trở lên, bạn có thể làm điều này hiệu quả hơn và tôi nghĩ rõ ràng hơn, bằng cách sử dụng các biểu thức bảnghàm cửa sổ phổ biến .

WITH ordering AS (
  SELECT ROW_NUMBER() OVER (ORDER BY name) AS n, example.* 
    FROM example ORDER BY name
)
SELECT * FROM ordering WHERE MOD(n, 5) = 0;

Về mặt khái niệm, điều này tạo ra một bảng tạm thời với nội dung của examplebảng được sắp xếp theo nametrường, thêm một trường bổ sung được gọi nlà số hàng và sau đó chỉ tìm nạp những hàng có số chính xác chia hết cho 5, tức là mọi hàng thứ 5. Trong thực tế, cơ sở dữ liệu thường có thể tối ưu hóa điều này tốt hơn thế. Nhưng ngay cả khi nó không tối ưu hóa nó nữa, tôi nghĩ nó rõ ràng hơn là sử dụng các biến người dùng lặp đi lặp lại như bạn đã làm trong các phiên bản MySQL trước đó.


0

Nếu bạn không yêu cầu số hàng trong tập kết quả, bạn có thể đơn giản hóa truy vấn.

SELECT 
    [column name] 
FROM
    (SELECT @row:=0) temp, 
    [table name] 
WHERE (@row:=@row + 1) % [n] = 1 

Thay thế các trình giữ chỗ sau:

  1. Thay thế [column name]bằng danh sách các cột bạn cần tìm nạp.
  2. Thay thế [table name]bằng tên bảng của bạn.
  3. Thay thế [n]bằng một số. Ví dụ: nếu bạn cần mỗi hàng thứ 5, hãy thay thế nó bằng 5

Cảm ơn, nó đã gần xong nhưng bạn nên làm điều này tốt hơn: chọn tên từ (SELECT @row: = - 1) temp, t where (@row: = @ row + 1)% 1 = 0; Điều này có hai lợi thế. Đầu tiên, bất kể n, bạn luôn nhận được hàng đầu tiên và hàng thứ hai, nếu bạn đặt n = 1, bạn nhận được tất cả các giá trị chứ không phải không có. (Hai thay đổi: -1 trong hàng: = - 1 và n = 0 thay vì n = 1)
Bruce
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.