Access
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Access

Access nói chuyện với các nguồn dữ liệu ODBC như thế nào? Phần 4

Access đang làm gì khi người dùng thực hiện thay đổi đối với dữ liệu trên bảng được liên kết ODBC?

Loạt bài theo dõi ODBC của chúng tôi tiếp tục và trong bài viết thứ tư này, chúng tôi sẽ giải thích cách chèn và cập nhật bản ghi dữ liệu trong tập bản ghi, cũng như quy trình xóa bản ghi. Trong bài trước, chúng ta đã tìm hiểu cách Access xử lý việc điền dữ liệu từ các nguồn ODBC. Chúng tôi thấy rằng kiểu tập bản ghi có ảnh hưởng quan trọng đến cách Access sẽ hình thành các truy vấn tới nguồn dữ liệu ODBC. Quan trọng hơn, chúng tôi nhận thấy rằng với bộ bản ghi kiểu dynaset, Access thực hiện công việc bổ sung để có tất cả thông tin cần thiết để có thể chọn một hàng bằng cách sử dụng một khóa. Điều này sẽ áp dụng trong bài viết này, nơi chúng ta khám phá cách xử lý các sửa đổi dữ liệu. Chúng ta sẽ bắt đầu với thao tác chèn, đây là thao tác phức tạp nhất, sau đó chuyển sang cập nhật và cuối cùng là xóa.

Chèn bản ghi vào tập bản ghi

Hành vi chèn của một tập bản ghi kiểu dynaset sẽ phụ thuộc vào cách Access nhận biết các khóa của bảng bên dưới. Sẽ có 3 hành vi khác biệt. Hai phần đầu đề cập đến việc xử lý các khóa chính được máy chủ tự động tạo theo một cách nào đó. Thứ hai là trường hợp đặc biệt của hành vi đầu tiên chỉ áp dụng với phần phụ trợ SQL Server bằng cách sử dụng IDENTITY cột. Giải pháp cuối cùng giải quyết trường hợp khi các khóa được cung cấp bởi người dùng (ví dụ:khóa tự nhiên như một phần của mục nhập dữ liệu). Chúng ta sẽ bắt đầu với trường hợp tổng quát hơn về các khóa do máy chủ tạo.

Chèn bản ghi; bảng có khóa chính do máy chủ tạo

Khi chúng tôi chèn một tập bản ghi (một lần nữa, cách chúng tôi thực hiện điều này, thông qua Access UI hoặc VBA không quan trọng), Access phải thực hiện những việc để thêm hàng mới vào bộ đệm ẩn cục bộ.

Điều quan trọng cần lưu ý là Access có các hành vi chèn khác nhau tùy thuộc vào cách thiết lập khóa. Trong trường hợp này, Cities bảng không có IDENTITY nhưng thay vào đó sử dụng SEQUENCE đối tượng để tạo khóa mới. Đây là SQL theo dõi được định dạng:

 SQLExecDirect:CHÈN VÀO "Ứng dụng". "Cities" ("CityName", "StateProvinceID", "LatestRecordedPopulation", "LastEditedBy") GIÁ TRỊ (?,?,?,?) SQLPrepare:CHỌN "CityID", "CityName "," StateProvinceID "," Location "," LatestRecordedPopulation "," LastEditedBy "," ValidFrom "," ValidTo "FROM" Application "." Các thành phố "WHERE" CityID "LÀ NULLSQLExecute:(GOTO BOOKMARK) SQLExecDirect:CHỌN" Ứng dụng " . "Cities". "CityID" TỪ "Ứng dụng". "Cities" WHERE "CityName" =? VÀ "StateProvinceID" =? VÀ "LatestRecordedPopulation" =? VÀ "LastEditedBy" =? SQLExecute:(GOTO BOOKMARK) SQLExecute:(MULTI-ROW FETCH) 
