Làm cách nào để chọn hàng thứ n trong bảng cơ sở dữ liệu SQL?


399

Tôi muốn tìm hiểu một số cách (lý tưởng) cơ sở dữ liệu bất khả tri trong việc chọn hàng thứ n từ bảng cơ sở dữ liệu. Cũng rất thú vị để xem làm thế nào có thể đạt được điều này bằng cách sử dụng chức năng gốc của các cơ sở dữ liệu sau:

  • Máy chủ SQL
  • MySQL
  • PostgreSQL
  • SQLite
  • Oracle

Tôi hiện đang làm một cái gì đó giống như sau trong SQL Server 2005, nhưng tôi muốn thấy các cách tiếp cận bất khả tri khác:

WITH Ordered AS (
SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
FROM Orders)
SELECT *
FROM Ordered
WHERE RowNumber = 1000000

Tín dụng cho SQL trên: Webro của Firoz Ansari

Cập nhật: Xem câu trả lời của Troels Arvin về tiêu chuẩn SQL. Troels, bạn đã có bất kỳ liên kết chúng tôi có thể trích dẫn?


3
Đúng. Đây là một liên kết đến thông tin về tiêu chuẩn ISO SQL: troels.arvin.dk/db/rdbms/links/#stiterias
Troels Arvin

13
Chỉ cần chỉ ra rằng theo định nghĩa của một mối quan hệ, các hàng trong bảng không có thứ tự, vì vậy không thể chọn hàng thứ N trong bảng. Những gì có thể được chọn là hàng thứ N trong một hàng - được trả về bởi (phần còn lại) của một truy vấn, đó là những gì ví dụ của bạn và tất cả các câu trả lời khác thực hiện. Đối với hầu hết điều này có thể chỉ là ngữ nghĩa, nhưng nó chỉ ra vấn đề cơ bản của câu hỏi. Nếu bạn cần phải trả về OrderNo N, sau đó giới thiệu một cột OrderSequenceNo trong bảng và tạo nó từ một trình tạo trình tự độc lập khi tạo một đơn hàng mới.
Damir Sudarevic

2
Tiêu chuẩn SQL xác định tùy chọn offset x fetch first y rows only. Hiện được hỗ trợ bởi (ít nhất) Postgres, Oracle12, DB2.
a_horse_with_no_name

Câu trả lời:


349

Có nhiều cách để làm điều này trong các phần tùy chọn của tiêu chuẩn, nhưng rất nhiều cơ sở dữ liệu hỗ trợ cách làm của riêng họ.

Một trang web thực sự tốt nói về điều này và những thứ khác là http://troels.arvin.dk/db/rdbms/#select-limit .

Về cơ bản, PostgreSQL và MySQL hỗ trợ phi tiêu chuẩn:

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 và MSSQL hỗ trợ các chức năng cửa sổ tiêu chuẩn:

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
    columns
  FROM tablename
) AS foo
WHERE rownumber <= n

(mà tôi vừa sao chép từ trang được liên kết ở trên vì tôi không bao giờ sử dụng các DB đó)

Cập nhật: Kể từ PostgreQuery 8.4, các chức năng cửa sổ tiêu chuẩn được hỗ trợ, do đó, hãy mong đợi ví dụ thứ hai cũng hoạt động với PostgreQuery.

Cập nhật: SQLite đã thêm các chức năng cửa sổ hỗ trợ trong phiên bản 3.25.0 vào 2018-09-15 nên cả hai biểu mẫu cũng hoạt động trong SQLite.


3
MySQL cũng sử dụng cú pháp OFFSET và LIMIT. Firebird sử dụng các từ khóa FIRST và SKIP, nhưng chúng được đặt ngay sau CHỌN.
Doug

7
Không nên chỉ WHERE rownumber = nđể có được hàng thứ n?
Steve Bennett

MySQL hỗ trợ các chức năng cửa sổ kể từ phiên bản 8. MariaDB kể từ phiên bản 10.2
Paul Spiegel

102

PostgreSQL hỗ trợ các chức năng cửa sổ như được định nghĩa bởi tiêu chuẩn SQL, nhưng chúng rất bất tiện, vì vậy hầu hết mọi người đều sử dụng (không chuẩn) LIMIT/OFFSET :

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;

Ví dụ này chọn hàng thứ 21. OFFSET 20đang nói với Postgres bỏ qua 20 hồ sơ đầu tiên. Nếu bạn không chỉ định một ORDER BYđiều khoản, không có gì đảm bảo bạn sẽ nhận lại được bản ghi nào, điều này hiếm khi hữu ích.


