Lọc trùng trong SQL?

Liên hệ QC

Ngày mai trời lại sáng

Thành viên thường trực
Tham gia
4/7/21
Bài viết
339
Được thích
139
Chào các bạn,
Em sử dụng câu lệnh sau để lấy ra dữ liệu như bảng 1 (file kèm):
Mã:
SELECT A.[CODE],A.[LOCAT],A.[INPUT_DATE]
FROM [DB_ABC].[dbo].[ODER] A
ORDER BY A.[INPUT_DATE] DESC
Em muốn lấy ra bảng 2 điều kiện 10 mã CODE không trùng và dữ liệu LOCAT,INPUT_DATE phải đi là thời điểm sau cùng thì sử dụng câu lệnh nào ạ?
Mong các bạn chỉ giúp, em cảm ơn.
 

File đính kèm

Dùng Liên hệ nội (Correlated Query)

Group theo mã lọc trùng
Chọn max date
Chọn các fields còn lại theo câu truy vấn phụ: =mã, và =max date

Tuy nhiên, nếu bạn không rõ correlated query thì dùng Join dễ hơn:

Truy vấn con: Group theo mã, lấy mã và max date [mxDate]
Truy vấn bảng join với truy vấn con theo mã và date = [mxDate]
 
Lần chỉnh sửa cuối:
Xem lại, tôi đã chỉnh bài, thêm cách thứ 2 dễ hơn.
Dạ,chú xem giúp cháu viết sai chỗ nào mà kết quả ra cả đống không lọc trùng lấy 10 mã ạ:
Mã:
SELECT   B.[CODE],B.[LOCAT],X.[INPUT_DATE]
FROM [DB_ABC].[dbo].[ODER] B
    LEFT JOIN
        (SELECT TOP (10)  A.[CODE], MAX (A.[INPUT_DATE]) AS [INPUT_DATE]
        FROM [DB_ABC].[dbo].[ODER] A
        GROUP BY A.[CODE]
        ORDER BY [INPUT_DATE] DESC ) AS X
ON
        B.[CODE] = X.[CODE]
ORDER BY X.[INPUT_DATE] DESC
 
Chào các bạn,
Em sử dụng câu lệnh sau để lấy ra dữ liệu như bảng 1 (file kèm):
Mã:
SELECT A.[CODE],A.[LOCAT],A.[INPUT_DATE]
FROM [DB_ABC].[dbo].[ODER] A
ORDER BY A.[INPUT_DATE] DESC
Em muốn lấy ra bảng 2 điều kiện 10 mã CODE không trùng và dữ liệu LOCAT,INPUT_DATE phải đi là thời điểm sau cùng thì sử dụng câu lệnh nào ạ?
Mong các bạn chỉ giúp, em cảm ơn.
Bạn thử với đoạn sau nhé:

SQL:
SELECT TOP 10 A.CODE,
              A.LOCAT,
              B.NGAY
FROM   [SHEET1$A2:C] A
       INNER JOIN (SELECT [CODE],
                          MAX([INPUT_DATE]) AS Ngay
                   FROM   [SHEET1$A2:C]
                   GROUP  BY [CODE]) B
               ON A.[CODE] = B.[CODE]
                  AND A.[INPUT_DATE] = B.NGAY
 
Bạn thử với đoạn sau nhé:

SQL:
SELECT TOP 10 A.CODE,
              A.LOCAT,
              B.NGAY
FROM   [SHEET1$A2:C] A
       INNER JOIN (SELECT [CODE],
                          MAX([INPUT_DATE]) AS Ngay
                   FROM   [SHEET1$A2:C]
                   GROUP  BY [CODE]) B
               ON A.[CODE] = B.[CODE]
                  AND A.[INPUT_DATE] = B.NGAY
Hic em thử với Excel thì ra kết quả đúng kết quả rồi:
Mã:
Sub Test()
    Dim strSQL As String
    strSQL = "SELECT TOP 10 A.CODE,A.LOCAT,B.NGAY FROM [SHEET1$A2:C] A " & _
            "INNER JOIN (SELECT [CODE], MAX([INPUT_DATE]) As NGAY FROM [SHEET1$A2:C] " & _
            "GROUP  BY [CODE]) B ON A.[CODE] = B.[CODE] AND A.[INPUT_DATE] = B.NGAY "
               
    With CreateObject("ADODB.Connection")
        .Open ("Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0;Data Source=" & ThisWorkbook.FullName)
        Sheet1.Range("O2").CopyFromRecordset .Execute(strSQL)
    End With
 