Lưu ý rằng Access sẽ chỉ gửi các cột đã được người dùng thực sự sửa đổi. Mặc dù bản thân truy vấn đã bao gồm nhiều cột hơn, chúng tôi chỉ chỉnh sửa 4 cột, vì vậy Access sẽ chỉ bao gồm những cột đó. Điều đó đảm bảo rằng Access không can thiệp vào hành vi mặc định được đặt cho các cột khác mà người dùng không sửa đổi, vì Access không có kiến ​​thức cụ thể về cách nguồn dữ liệu sẽ xử lý các cột đó. Ngoài ra, câu lệnh chèn còn khá nhiều thứ mà chúng tôi mong đợi.

Tuyên bố thứ hai, tuy nhiên, hơi kỳ quặc. Nó chọn cho WHERE "CityID" IS NULL . Điều đó dường như là không thể, vì chúng ta đã biết rằng CityID cột là một khóa chính và theo định nghĩa không được rỗng. Tuy nhiên, nếu bạn nhìn vào ảnh chụp màn hình, chúng tôi chưa bao giờ sửa đổi CityID cột. Từ Access ’POV, nó là NULL . Nhiều khả năng, Access áp dụng cách tiếp cận bi quan và sẽ không cho rằng nguồn dữ liệu trên thực tế sẽ tuân theo tiêu chuẩn SQL. Như chúng ta đã thấy từ phần thảo luận về cách Access chọn một chỉ mục để sử dụng để xác định duy nhất một hàng, nó có thể không phải là khóa chính mà chỉ là UNIQUE chỉ mục có thể cho phép NULL . Đối với trường hợp cạnh không chắc đó, nó thực hiện một truy vấn chỉ để đảm bảo rằng nguồn dữ liệu không thực sự tạo một bản ghi mới với giá trị đó. Khi nó đã kiểm tra rằng không có dữ liệu nào được trả lại, nó sẽ cố định vị lại bản ghi bằng bộ lọc sau:

 WHERE "CityName" =? VÀ "StateProvinceID" =? VÀ "LatestRecordedPopulation" =? VÀ "LastEditedBy" =? 
là 4 cột giống nhau mà người dùng thực sự đã sửa đổi. Vì chỉ có một thành phố có tên là “Zeke”, chúng tôi chỉ lấy lại một bản ghi và do đó Access có thể điền vào bộ nhớ cache cục bộ bản ghi mới với dữ liệu giống như nguồn dữ liệu có nó. Nó sẽ kết hợp bất kỳ thay đổi nào đối với các cột khác, vì SELECT danh sách chỉ bao gồm CityID , sau đó nó sẽ sử dụng trong câu lệnh đã được chuẩn bị sẵn để điền vào toàn bộ hàng bằng cách sử dụng CityID phím.

Chèn bản ghi; một bảng có khóa chính tự động bổ sung

Tuy nhiên, điều gì sẽ xảy ra nếu bảng đến từ cơ sở dữ liệu SQL Server và có một cột tự động bổ sung, chẳng hạn như IDENTITY thuộc tính? Quyền truy cập hoạt động khác. Vì vậy, hãy tạo một bản sao của Cities bảng nhưng chỉnh sửa để CityID cột bây giờ là một IDENTITY cột.

Hãy xem cách Access xử lý vấn đề này:

 SQLExecDirect:INSERT INTO "Application". "Cities" ("CityName", "StateProvinceID", "LatestRecordedPopulation", "LastEditedBy", "ValidFrom", "ValidTo") GIÁ TRỊ (?,?,?,?,? ,?) SQLExecDirect:SELECT @@ IDENTITYSQLExecute:(GOTO BOOKMARK) SQLExecute:(GOTO BOOKMARK) 
Có ít nói chuyện hơn đáng kể; chúng tôi chỉ cần thực hiện một SELECT @@IDENTITY để tìm danh tính mới được chèn. Thật không may, đây không phải là một hành vi chung. Ví dụ:MySQL hỗ trợ khả năng thực hiện SELECT @@IDENTITY , tuy nhiên, Access sẽ không cung cấp hành vi này. Trình điều khiển ODBC của PostgreSQL có chế độ mô phỏng SQL Server để lừa Access gửi @@IDENTITY sang PostgreSQL để nó có thể ánh xạ tới serial tương đương kiểu dữ liệu.