31

Tôi không chắc chắn về bất kỳ phần còn lại nào, nhưng tôi biết SQLite và MySQL không có bất kỳ thứ tự hàng "mặc định" nào. Trong hai phương ngữ đó, ít nhất, đoạn trích sau lấy mục thứ 15 từ the_table, sắp xếp theo ngày / giờ được thêm vào:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15

(tất nhiên, bạn cần phải có trường DATETIME được thêm và đặt nó vào ngày / giờ mà mục nhập đã được thêm vào ...)


Đây có vẻ là cách tốt nhất để giới hạn truy vấn với giá trị bù nội tuyến. Nhưng chúng ta không nên sử dụng 0,14 ở đây? 1,15 sẽ rời hàng đầu tiên.
Đấu sĩ

15 có nghĩa là gì? Tôi biết 1 nói để có được một bản ghi. Dấu phẩy không được sử dụng trong ví dụ này tôi đã kiểm tra ra 1keydata.com/sql/sql-limit.html
committedandroider

1
Trên thực tế, từ đây php.about.com/od/mysqlcommands/g/Limit_sql.htm , nếu bạn muốn lấy mục thứ 15, bạn sẽ không làm LIMIT 14, 1 (0 là phần tử đầu tiên, 1 chiều dài
commitandroider

nó sẽ được CHỌN * TỪ LỆNH SỐ LƯỢNG CÓ THỂ B BYNG CÁCH GIỚI HẠN DESC 15,1
JerryGidel

25

SQL 2005 trở lên có tính năng này tích hợp sẵn. Sử dụng hàm ROW_NUMBER (). Nó là tuyệt vời cho các trang web với trình duyệt kiểu << Prev và Next >>:

Cú pháp:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

Tôi thích giải pháp này, vì nó cảm thấy thẳng hơn.
FoxArc

18

Tôi nghi ngờ điều này là không hiệu quả nhưng là một cách tiếp cận khá đơn giản, nó đã làm việc trên một tập dữ liệu nhỏ mà tôi đã thử.

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc

Điều này sẽ nhận được mục thứ 5, thay đổi số thứ hai hàng đầu để có được một mục thứ n khác

Chỉ máy chủ SQL (tôi nghĩ) nhưng nên hoạt động trên các phiên bản cũ không hỗ trợ ROW_NUMBER ().


Tôi sẽ sử dụng điều này vì ROW_NUMBER () không hoạt động trong SQL 2000 (vâng, chúng tôi vẫn có ứng dụng khách trên SQL 2000) Cụ thể, tôi sẽ thay thế '5' bằng biến lặp của vòng lặp và sử dụng lần lượt sao chép và sửa đổi từng hàng của một bảng. Có lẽ ai đó sẽ thấy nhận xét này và thấy nó hữu ích
Inversus


14

Xác minh nó trên SQL Server:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp

Điều này sẽ cung cấp cho bạn ROW thứ 10 của bảng emp!


Bạn đã cung cấp câu trả lời cho câu hỏi này tại đây Xóa câu trả lời mà bạn cho là không đúng. Nếu bạn nghĩ cả hai câu trả lời đều đúng thì hãy đăng cả hai câu trả lời vào một nơi
SpringLearner

11

Trái với những gì một số câu trả lời khẳng định, tiêu chuẩn SQL không im lặng về chủ đề này.

Kể từ SQL: 2003, bạn đã có thể sử dụng "các hàm cửa sổ" để bỏ qua các hàng và giới hạn các tập kết quả.

Và trong SQL: 2008, một cách tiếp cận đơn giản hơn đã được thêm vào, sử dụng
OFFSET skip ROWS FETCH FIRST n ROWS ONLY

Cá nhân, tôi không nghĩ rằng sự bổ sung của SQL: 2008 là thực sự cần thiết, vì vậy nếu tôi là ISO, tôi sẽ không đưa nó ra khỏi một tiêu chuẩn khá lớn.


Thật tuyệt khi có một tiêu chuẩn, làm cho mọi người như cuộc sống của tôi trở nên dễ dàng hơn và microsoft thật tuyệt khi làm mọi thứ theo cách tiêu chuẩn :)
user230910

7

Khi chúng tôi từng làm việc trong MSSQL 2000, chúng tôi đã làm cái mà chúng tôi gọi là "bộ ba lật":

EDITED

DECLARE @InnerPageSize int
DECLARE @OuterPageSize int
DECLARE @Count int

SELECT @Count = COUNT(<column>) FROM <TABLE>
SET @InnerPageSize = @PageNum * @PageSize
SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)