End Sub
Cảm ơn anh Admin rất nhiều.
Bài đã được tự động gộp:

Bạn thử với đoạn sau nhé:

SQL:
SELECT TOP 10 A.CODE,
              A.LOCAT,
              B.NGAY
FROM   [SHEET1$A2:C] A
       INNER JOIN (SELECT [CODE],
                          MAX([INPUT_DATE]) AS Ngay
                   FROM   [SHEET1$A2:C]
                   GROUP  BY [CODE]) B
               ON A.[CODE] = B.[CODE]
                  AND A.[INPUT_DATE] = B.NGAY
Chào anh Admin có thể dữ liệu bảng 1 do em sử dụng "ORDER BY [INPUT_DATE] DESC " nên dữ liệu đã được sắp xếp ngày mới nhất lên trước.
Còn thực tế khi chạy toàn bộ câu lệnh này trong SQL thì chưa có 'ORDER BY [INPUT_DATE] DESC' nên dữ liệu vẫn lấy top 10 nhưng không lấy ngày mới nhất, em thử sắp xếp lại bảng 1 để ngày cũ lên trước thì kết quả chạy code xuất ra không giống bảng 2 nữa ạ.
Anh chỉnh giúp em với ạ, em cảm ơn anh.
 

File đính kèm

Lần chỉnh sửa cuối:
Bạn thử với đoạn sau nhé:

SQL:
SELECT TOP 10 A.CODE,
              A.LOCAT,
              B.NGAY
FROM   [SHEET1$A2:C] A
       INNER JOIN (SELECT [CODE],
                          MAX([INPUT_DATE]) AS Ngay
                   FROM   [SHEET1$A2:C]
                   GROUP  BY [CODE]) B
               ON A.[CODE] = B.[CODE]
                  AND A.[INPUT_DATE] = B.NGAY
Em thêm 'ORDER BY A.[INPUT_DATE] DESC ' ở cuối OK rồi ạ, cảm anh Admin nhiều
Mã:
SELECT TOP 10 A.CODE,
              A.LOCAT,
              B.NGAY
FROM   [SHEET1$A2:C] A
       INNER JOIN (SELECT [CODE],
                          MAX([INPUT_DATE]) AS Ngay
                   FROM   [SHEET1$A2:C]
                   GROUP  BY [CODE]) B
               ON A.[CODE] = B.[CODE]
                  AND A.[INPUT_DATE] = B.NGAY
                  ORDER BY A.[INPUT_DATE] DESC
 
Nếu Select Top 10 thì đặt nó ở query con để giảm số dòng lấy ra trước khi join.

Đối với SQL Server thì cái Execution Plan nó sẽ tối ưu hóa cho nên có thể cũng như nhau. Nhưng với Access thì cái plan này làm việc không hiệu quả bằng.
 
Truy vấn liên hệ nội đại khái nó như thế này:
(tôi chỉ cho biết nguyên lý thôi, phần hoa lá lấy 10 dòng đầu bạn tự tính lấy)

Mã:
SELECT Code, Locat, Input_date
FROM BANG A
WHERE Input_date IN
    ( SELECT MAX(Input_date)
       FROM BANG WHERE Code = A.Code)

Chú thích:
- câu truy vấn chính đặt một tên "nick" (tức A) cho bảng chính và truyền cái nick này cho câu truy vấn con. Mục đích để phân biệt hai bảng.
- với mỗi dòng trong A, câu chính thảy cái A.Code cho câu con để truy vấn phụ.
- câu truy vấn con lọc ra các dòng có Code bằng A.Code và lựa lấy thời điểm gần nhất
- Lệnh WHERE...IN chọn dòng có Input_date bằng thời điểm chọn trên.
- Túm lợi, hai câu truy vấn hợp lại để tìm dòng có thời điểm gần nhất cho mỗi Code.
 
Truy vấn liên hệ nội đại khái nó như thế này:
(tôi chỉ cho biết nguyên lý thôi, phần hoa lá lấy 10 dòng đầu bạn tự tính lấy)

Mã:
SELECT Code, Locat, Input_date
FROM BANG A
WHERE Input_date IN
    ( SELECT MAX(Input_date)
       FROM BANG WHERE Code = A.Code)