Chèn bản ghi có giá trị rõ ràng cho khóa chính

Hãy thực hiện thử nghiệm thứ 3 bằng cách sử dụng bảng có int bình thường cột, không có IDENTITY thuộc tính. Mặc dù nó vẫn sẽ là khóa chính trên bảng, nhưng chúng tôi sẽ muốn xem nó hoạt động như thế nào khi chúng tôi tự mình chèn khóa một cách rõ ràng.

 SQLExecDirect:CHÈN VÀO "Ứng dụng". "Cities" ("CityID", "CityName", "StateProvinceID", "LatestRecordedPopulation", "LastEditedBy", "ValidFrom", "ValidTo") GIÁ TRỊ (?,?,? ,?,?,?,?) SQLExecute:(GOTO BOOKMARK) SQLExecute:(MULTI-ROW FETCH) 
Khoảng thời gian này, không có thể dục phụ; vì chúng tôi đã cung cấp giá trị cho khóa chính, Access biết rằng nó không phải thử và tìm lại hàng; nó chỉ thực hiện câu lệnh đã chuẩn bị để đồng bộ hóa lại hàng đã chèn. Quay trở lại thiết kế ban đầu với Cities bảng đã sử dụng SEQUENCE để tạo khóa mới, chúng ta có thể thêm hàm VBA để tìm nạp số mới bằng cách sử dụng NEXT VALUE FOR và do đó chủ động điền khóa để giúp chúng tôi có được hành vi này. Điều này gần đúng hơn cách hoạt động của công cụ cơ sở dữ liệu Access; ngay sau khi chúng tôi làm hỏng bản ghi, nó sẽ tìm nạp một khóa mới từ AutoNumber kiểu dữ liệu, thay vì đợi cho đến khi bản ghi đã được chèn thực sự. Do đó, nếu cơ sở dữ liệu của bạn sử dụng SEQUENCE hoặc các cách tạo khóa khác, nó có thể mang lại lợi ích khi cung cấp cơ chế tìm nạp khóa một cách chủ động để giúp loại bỏ phỏng đoán mà chúng tôi đã thấy Access đang thực hiện với ví dụ đầu tiên.

Cập nhật bản ghi trong tập bản ghi

Không giống như các phần chèn trong phần trước, cập nhật tương đối dễ dàng hơn vì chúng tôi đã có khóa hiện tại. Do đó, Access thường hoạt động đơn giản hơn khi cập nhật. Có hai hành vi chính mà chúng ta cần xem xét khi cập nhật bản ghi phụ thuộc vào sự hiện diện của cột chuyển đổi hàng.

Cập nhật bản ghi mà không có cột chuyển đổi hàng

Giả sử chúng ta chỉ sửa đổi một cột. Đây là những gì chúng ta thấy trong ODBC.

 SQLExecute:(GOTO BOOKMARK) SQLExecDirect:CẬP NHẬT "Ứng dụng". "Cities" SET "CityName" =? WHERE "CityID" =? VÀ "CityName" =? VÀ "StateProvinceID" =? VÀ "Vị trí" LÀ KHÔNG VÀ "Mới nhấtRecordedPopulation" =? VÀ "LastEditedBy" =? VÀ "ValidFrom" =? VÀ "ValidTo" =? 
Hừm, giải quyết được gì với tất cả các cột bổ sung mà chúng tôi không sửa đổi? Vâng, một lần nữa, Access phải chấp nhận một triển vọng bi quan. Nó phải giả định rằng ai đó có thể đã thay đổi dữ liệu trong khi người dùng đang từ từ dò tìm các chỉnh sửa. Nhưng làm thế nào Access biết được rằng ai đó đã thay đổi dữ liệu trên máy chủ? Chà, về mặt logic, nếu tất cả các cột hoàn toàn giống nhau, thì lẽ ra nó chỉ được cập nhật một hàng, phải không? Đó là những gì Access đang tìm kiếm khi nó so sánh tất cả các cột; để đảm bảo rằng chỉ cập nhật sẽ ảnh hưởng đến chính xác một hàng. Nếu nó nhận thấy rằng nó đã cập nhật nhiều hơn một hàng hoặc không có hàng, nó sẽ khôi phục cập nhật và trả về lỗi hoặc #Deleted cho người dùng.

