PDA

View Full Version : Tìm kiếm một giá trị thỏa mãn nhiều điều kiện



handung107
08-06-06, 12:55 PM
Trong Excel có hàm Vlookup, Hlookup,..để tìm và cho ra một giá trị náo đó, những hàm này đơn thuần là tìm theo một điều kiện hay một giá trị.
Trong một CSDL các thông tim thường có liên hệ với nhau, đôi khi chúng ta cần tìm ra một giá trị thoả mãn n hiều điều kiện.
VD: Mình muốn tìm một nhân viên mà:
- Có gia đình
- Số con <3
- Số ngày công >=26

Các thông tin về gia đình, số con nằm trong DMNV, ngày công có trong sổ chấm công.

Với VD trên thì hình như các công cụ của Excel và các hàm không làm được?
(Autofilter và Advance Filter chỉ thực hiện trên một sổ -sheet))

Mình muốn gõ công thức vào một ô để nhận được tên nhân viên thoả mãn các điều kiện trên

Trước tiên xin chia xẻ với các bạn bài báo được đăng trên PCWord
Ví dụ chúng ta có một bảng dữ liệu, yêu cầu đặt ra là tìm điểm toán của một học sinh trong danh sách theo 2 điều kiện giới tính và tên. Vậy ta phải làm thế nào đây?


Tôi sẽ giới thiệu với các bạn một hàm tự tạo để làm việc này.

Trước tiên, bạn vào menu Tools\Macro\Visual Basic Editor (Alt + F11). Tại cửa sổ Microsoft Visual Basic, vào menu Insert\Module và nhập đoạn mã sau vào module vừa tạo.


Function FindTwoCondition(Table As Range, Val1 As Variant, _

Val1Occrnce As Integer, Val2 As Variant, Val2Col As Integer, ResultCol As Integer)

'Tabel la bang du lieu

'Val1 Dieu kien thu nhat

'Val1Occrnce gia tri thu n cua dieu kien trong cot

'Val2 dieu kien thu hai

'Val2Col cot thu n cua dieu kien thu 2

'ResultCol cot thu n can tim



Dim i As Integer, iCount As Integer

Dim rCol As Range



For i = 1 To Table.Rows.Count

If Table.Cells(i, 1) = Val1 And _

Table.Cells(i, Val2Col) = Val2 Then

iCount = iCount + 1

End If



If iCount = Val1Occrnce Then

FindTwoCondition = Table.Cells(i, ResultCol)

Exit For

End If

Next i

End Function



Sau khi đã nhập xong đoạn mã trên, bạn quay trở lại màn hình làm việc Excel bằng cách ấn Alt+Q. Bây giờ ta có thể sử dụng hàm vừa tạo như những hàm mà Excel đã hỗ trợ. Ví dụ tôi cần tìm Điểm Toán của người có tên là "Sơn" và có giới tính là "Nữ".

Trước tiên tôi lập bảng điều kiện, tại ô I6 tôi nhập công thức sau:


=FindTwoCondition($B$4:$F$13,I4,1,I5,3,4)


Trong đó:


- $B$4:$F$13: Vùng dữ liệu

- I4: Tên cần tìm

- 1: Tìm tên Sơn đầu tiên

- I5: Giới tính cần tìm

- 3: Số thứ tự của cột Giới tính trong vùng dữ liệu

- 4: Số thứ tự của cột Điểm Toán trong vùng dữ liệu


Kết quả sẽ trả về là 7. Chú ý ở đây hàm không phân biệt chữ thường chữ hoa.

Lâm Quang Bình

Binhlq77@yahoo.co.uk

Trích từ : http://www.pcworld.com.vn

handung107
08-06-06, 01:05 PM
Mình gửi file lên đây nhờ các bạn chỉ giúp.

P/S : Tạm thời, các bạn có thể liên hệ với BQT để có File

Cách 1- Lập công thức?
Cách 2- VBA ?

Mình nghĩ với cách 1 phải cố định số điều kiện thì mới làm được, còn cách 2 thì số điều kiện sẽ "động" hơn (có thể n điều kiện)?

Bằng VBA thì mình có thể sẽ làm được, nhưng lập công thức (cách 1) thì hiện nay chưa.