Chú thích:
- câu truy vấn chính đặt một tên "nick" (tức A) cho bảng chính và truyền cái nick này cho câu truy vấn con. Mục đích để phân biệt hai bảng.
- với mỗi dòng trong A, câu chính thảy cái A.Code cho câu con để truy vấn phụ.
- câu truy vấn con lọc ra các dòng có Code bằng A.Code và lựa lấy thời điểm gần nhất
- Lệnh WHERE...IN chọn dòng có Input_date bằng thời điểm chọn trên.
- Túm lợi, hai câu truy vấn hợp lại để tìm dòng có thời điểm gần nhất cho mỗi Code.
Dạ, cháu cảm ơn chú nhiều ạ.
Cách dùng In như thế này cũng rất hay, nhiều lúc cháu thắc mắc trong In có thể chứa được bao nhiêu phần tử?
Nhân đây nhờ chú chỉ thêm cho cháu mục này với ạ.
 
Truy vấn liên hệ nội đại khái nó như thế này
Tôi gọi Select Where ... In (Select ...) là truy vấn lồng. Nếu Select con (tạm gọi vậy) là chính bảng đó thì nó là liên hệ nội, nếu Select con lấy từ bảng khác thì cần có liên hệ ngoại. Cách lồng này hơi khó viết nhưng viết quen rồi thì ghiền. Hồi mới vọc Access tôi toàn phải viết các query trung gian rồi join các kiểu.
 
Dạ, cháu cảm ơn chú nhiều ạ.
Cách dùng In như thế này cũng rất hay, nhiều lúc cháu thắc mắc trong In có thể chứa được bao nhiêu phần tử?
Nhân đây nhờ chú chỉ thêm cho cháu mục này với ạ.
IN chỉ là một giới từ toán tử căn bản trong ngữ pháp SQL.
Người ta sử dụng nhiều là vì nó dễ hiểu, dễ dùng chứ trên thực tế nó không hiệu quả lắm với List/Set lớn.
Nếu nghĩ rằng cái list của mình sẽ lớn cỡ vài trăm phần tử thì đừng dùng IN, dùng exists hoặc join hiệu quả hơn.

Do đó, việc tìm hiểu giới hạn của List là thừa.
 
IN chỉ là một giới từ toán tử căn bản trong ngữ pháp SQL.
Người ta sử dụng nhiều là vì nó dễ hiểu, dễ dùng chứ trên thực tế nó không hiệu quả lắm với List/Set lớn.
Nếu nghĩ rằng cái list của mình sẽ lớn cỡ vài trăm phần tử thì đừng dùng IN, dùng exists hoặc join hiệu quả hơn.

Do đó, việc tìm hiểu giới hạn của List là thừa.
Dạ,cảm ơn chú đã hướng dẫn.
Đúng là như vậy giả sử cháu có một list danh mã hàng đầy đủ hơn 1000 mã mà nhưng cháu chỉ đưa vào có vài trăm mã hàng thôi.
Mục đích cháu muốn truy vẫn thông tin theo vài trăm mã hàng này giống như sử dụng VLOOKUP theo mã hàng vậy.
Không biết với trường hợp này ngoài dùng IN thì dùng exists hoặc join thì sẽ sử lý thế nào, nếu không phiền nhờ chú chỉ dẫn thêm ạ.
 
Dạ,cảm ơn chú đã hướng dẫn.
Đúng là như vậy giả sử cháu có một list danh mã hàng đầy đủ hơn 1000 mã mà nhưng cháu chỉ đưa vào có vài trăm mã hàng thôi.
Mục đích cháu muốn truy vẫn thông tin theo vài trăm mã hàng này giống như sử dụng VLOOKUP theo mã hàng vậy.
Không biết với trường hợp này ngoài dùng IN thì dùng exists hoặc join thì sẽ sử lý thế nào, nếu không phiền nhờ chú chỉ dẫn thêm ạ.
Trước mình cũng dùng sql server để thay vlookup.
Có lưu ý là dùng join nó sẽ khác vlookup ở chỗ là nếu có nhiều hơn 1 giá trị tham chiếu thì bảng kết quả sẽ hiện thị hết các tham chiếu.
Nên bạn cân nhắc xem trường hợp như vậy xảy ra, ban có chấp nhận không? Hay chỉ muốn tham chiếu 1 giá trị.
 