IF (@OuterPageSize < 0)
    SET @OuterPageSize = 0
ELSE IF (@OuterPageSize > @PageSize)
    SET @OuterPageSize = @PageSize

DECLARE @sql NVARCHAR(8000)

SET @sql = 'SELECT * FROM
(
    SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
    (
        SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
    ) AS t1 ORDER BY <column> DESC
) AS t2 ORDER BY <column> ASC'

PRINT @sql
EXECUTE sp_executesql @sql

Nó không thanh lịch, và nó không nhanh, nhưng nó hoạt động.


Giả sử bạn có 25 hàng và bạn muốn trang thứ ba gồm 10 trang có kích thước hàng, tức là hàng 21-25. Truy vấn trong cùng nhận được 30 hàng đầu (hàng 1-25). Truy vấn ở giữa nhận được 10 hàng cuối cùng (hàng 25-16). Truy vấn bên ngoài sắp xếp lại chúng và trả về các hàng 16-25. Điều này rõ ràng là sai nếu bạn muốn hàng 21-25.
Bill Karwin

Bây giờ nó không hoạt động nếu chúng ta muốn một trang giữa. Giả sử chúng tôi có 25 hàng và chúng tôi muốn trang thứ hai, tức là hàng 11-20. Truy vấn bên trong nhận được 2 * 10 = 20 hàng đầu hoặc hàng 1-20. Truy vấn ở giữa nhận được 15 hàng cuối cùng: 25 - ((2-1) * 10) = 15, mang lại các hàng 20-6. Truy vấn cuối cùng đảo ngược thứ tự và trả về các hàng 6-20. Kỹ thuật này không hoạt động, trừ khi tổng số hàng là bội số của kích thước trang bạn muốn.
Bill Karwin

Có lẽ kết luận tốt nhất là chúng ta nên nâng cấp mọi phiên bản MS SQL Server 2000 còn lại. :-) Đã gần năm 2012, và vấn đề này đã được giải quyết theo những cách tốt hơn trong nhiều năm!
Bill Karwin

@Bill Karwin: Lưu ý các IF / ELSE IFkhối bên dưới OuterPageSizephép tính - trên trang 1 và 2, chúng sẽ giảm OuterPageSizegiá trị xuống 10. Trên trang 3 (hàng 21-25), phép tính sẽ trả về đúng 5 và trên tất cả các trang 4 trở lên, kết quả âm tính từ phép tính sẽ được thay thế bằng 0 (mặc dù có thể sẽ nhanh hơn để trả về một hàng dữ liệu trống ngay tại thời điểm đó).
Adam V

Oh tôi hiểu rồi. Vâng, tôi nghĩ rằng việc sử dụng MS SQL Server 2000 ngày nay không đáng để bận tâm.
Bill Karwin

6

Máy chủ SQL


Chọn bản ghi thứ n từ đầu

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

chọn bản ghi thứ n từ dưới lên

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n

5

Oracle:

select * from (select foo from bar order by foo) where ROWNUM = x

1
where ROWNUM = xsẽ chỉ hoạt động cho x = 1 trong Oracle DB. tức là where ROWNUM = 2sẽ không trả lại bất kỳ hàng nào.
aff

5

Trong Oracle 12c, Bạn có thể sử dụng OFFSET..FETCH..ROWS tùy chọn vớiORDER BY

Ví dụ: để có được bản ghi thứ 3 từ đầu:

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;

4

Đây là một giải pháp nhanh chóng cho sự nhầm lẫn của bạn.

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1

Tại đây Bạn có thể nhận được hàng cuối cùng bằng cách điền N = 0, lần thứ hai cuối cùng bằng N = 1, lần thứ tư cuối cùng bằng cách điền N = 3, v.v.

Đây là câu hỏi rất phổ biến trong cuộc phỏng vấn và đây là câu hỏi rất đơn giản.

Hơn nữa Nếu bạn muốn Số tiền, ID hoặc một số Thứ tự sắp xếp số hơn bạn có thể sử dụng chức năng CAST trong MySQL.

SELECT DISTINCT (`amount`) FROM cart ORDER BY CAST( `amount` AS SIGNED ) DESC LIMIT 4 , 1

Tại đây Bằng cách điền N = 4 Bạn sẽ có thể nhận được Bản ghi cuối cùng thứ năm về số tiền cao nhất từ ​​bảng GIỎ HÀNG. Bạn có thể phù hợp với tên trường và bảng của bạn và đưa ra giải pháp.


3

THÊM VÀO:

LIMIT n,1

Điều đó sẽ giới hạn kết quả trong một kết quả bắt đầu từ kết quả n.