handung107
08-06-06, 01:08 PM
Theo em hiểu thì việc tổ chức các bảng cơ sở như trong file đính kèm của bác là bắt buộc(?). Nếu không, em có thể tạo một bảng phụ hoặc là gộp luôn cả 2 bảng vào làm 1. Xử lý sẽ rất đơn giản bằng Filter.
Còn nếu điều kiện lọc bắt buộc nằm trên nhiều bảng như vậy, em sẽ phải lọc điều kiện qua 2 bước:
Bước 1: Lọc điều kiện trên bảng chấm công
Bước 2: Lọc điều kiện trong bảng hồ sơ, kết hợp với mã tìm được ở bước 1.
Vấn đề sẽ đơn giản nếu tổ chức lại cơ sở dữ liệu đáp ứng được yêu cầu, mặc dù chưa được tối ưu lắm!
(Trong file đính kèm em gộp 2 bảng cơ sở dữ liệu làm 1, hơi thừa nhưng đáp ứng được yêu cầu thống kê)

handung107
08-06-06, 01:09 PM
Vấn đề của anh Tuân là tìm giải pháp từ công thức hay VBA để giải quyết chuyện của Querry. Nếu dùng công cụ truy vấn tin để tìm những giá trị thỏa mãn từ n Databse thì...
Ý tưởng của em là chôm 1 công cụ Querry nào đó, dùng VBA để điểu khiển.
Đồ chơi trong Excel kiểu này hình như là Ms Querry thì phải, nhưng điều khiển nó = VBA thì chịu

handung107
08-06-06, 01:11 PM
Cảm ơn bạn Cường

- Ghép bảng và dùng Filter, Advance Filter cũng được nhưng không ổn khi quản trị CSDL, không phải cứ có điều kiện thì lại thêm cột.

Có thể dùng công thức trong ô (=?) để nhận giá trị được không?

To Adam_tran :

- Dùng Query bàng dòng lệnh (VBA) có lẽ là giải pháp tốt. Nếu không rõ về Excel Query thì vẫn có thể có cách khác.

Cảm ơn và mong các bạn tiếp tục quan tâm!

handung107
08-06-06, 01:12 PM
Mình quy ước: Những các giá trị: 26, 3, 1 gọi là giá trị so sánh.
Còn những thứ như: gia đình, số con, số công của từng người là giá trị bị so sánh.
Cái này giống như số trừ và số bị trừ đấy hì hì....

Trước tiên, mình sẽ khởi tạo vài biến (nếu biết trước là sẽ có bao nhiêu giá trị so sánh) để chứa các giá trị so sánh:
đối với file của Mr Tuan, mình tạo 3 biến a, b, c. Mà cũng chỉ cần 2 biến là được bởi vì giá trị gia đình là 0 hoặc 1.

Đó là trường hợp chỉ có 3 thứ để so sánh, nếu phát sinh thêm nhiều thứ khác, mà không thể biết được sẽ phải tạo bao nhiêu biến thì không thể dùng biến như trên được, mà phải dùng mảng A[i...n]

Mỗi A[i] chứa một giá trị so sánh.

Mảng này mình khai báo nhỏ thôi khoảng 10 chẳng hạn.
Làm gì có ông nội nào so sánh nhiều điều kiện quá.

Để gán giá trị so sánh cho biến, mình dùng refedit,
Hoặc cho nó làm tham số truyền vào của thủ tục luôn.

Đến đây thì còn gì nữa đâu,
Dùng While hoặc Repeat để duyệt từ trên xuống dưới đến khi nào không còn nhân viên nào thì thôi. Hoặc tổng hợp số lượng nhân viên trước sau đó dùng For.

PP1: kiểm tra từng người.
Trước tiên so sánh số công, nếu số công OK, thì so sánh đến gia đình, nếu có gia đình, thì so sánh tiếp số con.

Nếu trong công ty có ai mà chưa có gia đình, mà vẫn có con thì phải phải kiểm tra số con. hì hì.....

PP2: Kiểm tra từng Sheet.
Trước tiên ở sheet chấm công, tìm ra những người thỏa mãn điều kiện về số công. Lưu lại mã nhân viên thỏa điều kiện.

