Chia sẻ Code Import/Export Data từ Excel đến Excel
Hi Các Bác,
Sau khi sưu tầm và chỉnh sửa code, hôm nay mình xin tổng hợp lại code dùng để Nhập và Xuất (Import / Export) dữ liệu từ 1 Excel đến file Excel khác.1. Code Nhập dữ liệu từ file excel khác, không cần mở file.
Code này sưu tầm từ Bác nmhung49:
Chú ý: nếu file bạn liên kết đến mà không đặt Password thì phần Password trong code để trống nha.
Sub connect_file() Dim fname On Error Resume Next Application.ScreenUpdating = False Application.Calculation = xlCalculationManual fname = Application.GetOpenFilename("Excel Files (*.xls*), *.xls") With Workbooks.Open(fname, , , , "password") ' PW can dat trong dau ngoac kep, neu ko co password thi de trong Sheets("Sheet1").Range("A4:D20000").Copy ThisWorkbook.Sheets("Sheet2").Range("A4") .Close False End With Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomatic End Sub2. Code Xuất dữ liệu từ ra file excel khác.
Code này mình tham khảo nhiều nơi và viết lại, do trình độ VBA yếu kém, nên chỉ viết cho nó chạy thôi, không phải là Code hay.
Sub ExportRangetoFile() Dim wb As Workbook Dim saveFile As String Dim WorkRng As Range On Error Resume Next xTitleId = "ExportDataExcelToExcel" Set WorkRng = Application.Selection Set WorkRng = Application.InputBox("Range", xTitleId, WorkRng.Address, Type:=8) Application.ScreenUpdating = False Application.DisplayAlerts = False Set wb = Application.Workbooks.Add WorkRng.Copy wb.Worksheets("Sheet1").Paste saveFile = Application.GetSaveAsFilename(fileFilter:="Excel files (*.xls*),*.xls") wb.SaveAs Filename:=saveFile, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False wb.Close Application.CutCopyMode = False Application.DisplayAlerts = True Application.ScreenUpdating = True End Sub2 code này bạn bỏ vào Module và chạy nhé.
Nếu các Bác có code hay hơn thì chia sẽ để mình học hỏi thêm nha.
Theo điều kiện lý tưởng thì một tiện ích "đọc" dữ liệu phải có tuỳ chọn đọc một copy của dữ liệu lúc kết nối connection. Khi ấy nó có thể đọc mà không cần mở (nó mở cái copy trong cache của nó). Nhưng tôi chưa đọc được tài liệu này cho nên không biết làm, và cũng chưa chắc điều kiện lý tuởng này đã hiện hữu.
Làm thử 1 sub mở connecion với một file, treo đó, khoan đóng connection. Qua Win Explorer xoá thử file sẽ thấy nó báo là file đang bị mở. Trở lại sub và chạy qua phần đóng connection. Trở lại Win Explorer để Retry sẽ thấy nó cho xoá.
Nhưng hãy thử với SQLServer hay là gì đó ta có thể mở hay xóa bình thường cho dù đã được kết nối vào hay chưa.
Khi bạn tạo kết nối thì ADO liên hệ với CSDL này để xin kết nối. Bởi vậy có cái phần "Provider".
Những CSDL hạng gộc (như SQL Server chẳng hạn) thì chúng có sẵn mấy cửa ngõ cho các phần mềm phác như ADO kết nối vào. Nếu qua Internet thì giao diện do máy chủ (DBase Server) phối hợp với OLEDB và SQL Server mà tạo giao diện cho ADO. Lưu ý là ADO không thể tự ý đi thẳng vào vùng chứa dữ liệu. SQL Server phải đang chạy và phải cho phép kết nối. Tất cả những gì VBA+ADO truy cập được từ bảng nào của SQL Server đều do SQL Server cung cấp. Người chủ CSDL đã định sẵn quyền hạn và pham vi truy cập cho mỗi loại kết nối.
Những loại khác (như Excel chẳng hạn) thì ADO phải sử dụng cái cổ máy JET hoăc ACCESS để truy cập file. Nếu qua Internet thì file phải nằm trong các thư mục cho phép "share" (luật của mạng: nếu không có share thì không thể nào truy cập). Trong trường hợp này, ADO sẽ đi thẳng vào vùng chứa dữ liệu của file (nếu file không có password). Vì file chỉ là một hệ thống dữ liệu phẳng cho nên ADO sau khi kết nối xong, có toàn quyền muốn làm gì thì làm.
Theo điều kiện lý tưởng thì một tiện ích "đọc" dữ liệu phải có tuỳ chọn đọc một copy của dữ liệu lúc kết nối connection. Khi ấy nó có thể đọc mà không cần mở (nó mở cái copy trong cache của nó). Nhưng tôi chưa đọc được tài liệu này cho nên không biết làm, và cũng chưa chắc điều kiện lý tuởng này đã hiện hữu.
Nếu tập tin chưa được mở thì nó chỉ tồn tại trên đĩa, làm gì có trong RAM trong cache nào?
Làm thử 1 sub mở connecion với một file, treo đó, khoan đóng connection. Qua Win Explorer xoá thử file sẽ thấy nó báo là file đang bị mở. Trở lại sub và chạy qua phần đóng connection. Trở lại Win Explorer để Retry sẽ thấy nó cho xoá.
Bạn cũng có thể viết code như thế, chuyên nhỏ. Có nhiều kiểu.
Sau khi nhấn Button1 thì không thể xóa được tập tin "C:hichic.txt", thậm chí đúp chuột cũng không mở được. Notepad báo là: "Tôi bó tay". Sau khi nhấn Button2 thì tập tin được đóng và xóa được hichic.txt
Private Const GENERIC_READ As Long = &H80000000
Private Const OPEN_EXISTING As Long = 3
Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80
Private Const PAGE_READWRITE As Long = &H4
Private Const FILE_MAP_ALL_ACCESS As Long = &HF001F
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Declare Function CreateFile Lib "kernel32.dll" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function CreateFileMapping Lib "kernel32.dll" Alias "CreateFileMappingA" (ByVal hFile As Long, ByRef lpFileMappigAttributes As SECURITY_ATTRIBUTES, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "kernel32.dll" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32.dll" (ByRef lpBaseAddress As Any) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private hFile As Long, hMapFile As Long, lpMapAddress As Long
Sub Button1_Click()
Dim sa As SECURITY_ATTRIBUTES
hFile = CreateFile("c:hichic.txt", GENERIC_READ, 0, sa, OPEN_EXISTING, _
FILE_ATTRIBUTE_NORMAL, 0)
hMapFile = CreateFileMapping(hFile, sa, PAGE_READWRITE, 0, 0, "MyFileMappingObject")
If hMapFile <> 0 Then
lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0)
End If
End Sub
Sub Button2_Click()
UnmapViewOfFile ByVal lpMapAddress
CloseHandle hMapFile
CloseHandle hFile
End Sub
www.giaiphapexcel.com/diendan/threads/chia-s%E1%BA%BB-code-import-export-data-t%E1%BB%AB-excel-%C4%91%E1%BA%BFn-excel.93282/
Hi Các Bác. Cảm ơn các Bác đã tranh luận.
Vì 2 câu "không cần mở file" mà các Bác cải nhau ghê quá, vì trong lĩnh vực VBA này, em là người mới level 0.5. Do đó em thấy không cần mở file đó lên thì em nói ko cần mở file theo đúng nghĩa đen, còn các Bác là Cao thủ rồi sẽ có nhìn nhận khác. kiểu như Bác học và học sinh tiểu học.Mục đích em post lên 2 phần này để giúp các bạn có yêu cầu đơn giản, có thể áp dụng theo code của em. Còn yêu cầu cao hơn thì nhờ tới các Bác vậy.
Đây là diễn đàn học hỏi. Người có nhu cầu này, kẻ có nhu cầu khác. Nếu không có những bàn luận rộng thì tôi vào đây là thừa à? Tất cả những nhu cầu đơn giản chỉ 1 người viết code là đủ. Thậm chí hầu hết mấy cái hàm đơn giản đều đã có rồi, chỉ chịu khó truy tìm (seacrh) là ra hết.
Nhưng bạn đã muốn nói chuyện theo code của bạn thì tôi nói chuyện theo code của bạn.
Code này chưa đạt đến trình độ "đơn giản, có thể áp dụng theo". Trước mắt là:
Hi Các Bác,
Sau khi sưu tầm và chỉnh sửa code, hôm nay mình xin tổng hợp lại code dùng để Nhập và Xuất (Import / Export) dữ liệu từ 1 Excel đến file Excel khác.1. Code Nhập dữ liệu từ file excel khác, không cần mở file.
Code này sưu tầm từ Bác nmhung49:
Chú ý: nếu file bạn liên kết đến mà không đặt Password thì phần Password trong code để trống nha.
Sub connect_file() Dim fname On Error Resume Next Application.ScreenUpdating = False Application.Calculation = xlCalculationManual fname = Application.GetOpenFilename("Excel Files (*.xls*), *.xls") With Workbooks.Open(fname, , , , "password") ' PW can dat trong dau ngoac kep, neu ko co password thi de trong Sheets("Sheet1").Range("A4:D20000").Copy ThisWorkbook.Sheets("Sheet2").Range("A4") .Close False End With [B][COLOR=#ff0000]Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomatic [/COLOR][/B]End Sub2. Code Xuất dữ liệu từ ra file excel khác.
Code này mình tham khảo nhiều nơi và viết lại, do trình độ VBA yếu kém, nên chỉ viết cho nó chạy thôi, không phải là Code hay.
Sub ExportRangetoFile() Dim wb As Workbook Dim saveFile As String Dim WorkRng As Range On Error Resume Next xTitleId = "ExportDataExcelToExcel" Set WorkRng = Application.Selection Set WorkRng = Application.InputBox("Range", xTitleId, WorkRng.Address, Type:=8) Application.ScreenUpdating = False Application.DisplayAlerts = False Set wb = Application.Workbooks.Add WorkRng.Copy wb.Worksheets("Sheet1").Paste saveFile = Application.GetSaveAsFilename(fileFilter:="Excel files (*.xls*),*.xls") wb.SaveAs Filename:=saveFile, FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False wb.Close [B][COLOR=#ff0000]Application.CutCopyMode = False Application.DisplayAlerts = True Application.ScreenUpdating = True [/COLOR][/B]End Sub2 code này bạn bỏ vào Module và chạy nhé.
Nếu các Bác có code hay hơn thì chia sẽ để mình học hỏi thêm nha.
Cái phần tôi tô đỏ là code nguy hiểm. Hàm này theo luật lập trình thì được liệt vào loại "không tái hoàn" (non-reentrant). Lý do là nó tự ý đổi trạng thái (modes) của application.
Nếu viết đứng đắn thì lúc đầu hàm, những trạng thái này phải được ghi (saved) lại và cuối hàm thì hoàn nguyên cho chúng.
Em vẫn chưa rõ lắm, Nếu vậy thì em cần thay đổi Code thế nào đây anh?
Theo nguyên tắc, một hàm (hay phương thức) chỉ chỉnh sửa những gì thuộc về công việc của nó mà thôi. Những gì không phải là công việc của nó nhưng vì lý do nào đó nó phải tạm sửa thì trước khi thoát ra, nó có bổn phận phải trả lại cho người ta.
Trong hàm connect_File trên, đầu hàm đặt:
Application.ScreenUpdating = False
Như vậy là nó tam mượn cái thuộc tính ScreenUpdating của Application để làm gì đó.
Cuối hàm đặt lại:
Application.ScreenUpdating = True
Mục đích nó nghĩ: "Ê Application, tớ trả cái thuộc tính ScreenUpdating về cho cậu đây. Thế là hết nợ nần nhau nhé!"
Đúng không?
Bạn nào nghĩ đúng là cả đoan. Bạn không bao giờ nghĩ là có lúc Application nó phản đối: "Khoan đã, cái cậu connect_File kia. Lúc cậu mượn tôi, ScreenUpdating nó là False. Lúc cậu trả tôi nó là True. Cậu làm việc như thế mà xem được à?"
connect_File: "Ơ tôi cứ ngỡ lúc nào nó cũng là True cơ"
Application: "Ngỡ? Làm việc mà nói chuyện ngỡ? Lúc vừa mượn được tại sao cậu không xem trước?"
Ví dụ thực tiễn:
Hàm LamGiDo gọi hàm connect_File
Sub LamGiDo()
Application.ScreenUpdating = False
…
connect_File
… ' LamGiDo bị hẫng ở đây, bởi vì connect_File sửa Application.ScreenUpdating thành True
' màn hình có thể sẽ giật tưng bừng hoa lá ở đây thì là do lỗi của ai?
…
End Sub
Thực sự là bây giờ không biết là nên hay không việc sử dụng application.sreenupdating. Mình có đọc cuốn vba trong excel cải thiện và tăng tốc của tác giả Kyo thì thấy tác giả khuyên nên sử dụng. Giờ đọc bài của anh vietMini lại bảo đây là code nguy hiểm.
Vậy mong anh VietMini và các bạn trên gpe cho biết là có nên sử dụng application.sreenupdating hay không ạ? Trong trường hợp nào thì nên dùng? Th nào thì không nên dùng.
Khi tôi nhắc tới vấn đề, tôi đã có gợi ý trong câu "Lúc vừa mượn tại sao cậu không xem trước?"
Rất đơn giản. Trước khi đụng chạm đến nó, chỉ việc dùng một biến copy lại trị của Application.ScreenUpdating, xài xong rồi trả về đúng trị ấy. Hết.
Cách thức và quy luật nằm trong những luật căn bản khi viết hàm/phương thức. Đáng ra những cái căn bản này các bạn phải tìm hiểu trong giai đoạn "căn bản cho người mới học VBA". Nhưng hình như các bạn lại thich học những cái công việc văn vẻ như tô màu, kẻ hàng, … hơn.
Code có 2 giai đoạn thử trước khi được chấp nhận. Giai đoạn thứ nhất là thử nó một mình – tức là cho nó chạy độc lập trong điều kiện không liên quan gì đến những code khác. Và giai đoạn thứ hai là thử nó trong mõi trường chung với những thức khác – tức là ở trong trường hợp có những điều kiện rắc rối khác, vì dụ như file đang bị người khác mở, vân vân.
Trong trường hợp của đề bài này, hàm sửa bất kỳ một thuộc tính nào của Application thì cũng phải đề phòng trường hợp code gọi nó cũng cần thuộc tính ấy.
Loại code chỉ viết chạy một lần cho xong công việc rồi thôi thì chỉ cần đạt giai đoạn đầu mà không cần giai đoạn thứ hai. Tôi không có đọc tài liệu gì đó bạn đề cập ở trên cho nên không biết tác giả nói những gì, và tác giả có phải chỉ nói chuyện trong phạm vi của loại code "chạy một lần" này hay không. Tuy nhiên nếu tác giả nói về việc chỉnh thuộc tính của Application để tăng tốc mà không nhắc đến việc bảo vệ các thuộc tính này thì đó là một điều thiếu sót trầm trọng.
Trong đề bài này, chủ thớt đem hàm lên gọi là "chia sẻ" thì code phải được coi là loại hoàn chỉnh, bắt buộc phải thử trong mọi điều kiện. Tức là phải đạt đủ hai giai đoạn.
Thực sự là bây giờ không biết là nên hay không việc sử dụng application.sreenupdating. Mình có đọc cuốn vba trong excel cải thiện và tăng tốc của tác giả Kyo thì thấy tác giả khuyên nên sử dụng. Giờ đọc bài của anh vietMini lại bảo đây là code nguy hiểm.
Vậy mong anh VietMini và các bạn trên gpe cho biết là có nên sử dụng application.sreenupdating hay không ạ? Trong trường hợp nào thì nên dùng? Th nào thì không nên dùng.
Ý người ta nói rằng: Dù bạn dùng code gì đi chăng thì cũng chú ý các thiết lập sẵn trong Excel, đừng tự ý thay đổi thiết lập của người khác.
Ví dụ: Vì bạn muốn ẩn thanh Formula nên đã dùng code
Application.DisplayFormulaBar = False
Và bạn nghĩ rằng sau khi chạy xong chương trình thì bạn sẽ cho hiện thanh Formula trở lại bằng code
Application.DisplayFormulaBar = True
Cũng tốt! Nhưng nhà lập trình chuyên nghiệp sẽ không làm vậy. Điều đầu tiên họ sẽ đọc trạng thái của thanh Formula xem nó đang ẩn hay hiện để mai này chạy code xong thì trả nó về như trước khi chạy code
Lưu ý rằng: trả thanh Formula về trạng thái trước khi chạy code nó khác với cho hiện thanh Formula nha, tức thanh Formula thế nào thì trả về như vậy. Ai biết được có tay nó đó dùng Excel và luôn thích ẩn thanh Formula thì sao? Bạn cho hiện Formula lên ở cuối code sẽ khiến người ta bực mình (chương trình quỷ quái gì "phá" đồ của tôi vậy?)
Với các đoạn code thuộc dạng "nguy hiểm" như đã đề cập ở trên thì cũng nên làm thế
Thật ra ta luôn dùng
Application.ScreenUpdating =False
ở đầu code và
Application.ScreenUpdating =True
ở cuối code. Hoặc:
Application.EnableEvents = False
ở đầu code và
Application.EnableEvents = True
ở cuối code. Hoặc
Application.DisplayAlerts =False
ở đầu code và:
Application.DisplayAlerts =True
ở cuối code. vân.. vân.. và.. mây.. mây.. cũng không có vấn đề gì vì ta tin đến 90% các trạng thái ấy luôn được thiết lập mặc định = TRUE trước rồi, nhưng còn 10% "bất ngờ" như thằng cha "dở hơi" kia muốn khác thì sao?
Tóm lại:
– Muốn học code vửa đủ xài cho công việc thì sao cũng được. Bạn không cần quan tâm mấy điều này
– Muốn học code theo hướng chuyên nghiệp thì nên… nghĩ xa hơn một chút
Vậy thôi!
Qua 2 bài giải thích cặn kẽ của thầy và anh VietMini em đã hiểu rõ hơn bản chất của các câu lệnh application….. rồi ạ! Trước giờ như thầy ndu đã nói em luôn nghĩ rằng các trạng thái đó nó luôn mặc định bằng TRUE cơ. Tai hại quá! Cảm ơn thầy ndu và anh VietMini nhiều nhiều ạ!
P/S: Em xin phép BQT chen ngang topic này 1 chút ạ. Chẳng là hôm vừa rồi em có đọc Topic về vòng lặp For…next của thầy ptm0412 thấy rất hay và bổ ích đặc biệt là em thấy thầy ndu có rất nhiều câu trả lời nhanh, em rất nể. Mấy hôm vừa rồi anh ChanhTQ có mở topic "Bài tập VBA cho người mới bắt đầu[phần 2], vậy em mong nếu thầy ndu nếu rảnh thì thầy có thể ra 1 số đề bài tập ở mức độ "cho người mới bắt đầu" để các thành viên mới như bọn em làm được không ạ. Tại sao em lại nhờ đích danh thầy bởi em thấy bản thân thầy là 1 thành viên tự học tự tìm tòi và rất thành công nên em nghĩ với những kinh nghiệm về việc tự học của thầy thì những bài tập thầy ra sẽ phù hợp cho những người cũng tự học như chúng em hơn! Cảm ơn thầy!
Thì thực chất nó luôn =TRUE theo mặc định mà. Ý tôi muốn nói có khi một người dùng nào đó lại thiết lập chúng = FALSE theo nhu cầu sử dụng (luôn ẩn thanh Formula chẳng hạn) và chúng ta không có quyền thiết lập chúng =TRUE ở cuối code (hiện thanh Formula chẳng hạn)—> Người ta sẽ rất ghét dùng chương trình của ta và họ sẽ cho rằng chúng ta đang… "phá".
Hầu hết những code các bạn viết ra đều được dùng để chạy cho xong việc. Cho nên mặc định như vậy cũng chả chết thằng Tây nào. Chính tôi khi viết code "chạy một lần" cũng lười biếng, cuối code cho nó bằng True tuốt luốt. Nhưng cần lưu ý ở 2 điểm:
1. Đó là môi trường của tôi. Tôi muốn thế nào thì mặc xác tôi
2. Tôi chỉ làm thế khi code không phải là một hàm tiện nghi, được viết để code khác gọi.
Trường hợp của code connect_file rõ ràng là một hàm tiện nghi.
Code A cần mở file nên gọi hàm tiện nghi connect_file. Trước đó, A cũng cần tăng tốc nên cũng đã tạm ngưng ScreenUpdating, nhưng sau khi gọi mở file xong thì A bị mất điều kiện tăng tốc.
Như vậy, phải chăng A trước khi gọi connect_file thì phải tìm hiểu xem tiện nghi này có đụng chạm gì đến ScreenUpdating để còn biết mà "tăng tốc" trở lại?
Tức là A phải được viết như thế này:
Sub A()
.
.
Dim SV_AppScreenUpdating As Boolean
SV_AppScreenUpdating = Application.ScreenUpdating
Application.ScreenUpdating = False [COLOR=#008000]' áp dụng kỹ thuật tăng tốc ở đây[/COLOR]
.
.
connect_file
[COLOR=#008000]' Application.ScreenUpdating bị connect_file đưa trờ về 'mặc định' ở đây[/COLOR]
Application.ScreenUpdating = False [COLOR=#008000]' người viết code A biết là connect_file đưa Application.ScreenUpdating về 'mặc định' cho nên lại phải chỉnh[/COLOR]
.
.
Application.ScreenUpdating = SV_AppScreenUpdating
End Sub
Mặc định trước sau gì vẫn là Application.ScreenUpdating = True. Điều đó không sai. Nhưng cái tai hại nằm ở chỗ app được trả về mặc định trước khi hết nhu cầu tạm chuyển.
Vấn đề ở đây là người viết code connect_file có nên lý luận: "tôi làm việc dúng đắn theo thông lệ mặc định, cậu có những nhu cầu đặc thù thì cậu phải tự biết bảo vệ chúng chứ !"
…
P/S: Em xin phép BQT chen ngang topic này 1 chút ạ. Chẳng là hôm vừa rồi em có đọc Topic về vòng lặp For…next của thầy ptm0412 thấy rất hay và bổ ích đặc biệt là em thấy thầy ndu có rất nhiều câu trả lời nhanh, em rất nể. Mấy hôm vừa rồi anh ChanhTQ có mở topic "Bài tập VBA cho người mới bắt đầu[phần 2], vậy em mong nếu thầy ndu nếu rảnh thì thầy có thể ra 1 số đề bài tập ở mức độ "cho người mới bắt đầu" để các thành viên mới như bọn em làm được không ạ. Tại sao em lại nhờ đích danh thầy bởi em thấy bản thân thầy là 1 thành viên tự học tự tìm tòi và rất thành công nên em nghĩ với những kinh nghiệm về việc tự học của thầy thì những bài tập thầy ra sẽ phù hợp cho những người cũng tự học như chúng em hơn! Cảm ơn thầy!
Bản thân tôi định nghĩa cụm từ "căn bản" theo cách khác. Tuy nhiên, tôi không thể đi ngược lại chiều huớng của hầu hết những người trên diễn đàn này cho nên tôi chỉ thích chỏ vào "phá bỉnh" những chỗ mà các bạn sơ sót thôi.
Thiết kế Tổng đãi ngộ (Total Rewards) theo khung SHRM
Khóa học “Thiết kế Tổng phần thưởng (Total Reward) chuẩn khung SHRM” giúp bạn nắm vững toàn bộ hệ thống đãi ngộ theo chuẩn...
Xem khóa học