3

Ví dụ: nếu bạn muốn chọn mỗi hàng thứ 10 trong MSSQL, bạn có thể sử dụng;

SELECT * FROM (
  SELECT
    ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
  FROM TableName
) AS foo
WHERE rownumber % 10 = 0

Chỉ cần lấy MOD và thay đổi số 10 ở đây bất kỳ số nào bạn muốn.


3

Đối với SQL Server, một cách chung để đi theo số hàng là như sau:

SET ROWCOUNT @row --@row = the row number you wish to work on.

Ví dụ:

set rowcount 20   --sets row to 20th row

select meat, cheese from dbo.sandwich --select columns from table at 20th row

set rowcount 0   --sets rowcount back to all rows

Điều này sẽ trả về thông tin của hàng thứ 20. Hãy chắc chắn để đưa vào hàng 0 sau đó.


2

GIỚI HẠN n, 1 không hoạt động trong MS SQL Server. Tôi nghĩ rằng đó chỉ là về cơ sở dữ liệu chính duy nhất không hỗ trợ cú pháp đó. Công bằng mà nói, nó không phải là một phần của tiêu chuẩn SQL, mặc dù nó được hỗ trợ rộng rãi đến mức nó phải như vậy. Trong tất cả mọi thứ trừ máy chủ SQL LIMIT hoạt động tuyệt vời. Đối với máy chủ SQL, tôi không thể tìm thấy một giải pháp tao nhã.


1
Ngoại trừ Oracle, DB2, cũng như mọi cơ sở dữ liệu cấp doanh nghiệp trên toàn thế giới. PostgreQuery là về cơ sở dữ liệu doanh nghiệp duy nhất có khả năng hỗ trợ từ khóa LIMIT và điều đó chủ yếu là vì là nguồn mở, nó cần phải được tiếp cận bởi đám đông không biết gì về ACID.
David

3
@AlexD "Câu trả lời" này đã được đăng lại trong những ngày cũ của Stackoverflow trước khi các bình luận được triển khai. Tôi đã có thể đăng bài này như một bình luận cho một câu trả lời khác, nhưng tại thời điểm đó, các bình luận đã không tồn tại.
Kibbee

2

Đây là phiên bản chung của một sproc tôi mới viết cho Oracle cho phép phân trang / phân loại động - HTH

-- p_LowerBound = first row # in the returned set; if second page of 10 rows,
--                this would be 11 (-1 for unbounded/not set)
-- p_UpperBound = last row # in the returned set; if second page of 10 rows,
--                this would be 20 (-1 for unbounded/not set)

OPEN o_Cursor FOR
SELECT * FROM (
SELECT
    Column1,
    Column2
    rownum AS rn
FROM
(
    SELECT
        tbl.Column1,
        tbl.column2
    FROM MyTable tbl
    WHERE
        tbl.Column1 = p_PKParam OR
        tbl.Column1 = -1
    ORDER BY
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
        DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
        DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
))
WHERE
    (rn >= p_lowerBound OR p_lowerBound = -1) AND
    (rn <= p_upperBound OR p_upperBound = -1);

2

Nhưng thực sự, không phải tất cả những điều này thực sự chỉ là thủ thuật để thiết kế cơ sở dữ liệu tốt ngay từ đầu sao? Một vài lần tôi cần chức năng như thế này là một truy vấn đơn giản để báo cáo nhanh. Đối với bất kỳ công việc thực tế, sử dụng các thủ thuật như thế này là mời rắc rối. Nếu cần chọn một hàng cụ thể thì chỉ cần có một cột có giá trị tuần tự và được thực hiện với nó.


2

Đối với máy chủ SQL, phần sau sẽ trả về hàng đầu tiên từ bảng cho.

declare @rowNumber int = 1;
    select TOP(@rowNumber) * from [dbo].[someTable];
EXCEPT
    select TOP(@rowNumber - 1) * from [dbo].[someTable];

Bạn có thể lặp qua các giá trị bằng một cái gì đó như thế này:

WHILE @constVar > 0
BEGIN
    declare @rowNumber int = @consVar;
       select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
       select TOP(@rowNumber - 1) * from [dbo].[someTable];  

       SET @constVar = @constVar - 1;    
END;

1

Trong Sybase SQL mọi nơi:

SELECT TOP 1 START AT n * from table ORDER BY whatever

Đừng quên thứ tự theo hoặc nó là vô nghĩa.


1

T-SQL - Chọn số thứ tự bản ghi từ bảng

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber

Where  RecordNumber --> Record Number to Select
       TableName --> To be Replaced with your Table Name