ở sheet Hồ sơ, tìm ra những người thỏa mãn về số con, và gia đình. Lưu lại mã nhân viên thỏa điều kiện.

Sau đó so sánh 2 kết quả tìm được ở 2 sheet, chọn ra những mã nhân viên nào mà có mặt ở cả 2 kết quả trên.

handung107
08-06-06, 01:13 PM
Nếu ngại đụng đến MS Query, cách mà em vẫn thường làm đối với sổ kế toán:
- Tạo ra một vùng điều kiện trong đó các cột phải tương ứng với bảng cần Filter (trong trường hợp này em sẽ chọn bảng Hoso là bảng filter vì nó có nhiều điều kiện hơn)
- Lọc bảng có điều kiện ít trước: ở đây bảng Chamcong chỉ có một điều kiện - em lọc bảng này trước để tìm ra những Mã thoả điều kiện
- Copy mã tìm được vào bảng điều kiện sau đó thực hiện lọc bảng Hoso
Em nghĩ cách này không cần dùng vòng duyệt nào sẽ nhanh hơn và đáp ứng được mọi điều kiện, kể cả việc mở rộng thêm điều kiện!

handung107
08-06-06, 01:14 PM
Tiện thấy bài này có những ý hay, em xin gửi các bác một các dùng ADO + Query với Excel theo đó em trực tiếp dùng ADO kết nối với một bảng tính đang mở để cấp dữ liệu cho form thông qua query mà không dùng đến range.

Cách tiếp cận thì không có gì mới, tôi xin giới thiệu cách này:
+ Coi Excel như là một nguồn CSDL. Thực hiện kết nối đến bảng tính Xls dung Jet Isam 4.0 với ADODB.
+ Dùng các câu lệnh truy vần SQL bình thường trên bảng tính với đối tượng recordset.
Ví dụ:
Select * from [Sheet1$] where ….;
Và trả về kết quả là đối tượng Recordset.
Như thế việc dung đến JOIN và UNION cũng không khó đúng không.
Tương tự các bạn cũng có thể dung để lọc trên nhiều bản.
Tuy nhiên, với nhiều điều kiện (n điều kiện) như yêu cầu của Tuân, thì bản thân SQL cũng đâu cho phép điều kiện quá phức tạp, vì thế ta cần xử lý việc đặt điều kiện sao cho năng động. VÍ dụ tách điều kiện phức hợp….

handung107
08-06-06, 01:16 PM
Bây giờ mới để ý cái nội dung của đề tài này.

Về vấn đề Dynamic Filter, mọi người cần quan tâm đến mấy vấn đề sau:
- List các đối tượng cần lọc dữ liệu (ĐỐI TƯỢNG LỌC) cùng với các thuộc tính của đối tượng. Như vậy, công cụ Dynamic Filter có thể áp dụng cho mọi đối tượng của hệ thống (như: Khách hàng, Nhà cung cấp, Nhân viên, Giao dịch, v.v... --> Any objects if you want)
- List các đối tượng khác quan hệ với đối tượng đó (ĐỐI TƯỢNG QUAN HỆ) cùng với các thuộc tính của đối tượng quan hệ (identify and non-identify tables)
- List các toán tử so sánh, các toán tử logic, cùng các dấu {}, [], ()
- Tạo 1 công cụ cho phép visualize cách thức lập câu hỏi lọc. Tất nhiên ko thể hiện cho người dùng kiểu: SELECT * FROM tbl_NHANVIEN WHERE ID = XYZ AND EmployeeName Like "Ha*" được vì đó chỉ là cách hiển thị cho dân lập trình thôi. Vậy công cụ đó phải cho phép kiểu như: Hiển thị danh sách <Nhân viên> với các điều kiện: Mã nhân viên là XYZ và Tên nhân viên bắt đầu bằng "Ha". Từ những điều kiện được chọn 1 cách visualize đó thì công cụ phải tự parse sang PL SQL và thực hiện nó. Các điều kiện của câu hỏi nên thể hiện dưới dạng tự nhiên, tốt nhất là dưới dạng Tree cho dễ nhìn.
- Kết quả của việc Lọc có thể hiển thị dưới nhiều dạng format khác nhau như một mẫu báo cáo nào đó (theo template), dạng danh sách, v.v... và có thể export ra nhiều loại file như PDF, HTML,...
- Công cụ Lọc phải cho phép lưu trữ các câu hỏi đã được lập vào CSDL cho từng người sử dụng.
- v.v...
(Thôi, khéo lại thành yêu cầu thầu thì các bác lập trình chửi tôi thì chết)