Trước mình cũng dùng sql server để thay vlookup.
Có lưu ý là dùng join nó sẽ khác vlookup ở chỗ là nếu có nhiều hơn 1 giá trị tham chiếu thì bảng kết quả sẽ hiện thị hết các tham chiếu.
Nên bạn cân nhắc xem trường hợp như vậy xảy ra, ban có chấp nhận không? Hay chỉ muốn tham chiếu 1 giá trị.
Cảm ơn bạn nếu kết quả trả về có nhiều hơn 1 giá trị cũng được bạn à, mình sẽ tùy biến thêm các điều kiện khác nếu cần.
 
Dạ,cảm ơn chú đã hướng dẫn.
Đúng là như vậy giả sử cháu có một list danh mã hàng đầy đủ hơn 1000 mã mà nhưng cháu chỉ đưa vào có vài trăm mã hàng thôi.
Mục đích cháu muốn truy vẫn thông tin theo vài trăm mã hàng này giống như sử dụng VLOOKUP theo mã hàng vậy.
Không biết với trường hợp này ngoài dùng IN thì dùng exists hoặc join thì sẽ sử lý thế nào, nếu không phiền nhờ chú chỉ dẫn thêm ạ.
VLookup có thể dùng kiểu tìm gần đúng để tăng tốc. VLookup là tài sản riêng của Excel cho nên MS muons làm gì thì làm.
IN trong SQL thì tiêu chuẩn SQL chỉ bắt buộc kết quả, còn quy trình tra như thế nào các phần mềm tự làm. Tương tự như mấy bài hỏi về code VBA ở đây, chỉ có kết quả là bắt buộc. Code thì người viết code chú trọng chạy nhanh, kẻ chú trọng tổng quát nhiều tính năng.

Lệnh Exists đi xa vấn đề rồi. Tôi trả lời thì bạn sẽ hỏi tiếp, nó như sóng sông cả, lớp sau tiếp lớp trước, cả tháng sau cũng chưa kết thúc. Bạn tự tìm hiểu và thử đi nhé - thử cỡ chục lần, nhìn đủ khía cạnh rồi hãy hỏi tiếp.
 
Cảm ơn bạn nếu kết quả trả về có nhiều hơn 1 giá trị cũng được bạn à, mình sẽ tùy biến thêm các điều kiện khác nếu cần.
Mình dùng Left Join, bạn google để có thể tìm hiểu thêm về Join trong SQL để biết thêm nhiều cách sử dụng khác.

SQL:
SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name

Ví dụ bảng 1 là bảng giá trị cần tìm kiếm, bảng 2 là bảng tham chiếu.
table1.Column_name và table2.Column_name là cột chứa giá trị cần tìm kiếm
 
VLookup có thể dùng kiểu tìm gần đúng để tăng tốc. VLookup là tài sản riêng của Excel cho nên MS muons làm gì thì làm.
IN trong SQL thì tiêu chuẩn SQL chỉ bắt buộc kết quả, còn quy trình tra như thế nào các phần mềm tự làm. Tương tự như mấy bài hỏi về code VBA ở đây, chỉ có kết quả là bắt buộc. Code thì người viết code chú trọng chạy nhanh, kẻ chú trọng tổng quát nhiều tính năng.

Lệnh Exists đi xa vấn đề rồi. Tôi trả lời thì bạn sẽ hỏi tiếp, nó như sóng sông cả, lớp sau tiếp lớp trước, cả tháng sau cũng chưa kết thúc. Bạn tự tìm hiểu và thử đi nhé - thử cỡ chục lần, nhìn đủ khía cạnh rồi hãy hỏi tiếp.
Cảm ơn chú đã chỉ bảo, vấn đề lọc trùng của cháu được giải quyết từ các bài trước rồi nên để tránh đi xa cháu xin dừng có gì cháu tìm hiểu tiếp nếu có gì không hiểu cháu hỏi tiếp ạ.
Mình dùng Left Join, bạn google để có thể tìm hiểu thêm về Join trong SQL để biết thêm nhiều cách sử dụng khác.

SQL:
SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name

Ví dụ bảng 1 là bảng giá trị cần tìm kiếm, bảng 2 là bảng tham chiếu.
table1.Column_name và table2.Column_name là cột chứa giá trị cần tìm kiếm
Xin cảm ơn bạn nhiều...
 
Web KT

Bài viết mới nhất

Back
Top Bottom