Nhưng… đó là loại không hiệu quả, phải không? Hơn nữa, điều này có thể gây ra vấn đề nếu có logic phía máy chủ có thể thay đổi các giá trị mà người dùng nhập vào. Để minh họa, giả sử chúng tôi thêm một trình kích hoạt ngớ ngẩn làm thay đổi tên thành phố (tất nhiên, chúng tôi không khuyến khích điều này):

 TẠO Ứng dụng SillyTriggerON TRIGGER. Vì vậy, nếu sau đó chúng tôi cố gắng cập nhật một hàng bằng cách thay đổi tên thành phố, thì có vẻ như nó đã thành công. 

Nhưng nếu sau đó chúng tôi cố gắng chỉnh sửa lại, chúng tôi sẽ nhận được thông báo lỗi với thông báo được làm mới:

Đây là kết quả từ sqlout.txt :

 SQLExecDirect:CẬP NHẬT "Ứng dụng". "Các thành phố" SET "CityName" =? WHERE "CityID" =? VÀ "CityName" =? VÀ "StateProvinceID" =? VÀ "Vị trí" LÀ KHÔNG VÀ "Mới nhấtRecordedPopulation" =? VÀ "LastEditedBy" =? VÀ "ValidFrom" =? AND "ValidTo" =? SQLExecute:(GOTO BOOKMARK) SQLExecute:(GOTO BOOKMARK) SQLExecute:(MULTI-ROW FETCH) SQLExecute:(MULTI-ROW FETCH) 
Điều quan trọng cần lưu ý là GOTO BOOKMARK thứ 2 và MULTI-ROW FETCH tiếp theo đã không xảy ra cho đến khi chúng tôi nhận được thông báo lỗi và loại bỏ nó. Lý do là khi chúng tôi làm bẩn bản ghi, Access sẽ thực hiện GOTO BOOKMARK , nhận ra rằng dữ liệu trả về không còn khớp với dữ liệu có trên bộ nhớ cache, điều này khiến chúng tôi nhận được thông báo "Dữ liệu đã bị thay đổi". Điều đó giúp chúng tôi không mất thời gian chỉnh sửa một bản ghi chắc chắn sẽ không thành công vì nó đã cũ. Lưu ý rằng Access cuối cùng cũng sẽ phát hiện ra thay đổi nếu chúng tôi cho nó đủ thời gian để làm mới dữ liệu. Trong trường hợp đó, sẽ không có thông báo lỗi; biểu dữ liệu sẽ chỉ được cập nhật để hiển thị dữ liệu chính xác.

Tuy nhiên, trong những trường hợp đó, Access có khóa phù hợp nên không gặp vấn đề gì khi khám phá dữ liệu mới. Nhưng nếu đó là chiếc chìa khóa mỏng manh? Nếu trình kích hoạt đã thay đổi khóa chính hoặc nguồn dữ liệu ODBC không đại diện cho giá trị chính xác như Access nghĩ, điều đó sẽ khiến Access vẽ bản ghi là #Deleted vì nó không thể biết liệu nó đã được chỉnh sửa bởi máy chủ hay ai khác hay không so với việc nó đã bị xóa một cách hợp pháp bởi người khác.

Cập nhật bản ghi với cột chuyển đổi hàng

Dù bằng cách nào, nhận được thông báo lỗi hoặc #Deleted có thể khá khó chịu. Nhưng có một cách để tránh Access so sánh tất cả các cột. Hãy xóa trình kích hoạt và thêm một cột mới:

 ALTER TABLE Application.CitiesADD RV rowversion NOT NULL; 