handung107
08-06-06, 01:18 PM
Nếu lập công thức để đáp ứng n điều kiện mình thấy rất khó và chưa có cách.
Bạn có thể đưa ra để mọi người tham khảo không?
Ở đây chúng ta cùng bàn để cho ra một giải pháp cùng thuật toán tốt nhất trên Excel.


Trích nguyên văn:
Nguyên văn bởi adam_tran
...để giải quyết 1 vấn đề của mình thì mò hoài cũng ra. Nhưng tôi nghỉ "tham vọng" của anh Tuân là tạo ra 1 công cụ để tổng hợp hay so sánh các bảng CSDL của Excel qua một hay vài "key column" tương tự so sánh các table qua công cụ querry bên Access, từ đó tạo ra 1 CSDL mới (1 sheet mới) thỏa mãn những điều kiện nào đó.

Đúng vậy bác Adam sờ mít đã thấy tham vọng của mình, nhưng để làm vậy thật khó! Tham vọng này mình sẽ bạn trên một topic khác, còn ở topic này mình muốn có một hàm DFind(criteria)


Trích nguyên văn:
Nguyên văn bởi Đào Việt Cường
...Em cứ hình dung thấy một công cụ filter to report kiểu như A-Excel, rất chuyên nghiệp! Kiểu này chắc nhờ anh 2 chia sẻ cách làm - nhất là cái màn hình visible mà được ứng dụng làm màn hình tìm kiếm và tra cứu thì thật là tuyệt!

Bật mí với Cường là chức năng "Lọc chứng từ đã ghi..." trong A-Excel (filter to report) được thiết kế hoàn toàn là EXCEL dựa trên cơ sở thiết kế A-Tools không dùng ADO, DAO, ODBC,...Trong phiên bản mới (4.*) sẽ có công cụ đặt quan hệ và truy vấn các Sheet/Range->báo cáo như kiểu Access nhưng nó là Excel.

Mình đã đọc tất cả các giải pháp các bạn đưa ra và thấy có hướng giải quyết, nhưng vẫn mong các bác cụ thể hóa hơn bằng công thức cụ thể hay vài đoạn code.

Tập hợp các hàm mà MS Excel đưa ra rất phong phú, đặc biệt nhóm hàm Database (DSUM, DCOUT,DMAX,...D*) giải quyết việc thống kê với n điều kiện rất hữu hiệu, với công thức mảng MS Excel cũng đã cho người dùng như thêm một đôi tay.

Nhưng dù sao vẫn chưa thỏa lòng tham của mình!
+ Trong nhóm hàm Database D*(database,field,criteria), vùng điều kiện (hay còn gọi là vùng tiêu chuẩn) criteria chỉ giới hạn các cột so sánh trong một Sheet/Table.
+ Trong nhóm hàm Lookup (Vlookup, Hlookup, Lookup,...) chỉ tìm trên một giá trị không có điều kiện?

Đây là hai vấn đề chúng ta rất cần và nếu MS Excel mà có thì càng tuyệt vời hơn. MS không nghĩ hay nghĩ nhưng không làm? Hay chúng ta chưa khai thác được hết?

Từ những mặt còn thiếu của MS Excel, tham vọng của mình là:
+ Tạo ra nhóm hàm thống kê D**, chức năng tương tự như D* nhưng criteria mở rộng cho nhiều Sheet trong CSDL. Mục đích này sẽ làm trên topic khác.

+ Tạo ra hàm tìm kiếm DFind(criteria), chức năng để tìm và cho ra giá trị theo nhiều điều kiện.

(criteria gọi là vùng điều kiện hay vùng tiêu chuẩn)


Nếu thành công thì mỗi khi tìm kiếm theo nhiều điều kiện (Multsheet) chúng ta chỉ cần gõ =DFind(A1:Bn) là Ok.

Ý tưởng về cách dùng và thiết kế hàm DFind của mình như thế này:

+ Cấu trúc hàm DFind(criteria).
+ Cách dùng. Người dùng cần có một vùng (mảng) điều kiện VD như bắt đầu từ dòng 1, cột A là cột so sách; cột B là giá trị so sách. Như vậy, mỗi điều kiện là một dòng, A1:Bn là vùng có n điều kiện.
+ Thiết kế hàm DFind trên VBA:
Có 2 lựa chọn
1- Dùng kỹ thuật SQL
2- Không dùng kỹ thuật SQL (nếu không biết)

Cột so sánh:
Ngôn ngữ SQL thường nhận biết cột A là của sổ nào nó thường dùng dấu "!" hay dấu "." như là Hoso!Gia đình (cột gia đình trong sổ hoso).
Như vậy cột so sánh ta cần phải ghi rõ: Chamcong!Số công; Hoso!Gia đình; Hoso!Số con. Như thế thì hàm DFind mới có cơ sở để biết những Sheet/Rang/Table nào cùng tham gia điều kiện.

Cột giá trị so sánh
Dúng ra chúng ta phải có một cột "phép so sánh" để vào các phép SS: >, <, >=, <>... Nhưng để đơn giản cho người dùng cũng như giống cấu trúc Criteria của nhóm hàm Database (D*), trước mỗi giá trị so sánh cần đặt các phép so sánh như >=26; <3; =1.

Nhận biết điều kiện And và Or (cái này có thể làm sau)
Các điều kiện trên cùng một cột ở các dòng khác nhau sẽ được hiểu là điều kiện kết nối And, các điều kiện trên cùng một dòng ở các cột khác nhau sẽ được hiểu là điều kiện kết nối Or.

Trên là sơ lược để tạo hàm DFind theo hướng lập trình, còn bằng công thức thì mình chưa có hướng giải quyết. Theo cách nghĩ chủ quan của mình thì công thức không thể làm động được?

Đến bây giờ mình thấy vấn đề này khó hơn những gì nghĩ ban đầu!

handung107
08-06-06, 01:20 PM
Criteria1 As Object, Criteria2 As Object, được không Bác Tuân?

--------------------------------------------------------------------------------


Trích nguyên văn:
Nguyên văn bởi Tuanktcdcn
Nếu lập công thức để đáp ứng n điều kiện mình thấy rất khó và chưa có cách.Mình muốn có một hàm DFind(criteria) !

'Hàm này lấy KQ từ 2 sheets, 1 là hồ sơ HS cấp 2 (chỉ 13 Rec.)
'
' =TFIND( HoSo, DSo)
' =TFIND( HoSo, DSo, 0)
' =TFIND( HoSo, DSo, 1)
' =TFIND( HoSo, DSo,2)
' Ở đây HoSo là tên vùng thuộc sheet hồ sơ; DSo là tên vùng thuộc sheets DS điểm TB 3 môn thi

Function TFIND(HSo As Object, Diem As Object, Optional Loai As Byte)
Dim KQua(2), iHang As Byte
For iHang = 2 To 13
1 If HSo.Cells(iHang, 4) = 0 Then
2 KQua(0) = 1 + KQua(0)
3 If HSo.Cells(iHang, 5) < 8 Then
4 KQua(1) = 1 + KQua(1)
5 If Diem.Cells(iHang, 4) >= 24 Then KQua(2) = 1 + KQua(2)
6 End If: End If
Next iHang
TFIND = KQua(0)
Select Case Loai
Case 1
7 TFIND = KQua(1)
Case 2
8 TFIND = KQua(2)
End Select
End Function


Function PTBac2(aA As Double, bB As Double, cC As Double)
Dim Temp( 1 To 3): Dim DelTa As Double

DelTa= (bB ^ 2) - (4 * aA * cC)
Select Case DelTa
Case Is < 0
Temp(1) = "Voâ nghieäm"
Temp(2) = "": Temp(3) = " "
Case 0
Temp(1) = "Moät nghieäm:"
Temp(2) = -bB / ( 2 * aA): Temp(3) = ""
Case Else
Temp(1) = "Hai nghieäm:"
Temp(2) = (-bB + Sqr( DelTa)) / ( 2 * aA)
Temp(3) = (-bB - Sqr( DelTa))/(2 * aA)
End Select
PTBac2 = Temp
End Function
Chúng ta kiểm tra hàm này Tại Sheet . . . = cách:

Chọn dãy ô D47:F47 từ D47 (số lượng ô tuỳ thuộc vô số lượng biến được trả về!) & nhập =PTBac2( E42 , E43, E44) Vì là hàm

mảng nên ta phải kết thúc = tổ hợp 3 phím CTRL+SHIFT+ENTER

handung107
08-06-06, 01:22 PM
Theo mình biết thì từ Excel 2K trở đi hàm tự tạo có thể trả về không chỉ 1 giá trị mà có thể trả về mảng giá trị

Function PTBac2(CacHeSo As Object)
Dim Temp(1 To 3): Dim DelTa
Dim HeSo(1 To 3)
For DelTa = 1 To 3
2 HeSo(DelTa) = CacHeSo.Cells(1, DelTa)
Next DelTa
DelTa = (HeSo(2) ^ 2) - (4 * HeSo(1) * HeSo(3))

Select Case DelTa
Case Is < 0
7Temp(1) = "Voâ nghieäm"
8Temp(2) = "": Temp(3) = " "
Case 0
9Temp(1) = "Moät nghieäm:"
10Temp(2) = -(HeSo(2)) / (2 * HeSo(1)): Temp(3) = ""
Case Else
11Temp(1) = "Hai nghieäm:"
12Temp(2) = (-HeSo(2) + Sqr(DelTa)) / (2 * HeSo(1))
13Temp(3) = (-HeSo(2) - Sqr(DelTa)) / (2 * HeSo(1))
End Select
PTBac2 = Temp
End Function

Vì là hàm mảng nên ta phải kết thúc = tổ hợp 3 phím CTRL+SHIFT+ENTER

handung107
08-06-06, 01:25 PM
Trích nguyên văn:
Nguyên văn bởi Tuanktcdcn
Topic này chúng ta sẽ có một hàm DFind() hay một công cụ gì đó để tìm giá trị trên nhiều vùng dữ liệu. Mình mong tiếp tục nhận được sự đóng góp của các bạn!
Hôm nay mình vừa đưa lên hàm =DFIND() cho mọi người tham khảo
Hàm có dạng:
=DFIND( Sh1 As Object, Sh2 As Object, Lop As String)
để tìm & trả về mãng kết quả thoả 3 điều kiện (trong đó 2 Đ/k cài sẵn);

Còn Lop thì chọn từ ComBoBox;
http://webketoan.com/forum/showthread.php?t=17161


Lời giải tại: http://www.giaiphapexcel.com/forum/showpost.php?p=58&postcount=6

Đấy là hàm người dùng mà TuanKTCDCN! Bạn thử đi nha, là hàm mãng:
tại ô O2 bạn quét chọn lấy 4 cột & 30 hàng rồi nhập công thức sau
=Loc2Bang(A2:F999,'S2'!A2:B999,K1)
/(/hớ kết thúc = tổ hợp 3 fím nha!
Bạn thừa sức hiểu rằng đây là hàm mãng tự tạo mà, phải ?

SA_DQ
08-06-06, 03:01 PM
In Excel, tham vọng của mình là:
+ Tạo ra nhóm hàm thống kê D**, chức năng tương tự như D* nhưng criteria mở rộng cho nhiều Sheet trong CSDL.
Nếu thành công thì mỗi khi tìm kiếm theo nhiều điều kiện (Multsheet) chúng ta chỉ cần gõ =DFind(A1:Bn) là Ok.
Dự án sẽ như sau:
=DFIND( Rng1 As Range; Rng2 As Range; Rng3 As Range; Rng4 As Range)
Mình đã công bố hàm =DFIND(Sh1 As Object, SH2 As Object) tại WEBKeToan.com (Ver 1.1)
sắp tới sẽ là ver 1.2 có dạng: =DFIND( Sh1 As Object, Sh2 As Object, StrCh As String)
Xin các thành viên góp ý thêm!

hoakttv
10-08-07, 09:52 AM
có bác nào biết sử dung tính mô hình TANK (ứng dụng Solver) không? chỉ giùm với