Ví dụ: để chọn bản ghi thứ 5 từ bảng Nhân viên, truy vấn của bạn phải là

select * from
 (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5

1
SELECT * FROM emp a
WHERE  n = (SELECT COUNT( _rowid)
              FROM emp b
             WHERE a. _rowid >= b. _rowid);

1
SELECT
    top 1 *
FROM
    table_name
WHERE
    column_name IN (
        SELECT
            top N column_name
        FROM
            TABLE
        ORDER BY
            column_name
    )
ORDER BY
    column_name DESC

Tôi đã viết truy vấn này để tìm hàng thứ N. Ví dụ với truy vấn này sẽ là

SELECT
    top 1 *
FROM
    Employee
WHERE
    emp_id IN (
        SELECT
            top 7 emp_id
        FROM
            Employee
        ORDER BY
            emp_id
    )
ORDER BY
    emp_id DESC

0

không thể tin được rằng bạn có thể tìm thấy một công cụ SQL thực thi cái này ...

WITH sentence AS
(SELECT 
    stuff,
    row = ROW_NUMBER() OVER (ORDER BY Id)
FROM 
    SentenceType
    )
SELECT
    sen.stuff
FROM sentence sen
WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1

0

Không có gì lạ mắt, không có chức năng đặc biệt, trong trường hợp bạn sử dụng Caché như tôi ...

SELECT TOP 1 * FROM (
  SELECT TOP n * FROM <table>
  ORDER BY ID Desc
)
ORDER BY ID ASC

Cho rằng bạn có một cột ID hoặc cột dấu thời gian bạn có thể tin tưởng.


0

Đây là cách tôi thực hiện trong SQL SQL, tôi tin rằng RRN (số bản ghi tương đối) được O / S lưu trữ trong bảng;

SELECT * FROM (                        
   SELECT RRN(FOO) AS RRN, FOO.*
   FROM FOO                         
   ORDER BY RRN(FOO)) BAR             
 WHERE BAR.RRN = recordnumber

0
select * from 
(select * from ordered order by order_id limit 100) x order by 
x.order_id desc limit 1;

Đầu tiên chọn 100 hàng trên cùng bằng cách sắp xếp theo thứ tự tăng dần và sau đó chọn hàng cuối bằng cách sắp xếp theo thứ tự giảm dần và giới hạn là 1. Tuy nhiên, đây là một tuyên bố rất tốn kém vì nó truy cập dữ liệu hai lần.


0

Dường như với tôi, để hiệu quả, bạn cần 1) tạo một số ngẫu nhiên từ 0 đến một ít hơn số lượng bản ghi cơ sở dữ liệu và 2) có thể chọn hàng tại vị trí đó. Thật không may, các cơ sở dữ liệu khác nhau có các trình tạo số ngẫu nhiên khác nhau và các cách khác nhau để chọn một hàng tại một vị trí trong tập kết quả - thông thường bạn chỉ định có bao nhiêu hàng để bỏ qua và bao nhiêu hàng bạn muốn, nhưng nó được thực hiện khác nhau cho các cơ sở dữ liệu khác nhau. Đây là một cái gì đó phù hợp với tôi trong SQLite:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Nó phụ thuộc vào việc có thể sử dụng truy vấn con trong mệnh đề giới hạn (trong SQLite là LIMIT <recs để bỏ qua>, <recs to Take>) Việc chọn số lượng bản ghi trong bảng phải đặc biệt hiệu quả, là một phần của cơ sở dữ liệu dữ liệu meta, nhưng điều đó phụ thuộc vào việc triển khai cơ sở dữ liệu. Ngoài ra, tôi không biết liệu truy vấn có thực sự xây dựng tập kết quả hay không trước khi truy xuất bản ghi thứ N, nhưng tôi hy vọng rằng nó không cần thiết. Lưu ý rằng tôi không chỉ định mệnh đề "order by". Có thể tốt hơn là "sắp xếp theo" thứ gì đó giống như khóa chính, sẽ có một chỉ mục - nhận bản ghi N từ một chỉ mục có thể nhanh hơn nếu cơ sở dữ liệu không thể lấy bản ghi thứ N từ chính cơ sở dữ liệu mà không xây dựng tập kết quả .


0

Câu trả lời phù hợp nhất mà tôi đã thấy trên này bài viết cho máy chủ sql

WITH myTableWithRows AS (
    SELECT (ROW_NUMBER() OVER (ORDER BY myTable.SomeField)) as row,*
    FROM myTable)
SELECT * FROM myTableWithRows WHERE row = 3
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.