Chúng tôi thêm một rowversion có thuộc tính được tiếp xúc với ODBC là có SQLSpecialColumns(SQL_ROWVER) , đó là những gì Access cần biết rằng nó có thể được sử dụng như một cách để phiên bản hàng. Hãy xem các bản cập nhật hoạt động như thế nào với thay đổi này.

 SQLExecDirect:CẬP NHẬT "Ứng dụng". "Các thành phố" SET "CityName" =? WHERE "CityID" =? VÀ "RV" =? SQLExecute:(GOTO BOOKMARK) 
Không giống như ví dụ trước trong đó Access so sánh giá trị trong mỗi cột, cho dù người dùng có chỉnh sửa hay không, chúng tôi chỉ cập nhật bản ghi bằng cách sử dụng RV làm tiêu chí bộ lọc. Lý do là nếu RV vẫn có cùng giá trị với giá trị mà Access đã chuyển vào, khi đó Access có thể tin tưởng rằng hàng này không bị ai khác chỉnh sửa vì nếu đúng như vậy thì RV Giá trị của ‘s sẽ thay đổi.

Điều đó cũng có nghĩa là nếu một trình kích hoạt thay đổi dữ liệu hoặc nếu SQL Server và Access không đại diện cho một giá trị theo cùng một cách (ví dụ:số thực), Access sẽ không chùn bước khi nó chọn lại hàng đã cập nhật và nó trở lại với giá trị khác giá trị trong các cột khác mà người dùng không chỉnh sửa.

LƯU Ý :Không phải tất cả các sản phẩm DBMS sẽ sử dụng các điều khoản giống nhau. Ví dụ:timestamp của MySQL có thể được sử dụng làm đảo ngược cho các mục đích của ODBC. Bạn sẽ cần tham khảo tài liệu của sản phẩm để xem liệu chúng có hỗ trợ tính năng đảo hàng hay không để bạn có thể tận dụng hành vi này với Access.

Lượt xem và đảo hàng

Lượt xem cũng bị ảnh hưởng bởi sự hiện diện hoặc không có sự lộn xộn. Giả sử chúng ta tạo một dạng xem trong SQL Server với định nghĩa:

 TẠO CHẾ ĐỘ XEM dbo.vwCities ASSELECT CityID, CityNameFROM Application.Cities; 
Việc cập nhật bản ghi trên chế độ xem sẽ hoàn nguyên về so sánh từng cột như thể cột chuyển đổi hàng không tồn tại trên bảng:

 SQLExecDirect:CẬP NHẬT "dbo". "vwCities" SET "CityName" =? WHERE "CityID" =? VÀ "CityName" =? 
Do đó, nếu bạn cần hành vi cập nhật dựa trên chuyển đổi hàng, bạn nên cẩn thận để đảm bảo rằng các cột chuyển đổi hàng được bao gồm trong các dạng xem. Trong trường hợp chế độ xem có chứa nhiều bảng trong các phép nối, tốt nhất bạn nên bao gồm ít nhất các cột chuyển đổi hàng từ (các) bảng mà bạn định cập nhật. Vì thường chỉ có một bảng có thể được cập nhật, chỉ bao gồm một chuyển đổi hàng có thể là đủ như một quy tắc chung.

Xóa bản ghi trong tập bản ghi

Việc xóa bản ghi hoạt động tương tự như các bản cập nhật và cũng sẽ sử dụng đảo ngược nếu có. Trên một bảng không có lộn xộn, chúng tôi nhận được:

 SQLExecDirect:XÓA khỏi "Ứng dụng". "Các thành phố" WHERE "CityID" =? VÀ "CityName" =? VÀ "StateProvinceID" =? VÀ "Vị trí" LÀ KHÔNG VÀ "Mới nhấtRecordedPopulation" =? VÀ "LastEditedBy" =? VÀ "ValidFrom" =? VÀ "ValidTo" =? 
Trên bảng có đảo ngược, chúng ta nhận được:

 SQLExecDirect:XÓA khỏi "Ứng dụng". "Các thành phố" WHERE "CityID" =? VÀ "RV" =? 
Một lần nữa, Access phải bi quan về việc xóa cũng như cập nhật; nó sẽ không muốn xóa một hàng đã được thay đổi bởi người khác. Do đó, nó sử dụng cùng một hành vi mà chúng tôi đã thấy khi cập nhật để bảo vệ khỏi việc nhiều người dùng thay đổi các bản ghi giống nhau.

Kết luận

Chúng tôi đã tìm hiểu cách Access xử lý các sửa đổi dữ liệu và giữ bộ nhớ cache cục bộ của nó đồng bộ hóa với nguồn dữ liệu ODBC. Chúng tôi đã thấy Access bi quan như thế nào, điều này được thúc đẩy bởi sự cần thiết phải hỗ trợ càng nhiều nguồn dữ liệu ODBC càng tốt mà không dựa trên các giả định hoặc kỳ vọng cụ thể rằng các nguồn dữ liệu ODBC đó sẽ hỗ trợ một tính năng nhất định. Vì lý do đó, chúng tôi thấy rằng Access sẽ hoạt động khác nhau tùy thuộc vào cách khóa được xác định cho một bảng được liên kết ODBC nhất định. Nếu chúng tôi có thể chèn khóa mới một cách rõ ràng, điều này yêu cầu công việc tối thiểu từ Access để đồng bộ hóa lại bộ đệm cục bộ cho bản ghi mới được chèn. Tuy nhiên, nếu chúng tôi cho phép máy chủ điền khóa, Access sẽ phải thực hiện thêm công việc trong nền để đồng bộ hóa lại.

Chúng tôi cũng thấy rằng việc có một cột trên bảng có thể được sử dụng làm đảo ngược hàng có thể giúp giảm bớt sự lộn xộn giữa Access và nguồn dữ liệu ODBC trên một bản cập nhật. Bạn sẽ cần tham khảo tài liệu trình điều khiển ODBC để xác định xem nó có hỗ trợ chuyển đổi hàng ở lớp ODBC hay không và nếu có, hãy bao gồm cột đó trong các bảng hoặc dạng xem trước khi liên kết với Access để thu được lợi ích của các bản cập nhật dựa trên chuyển đổi hàng.

Giờ đây, chúng tôi biết rằng đối với bất kỳ bản cập nhật hoặc xóa nào, Access sẽ luôn cố gắng xác minh rằng hàng không bị thay đổi kể từ lần cuối cùng được Access tìm nạp, để ngăn người dùng thực hiện các thay đổi có thể không mong muốn. Tuy nhiên, chúng tôi cần xem xét các tác động phát sinh từ việc thực hiện các thay đổi ở những nơi khác (ví dụ:trình kích hoạt phía máy chủ, chạy một truy vấn khác trong một kết nối khác) có thể khiến Access kết luận rằng hàng đã bị thay đổi và do đó không cho phép thay đổi. Thông tin đó sẽ giúp chúng tôi phân tích và tránh tạo ra một chuỗi sửa đổi dữ liệu có thể mâu thuẫn với mong đợi của Access khi nó đồng bộ hóa lại bộ đệm cục bộ.

Trong phần tiếp theo, chúng ta sẽ xem xét các tác động của việc áp dụng các bộ lọc trên một tập bản ghi.

Nhận trợ giúp từ các Chuyên gia truy cập của chúng tôi ngay hôm nay. Gọi cho nhóm của chúng tôi theo số 773-809-5456 hoặc gửi email cho chúng tôi theo địa chỉ [email protected].


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hướng dẫn 7 bước để sử dụng quyền truy cập với xác thực đa yếu tố Azure

  2. Câu lệnh DefType trong VBA:Mặt tối của khả năng tương thích ngược

  3. Kết nối SAP Lumira với Microsoft Access

  4. 10 lý do hàng đầu để sử dụng Access và Excel cùng nhau

  5. Tìm hiểu cách tạo ra các hình thức trong trí nhớ (Vâng, bạn đã nghe đúng)