การรับข้อผิดพลาด 3340 Query '' เสียหายขณะดำเนินการสืบค้น DoCmd.RunSQL


83

ตั้งแต่ติดตั้งWindows Update สำหรับ Office 2010 การแก้ปัญหา KB 4484127ฉันได้รับข้อผิดพลาดในขณะที่ดำเนินการแบบสอบถามซึ่งมีส่วนคำสั่ง WHERE อยู่

ตัวอย่างเช่นการดำเนินการค้นหานี้:

DoCmd.RunSQL "update users set uname= 'bob' where usercode=1"

ผลลัพธ์ในข้อผิดพลาดนี้:

หมายเลขข้อผิดพลาด = 3340 Query '' เสียหาย

ยังมีการติดตั้งการอัปเดตที่เป็นปัญหา :

สกรีนช็อตแสดงการอัปเดต Microsoft Office 2010 Service Pack 2 448127

ฉันจะเรียกใช้คิวรีของฉันสำเร็จได้อย่างไร? ฉันควรถอนการติดตั้งอัปเดตนี้หรือไม่

คำตอบ:


92

สรุป

นี่เป็นข้อผิดพลาดที่ทราบว่าเกิดจากการอัปเดต Office ที่วางจำหน่ายในวันที่ 12 พฤศจิกายน 2019 ข้อผิดพลาดนี้ส่งผลกระทบต่อ Access ทุกรุ่นที่ Microsoft สนับสนุนในปัจจุบัน (จาก Access 2010 ถึง 365)

ข้อผิดพลาดนี้ได้รับการแก้ไขแล้ว

  • หากคุณใช้ Office รุ่น C2R (คลิกเพื่อเรียกใช้) ให้ใช้ "อัปเดตทันที" :
    • Access 2010 C2R: แก้ไขใน Build 7243.5000
    • การเข้าถึง 2013 C2R: แก้ไขใน Build 5197.1000
    • การเข้าถึง 2016 C2R: แก้ไขในรุ่น 12130.20390
    • เข้าถึง 2019 (v1910): แก้ไขในรุ่น 12130.20390
    • การเข้าถึง 2019 (Volume License): แก้ไขในรุ่น 10353.20037
    • ช่องรายเดือน Office 365: แก้ไขใน Build 12130.20390
    • ครึ่งปีของ Office 365: แก้ไขใน Build 11328.20480
    • ครึ่งปีของ Office 365 Extended: แก้ไขใน Build 10730.20422
    • เป้าหมายครึ่งปีของ Office 365: แก้ไขในรุ่น 11929.20494
  • หากคุณใช้ Office เวอร์ชัน MSI ให้ติดตั้งอัปเดตที่ตรงกับรุ่น Office ของคุณ แพทช์เหล่านี้ทั้งหมดได้เปิดตัวใน Microsoft Update ดังนั้นการติดตั้ง Windows Update ที่ค้างอยู่ทั้งหมดควรจะพอเพียง
    • Access 2010 MSI: แก้ไขในKB4484193
    • Access 2013 MSI: แก้ไขในKB4484186
    • Access 2016 MSI: แก้ไขในKB4484180

ตัวอย่าง

นี่คือตัวอย่างการทำซ้ำขั้นต่ำ:

  1. สร้างฐานข้อมูล Access ใหม่
  2. สร้างตารางใหม่ที่ว่างเปล่า "Table1" ด้วยฟิลด์ ID เริ่มต้นและฟิลด์ Long Integer "myint"
  3. ดำเนินการรหัสต่อไปนี้ในหน้าต่างทันทีของตัวแก้ไข VBA:

    CurrentDb.Execute "UPDATE Table1 SET myint = 1 WHERE myint = 1"

ผลลัพธ์ที่ควรได้รับ : คำสั่งเสร็จสมบูรณ์

ผลลัพธ์จริงเมื่อติดตั้งหนึ่งในการอัปเดตของ buggy: ข้อผิดพลาดรันไทม์ 3340 เกิดขึ้น ("Query '' เสียหาย")


ลิ้งค์ที่มีความเกี่ยวข้อง:


9
โพสต์นี้ดูเหมือนจะพบข้อผิดพลาดเดียวกันโดยใช้ 64-bit Access runtime และ OLEDB สิ่งที่น่ากลัวนี้จะทำให้แอปพลิเคชั่นมากมายที่ใช้ Access เพื่อเก็บข้อมูลไม่สามารถใช้งานได้
เอริค

4
ฉันเพียงแค่การตรวจสอบระบบที่มี Office 2013 รุ่น 32 บิตและในเครื่องที่โดยเฉพาะอย่างยิ่งสำหรับการปรับปรุง UUID คือ90150000-006E-0409-0000-0000000FF1CE... ว่าไม่-0409- -0407-
Gord Thompson

4
ฉันเพิ่งตรวจสอบเครื่องอื่นในสำนักงานที่มี Office 2013 64 บิตและ UUID ก็-006E-0409-เช่นกัน ทั้งสองเครื่องมี Service Pack 1 สำหรับ Microsoft Office 2013 (KB2850036) ติดตั้ง
Gord Thompson

4
สำหรับ Office 2010 Pro Plus (SP2) เราจำเป็นต้องใช้{90140000-0011-0000-0000-0000000FF1CE}ในสคริปต์ชุดงาน หมายเหตุ{9014...ไม่ได้{9114..}
AdamsTips

2
ฉันได้ทำการติดตั้งด้วยการอัพเดทอย่างเป็นทางการเพื่อแก้ไขปัญหา แต่ฉันยังคงได้รับข้อผิดพลาด ใครมีปัญหานั้นอีก
user218076

33

วิธีที่ง่ายที่สุด

สำหรับผู้ใช้ของฉันการรอเกือบหนึ่งเดือนจนถึงวันที่ 10 ธันวาคมสำหรับการเปิดตัวการแก้ไขจาก Microsoft ไม่ใช่ตัวเลือก และไม่ถอนการติดตั้งการอัปเดตของ Microsoft ที่ละเมิดในหลาย ๆ เวิร์กสเตชันของรัฐบาลที่ถูกล็อค

ฉันต้องใช้วิธีแก้ปัญหา แต่ฉันก็ไม่ได้ตื่นเต้นกับสิ่งที่ Microsoft แนะนำ - การสร้างและทดแทนแบบสอบถามสำหรับแต่ละตาราง

การแก้ปัญหาคือการแทนที่ชื่อตารางด้วย(SELECT * FROM Table)แบบสอบถามง่าย ๆโดยตรงในUPDATEคำสั่ง สิ่งนี้ไม่ต้องการการสร้างและบันทึกการสืบค้นตารางหรือฟังก์ชั่นเพิ่มเติม

ตัวอย่าง:

ก่อน:

UPDATE Table1 SET Field1 = "x" WHERE (Field2=1);  

หลังจาก:

UPDATE (SELECT * FROM Table1) SET Field1 = "x" WHERE (Field2=1);  

ซึ่งน่าจะง่ายกว่าที่จะนำไปใช้กับฐานข้อมูลและแอพพลิเคชั่นหลายตัว


20

นี่ไม่ใช่ปัญหาการอัปเดต Windows แต่เป็นปัญหาที่เกิดขึ้นกับรุ่นพฤศจิกายน Patch Tuesday Office การเปลี่ยนแปลงเพื่อแก้ไขช่องโหว่ด้านความปลอดภัยทำให้การค้นหาที่ถูกต้องตามกฎหมายถูกรายงานว่าเสียหาย เนื่องจากการเปลี่ยนแปลงเป็นการแก้ไขด้านความปลอดภัยจึงส่งผลต่อการสร้าง Office ทั้งหมดรวมถึง 2010, 2013, 2016, 2019 และ O365

ข้อผิดพลาดได้รับการแก้ไขในทุกช่องทาง แต่เวลาในการจัดส่งจะขึ้นอยู่กับว่าคุณอยู่ในช่องใด

สำหรับ 2010, 2013 และ 2016 MSI, และ 2019 Volume License บิวด์และ O365 Semi-annual Channel การแก้ไขจะอยู่ในการสร้างธันวาคม Patch Tuesday, 10 ธ.ค. สำหรับ O365, Monthly Channel และ Insiders สิ่งนี้จะได้รับการแก้ไข เมื่อวางจำหน่ายเดือนตุลาคมซึ่งวางแผนไว้สำหรับวันที่ 24 พฤศจิกายน

สำหรับช่องทางครึ่งปีข้อผิดพลาดถูกนำมาใช้ใน 11328.20468 ซึ่งเปิดตัว 12 พฤศจิกายน แต่ไม่ได้แผ่ออกไปทุกคนในคราวเดียว หากทำได้คุณอาจต้องการระงับการอัปเดตจนถึงวันที่ 10 ธันวาคม

ปัญหานี้เกิดขึ้นสำหรับแบบสอบถามแบบใช้ปรับปรุงข้อมูลกับตารางเดียวโดยมีเกณฑ์ที่ระบุ (ดังนั้นแบบสอบถามชนิดอื่น ๆ จะไม่ได้รับผลกระทบหรือแบบสอบถามใด ๆ ที่ปรับปรุงแถวทั้งหมดของตารางหรือแบบสอบถามที่ปรับปรุงชุดผลลัพธ์ของแบบสอบถามอื่น) ระบุว่าวิธีแก้ปัญหาที่ง่ายที่สุดในกรณีส่วนใหญ่คือการเปลี่ยนคิวรีอัปเดตเพื่ออัปเดตคิวรีอื่นที่เลือกทุกอย่างจากตารางแทนที่จะอัปเดตคิวรีโดยตรง

คือถ้าคุณมีคำถามเช่น:

UPDATE Table1 SET Table1.Field1 = "x" WHERE ([Table1].[Field2]=1);

จากนั้นสร้างแบบสอบถามใหม่ (Query1) ที่กำหนดเป็น:

Select * from Table1;

และอัปเดตข้อความค้นหาเดิมของคุณเป็น:

UPDATE Query1 SET Query1.Field1 = "x" WHERE ([Query1].[Field2]=1);

หน้าอย่างเป็นทางการ: ข้อผิดพลาดการเข้าถึง: "แบบสอบถามเสียหาย"


13
คุณกำลังพูดอย่างตรงไปตรงมาว่าเราใช้โค้ดที่มีอยู่ถึง 100 แสนบรรทัดในหลายแอพพลิเคชั่นและแก้ไขการอัพเดท sql ทั้งหมดที่ง่ายต่อการอัพเดทแถวข้อมูล? ฉันคิดว่าถ้าคุณเขียนแบบสอบถามใหม่วันนี้และตอนนี้วิธีแก้ปัญหาดังกล่าวเป็นไปได้ แต่สำหรับโค้ดและแอพพลิเคชั่นที่มีอยู่แล้วความคิดที่ว่าการอัพเดต sql นั้นจะต้องเปลี่ยนนั้นแน่นอนว่าไม่ใช่วิธีการที่ใช้งานได้จริงในการแก้ปัญหาโพรบในทุกวิธี
Albert D. Kallal

5
@ AlbertD.Kallal คุณควรรู้จากรายการ MVP ว่าฉันแค่อ้างถึงคำอธิบายสำหรับแหล่งที่มาของปัญหา วิธีจัดการกับปัญหานั้นขึ้นอยู่กับคุณจริง ๆ และสิ่งที่อาจเหมาะสมกับสถานการณ์ของคุณ วิธีการอธิบายที่นี่เป็นเพียงหนึ่งในหลาย ๆ
กุสตาฟ

1
@ AlbertD.Kallal ไม่ควรเปลี่ยนชื่อตารางและสร้าง QueryDefs ด้วยการแก้ไขชื่อตารางเก่าหรือไม่ (ฉันจะทดสอบและโพสต์สคริปต์หากใช้งานได้)
ComputerVersteher

คุณสามารถทำได้โดยไม่ต้องวางโปรแกรมเช่นเปลี่ยนชื่อตาราง "users" เป็น "userst" จากนั้นสร้างชื่อแบบสอบถาม "users" - แล้วมันจะทำงานโดยไม่มี programing chane ....
Zvi Redler

9
@ AlbertD.Kallal: ฉันแบ่งปันความเจ็บปวดของคุณ - ถ้านี่เป็นข้อผิดพลาดที่มีผลต่อไลบรารี VC runtime ฉันไม่คิดว่า MS จะหน่วงเวลาการแก้ไขเป็นเวลาหนึ่งเดือนและแนะนำวิธีแก้ปัญหา "rewrite, recompile และ redeploy" (เพื่อความเป็นธรรมพวกเขาแก้ไขและปล่อยปัญหา VBA ในปลายเดือนสิงหาคมอย่างรวดเร็ว) แต่อย่ายิงผู้ส่งสาร - กุสตาฟดูเหมือนจะไม่เป็นพนักงานของ MS หวังว่าพวกเขาจะทบทวนและปล่อยแพตช์ก่อนหน้านี้ หลังจากที่ทุกคนก็ยังมีผลต่อการใช้งานที่เขียนในภาษาอื่น ๆ ที่เพิ่งเกิดขึ้นในการใช้เครื่องมือการเข้าถึงฐานข้อมูล
Heinzi

15

เมื่อต้องการแก้ไขปัญหานี้ชั่วคราวขึ้นอยู่กับรุ่น Access ที่ใช้:
Access 2010 ถอนการติดตั้งการอัปเดต KB4484127
Access 2013 ถอนการติดตั้งอัปเดต KB4484119
Access 2016 ถอนการติดตั้งอัปเดต KB4484113
เข้าถึง 2019 หากจำเป็น (tbc) ปรับลดรุ่นจากรุ่น 1808 (สร้าง 10352.20042) เป็นรุ่น 1808 (สร้าง 10351.20054)
Office 365 ProPlus ปรับลดรุ่นจากรุ่น 1910 (รุ่น 12130.20344) ไปเป็นรุ่นก่อนหน้าดูhttps://support.microsoft.com/en-gb/help/2770432/ วิธีที่จะเปลี่ยนกลับไปใช้เวอร์ชันก่อนหน้านี้ของสำนักงาน 2013 หรือสำนักงาน 2016-คลิก


ฉันถอนการติดตั้งแล้ว แต่ติดตั้งใหม่ในครั้งต่อไปที่ฉันเริ่ม Windows คุณจะป้องกันไม่ให้ติดตั้งใหม่ได้อย่างไร
dsteele

5
@dsteele หากรุ่น MSI และไม่มี WSUS ให้ใช้support.microsoft.com/en-us/help/3073930/…เครื่องมือแก้ปัญหา ใน CTR ปิดการใช้งานการอัปเดตใน Office-Account-Settings ..
ComputerVersteher

5

เราและลูกค้าของเราต้องดิ้นรนกับเรื่องนี้ในช่วงสองวันที่ผ่านมาและในที่สุดก็เขียนรายงานเพื่อหารือเกี่ยวกับปัญหาอย่างละเอียดพร้อมกับวิธีแก้ปัญหาบางอย่าง: http://fmsinc.com/MicrosoftAccess/Errors/query_is_corrupt/

ซึ่งรวมถึงการค้นพบของเราว่ามีผลกระทบต่อโซลูชันการเข้าถึงเมื่อเรียกใช้แบบสอบถามแบบใช้ปรับปรุงข้อมูลในตารางท้องถิ่นตารางเชื่อมโยงและแม้แต่ตาราง SQL Server ที่เชื่อมโยง

นอกจากนี้ยังส่งผลกระทบต่อโซลูชันที่ไม่ใช่ของ Microsoft Access โดยใช้ Access Database Engine (ACE) เพื่อเชื่อมต่อกับฐานข้อมูล Access โดยใช้ ADO ซึ่งรวมถึงแอพ Visual Studio (WinForm) แอพ VB6 และแม้กระทั่งเว็บไซต์ที่อัพเดทฐานข้อมูล Access บนเครื่องที่ไม่เคยมี Access หรือ Office ติดตั้งอยู่

ความผิดพลาดนี้อาจส่งผลกระทบต่อแอพ Microsoft ที่ใช้ ACE เช่น PowerBI, Power Query, SSMA, ฯลฯ (ไม่ได้รับการยืนยัน) และแน่นอนโปรแกรมอื่น ๆ เช่น Excel, PowerPoint หรือ Word โดยใช้ VBA เพื่อแก้ไขฐานข้อมูล Access

นอกเหนือจากการถอนการติดตั้งการอัปเดตความปลอดภัยที่ละเมิดแล้วอย่างเห็นได้ชัดเรายังมีตัวเลือกบางอย่างเมื่อไม่สามารถถอนการติดตั้งเนื่องจากสิทธิ์หรือการแจกจ่ายแอปพลิเคชัน Access ให้กับลูกค้าภายนอกที่พีซีอยู่เหนือการควบคุมของคุณ ซึ่งรวมถึงการเปลี่ยนแปลงคำสั่งอัปเดตทั้งหมดและกระจายแอปพลิเคชัน Access โดยใช้ Access 2007 (ขายปลีกหรือรันไทม์) เนื่องจากเวอร์ชันนั้นไม่ได้รับผลกระทบจากการอัปเดตความปลอดภัย


4

ใช้โมดูลต่อไปนี้เพื่อใช้วิธีแก้ปัญหาที่แนะนำโดยอัตโนมัติของ Microsoft (ใช้แบบสอบถามแทนตาราง) เพื่อเป็นการป้องกันไว้ล่วงหน้าให้สำรองฐานข้อมูลของคุณก่อน

ใช้AddWorkaroundForCorruptedQueryIssue()เพื่อเพิ่มวิธีแก้ปัญหาและRemoveWorkaroundForCorruptedQueryIssue()เพื่อลบได้ตลอดเวลา

Option Compare Database
Option Explicit

Private Const WorkaroundTableSuffix As String = "_Table"

Public Sub AddWorkaroundForCorruptedQueryIssue()
    On Error Resume Next

    With CurrentDb
        Dim tableDef As tableDef
        For Each tableDef In .tableDefs
            Dim isSystemTable As Boolean
            isSystemTable = tableDef.Attributes And dbSystemObject

            If Not EndsWith(tableDef.Name, WorkaroundTableSuffix) And Not isSystemTable Then
                Dim originalTableName As String
                originalTableName = tableDef.Name

                tableDef.Name = tableDef.Name & WorkaroundTableSuffix

                Call .CreateQueryDef(originalTableName, "select * from [" & tableDef.Name & "]")

                Debug.Print "OldTableName/NewQueryName" & vbTab & "[" & originalTableName & "]" & vbTab & _
                            "NewTableName" & vbTab & "[" & tableDef.Name & "]"
            End If
        Next
    End With
End Sub

Public Sub RemoveWorkaroundForCorruptedQueryIssue()
    On Error Resume Next

    With CurrentDb
        Dim tableDef As tableDef
        For Each tableDef In .tableDefs
            Dim isSystemTable As Boolean
            isSystemTable = tableDef.Attributes And dbSystemObject

            If EndsWith(tableDef.Name, WorkaroundTableSuffix) And Not isSystemTable Then
                Dim originalTableName As String
                originalTableName = Left(tableDef.Name, Len(tableDef.Name) - Len(WorkaroundTableSuffix))

                Dim workaroundTableName As String
                workaroundTableName = tableDef.Name

                Call .QueryDefs.Delete(originalTableName)
                tableDef.Name = originalTableName

                Debug.Print "OldTableName" & vbTab & "[" & workaroundTableName & "]" & vbTab & _
                            "NewTableName" & vbTab & "[" & tableDef.Name & "]" & vbTab & "(Query deleted)"
            End If
        Next
    End With
End Sub

'From https://excelrevisited.blogspot.com/2012/06/endswith.html
Private Function EndsWith(str As String, ending As String) As Boolean
     Dim endingLen As Integer
     endingLen = Len(ending)
     EndsWith = (Right(Trim(UCase(str)), endingLen) = UCase(ending))
End Function

คุณสามารถค้นหารหัสล่าสุดบนของพื้นที่เก็บข้อมูล GitHub

AddWorkaroundForCorruptedQueryIssue()จะเพิ่มต่อท้าย_Tableทุกตารางระบบไม่เช่นตารางจะถูกเปลี่ยนชื่อเป็นIceCreamsIceCreams_Table

มันจะสร้างแบบสอบถามใหม่โดยใช้ชื่อตารางเดิมซึ่งจะเลือกคอลัมน์ทั้งหมดของตารางที่เปลี่ยนชื่อ ในตัวอย่างของแบบสอบถามจะได้รับการตั้งชื่อIceCreamsและจะดำเนินการใน select * from [IceCreams_Table]SQL

RemoveWorkaroundForCorruptedQueryIssue() ทำสิ่งที่ตรงกันข้าม

ฉันทดสอบสิ่งนี้กับตารางทุกชนิดรวมถึงตารางที่ไม่ใช่ MDB ภายนอก (เช่น SQL Server) แต่โปรดทราบว่าการใช้คิวรีแทนตารางสามารถนำไปสู่คิวรีที่ไม่เหมาะสำหรับการดำเนินการกับฐานข้อมูลแบ็กเอนด์ในบางกรณีโดยเฉพาะถ้าคิวรีดั้งเดิมของคุณที่ใช้ตารางนั้นมีคุณภาพไม่ดีหรือซับซ้อนมาก

(และแน่นอนขึ้นอยู่กับรูปแบบการเข้ารหัสของคุณก็เป็นไปได้ที่จะทำลายสิ่งต่าง ๆ ในแอปพลิเคชันของคุณดังนั้นหลังจากตรวจสอบว่าการแก้ไขโดยทั่วไปเหมาะกับคุณแล้วคุณไม่ควรส่งออกวัตถุทั้งหมด เวทมนต์เพื่อให้แน่ใจว่าการใช้ชื่อตารางใด ๆ ที่เกิดขึ้นจะถูกเรียกใช้ต่อคิวรีและไม่ใช่ตาราง)

ในกรณีของฉันการแก้ไขนี้ใช้งานได้เป็นอย่างดีโดยไม่มีผลข้างเคียงใด ๆ ฉันแค่ต้องเปลี่ยนชื่อUSysRibbons_TableกลับUSysRibbonsเป็นด้วยตนเองเนื่องจากฉันไม่ได้ทำเครื่องหมายว่าเป็นตารางระบบเมื่อฉันสร้างขึ้นในอดีต


ฉันชอบการกำหนดตารางระบบด้วยTableDef.Attributesและคัดลอกคำตอบของฉันไป) และฟังก์ชั่นการเลิกทำเป็นความคิดที่ดี (แต่ชื่อเก่าและใหม่ควรเก็บไว้ในตารางโดยขึ้นอยู่กับไม่มีตารางต่อท้ายก่อนที่จะเปลี่ยนชื่อ) บางส่วนอื่น ๆ มีความผิดพลาด (เช่นตารางสามารถลงท้ายด้วยคำต่อท้ายหรือชื่อใหม่คือทั้งหมดพร้อมใช้งานหรือOn Error Resume Nextไม่จัดการข้อผิดพลาดในภายหลัง) คุณรู้จักRubberduckVBAหรือไม่ Addin นี้สามารถตรวจสอบรหัสของคุณและให้คำแนะนำที่ดีสำหรับการปรับปรุงนอกเหนือจากคุณสมบัติอื่น ๆ ทั้งหมด
ComputerVersteher

และคุณควรชี้ไปที่ข้อบกพร่องที่วิธีการของเราสามารถทำให้เกิด (ดูความคิดเห็น @Erics ในคำตอบของฉัน)
ComputerVersteher

อาฉันไม่เห็นว่ามีคำตอบที่คล้ายกันอยู่ที่นี่ดังนั้นขอบคุณสำหรับความคิดเห็น! คำต่อท้ายที่กำหนดไว้ในค่าคงที่ของตัวเองดังนั้นจึงสามารถเปลี่ยนแปลงได้อย่างง่ายดายในกรณีที่มีวัตถุที่มีอยู่ก่อนหน้านี้กำหนดไว้แล้วที่ใช้คำต่อท้าย มิฉะนั้นสคริปต์จะทำงานเหมือนที่เป็นอยู่ แต่ทุกคนควรรู้สึกว่าได้รับการสนับสนุนให้ปรับเปลี่ยนตามความต้องการส่วนบุคคล สคริปต์ได้รับการทดสอบในโครงการขนาดใหญ่พอสมควร (400+ ตาราง) รวมถึงตารางภายนอก / ลิงก์ไปยังแหล่งฐานข้อมูลภายนอกอื่น ฉันไม่รู้เกี่ยวกับ Rubberduck (เฉพาะเกี่ยวกับ MZ-Tools) ฉันจะตรวจสอบพวกเขาอย่างแน่นอน!
lauxjpn

3

สำหรับผู้ที่ต้องการทำให้กระบวนการนี้เป็นแบบอัตโนมัติผ่านPowerShell ต่อไปนี้เป็นลิงค์บางส่วนที่ฉันพบว่าอาจมีประโยชน์:

ตรวจจับและลบการปรับปรุงที่กระทำผิด

มีสคริปต์ PowerShell อยู่ที่นี่https://www.arcath.net/2017/09/office-update-removerที่ค้นหารีจิสตรีสำหรับการอัปเดต Office เฉพาะ (ส่งเป็นหมายเลข kb) และลบออกโดยใช้การโทรmsiexec.exe. สคริปต์นี้แยกวิเคราะห์ guid ทั้งสองออกจากรีจิสตรีคีย์เพื่อสร้างคำสั่งเพื่อลบการปรับปรุงที่เหมาะสม

การเปลี่ยนแปลงอย่างหนึ่งที่ฉันอยากจะแนะนำจะใช้/REBOOT=REALLYSUPPRESSตามที่อธิบายไว้ในวิธีถอนการติดตั้ง KB4011626 และการปรับปรุง Office อื่น ๆ (อ้างอิงเพิ่มเติม: https://docs.microsoft.com/en-us/windows/win32/msi/uninstalling-patches ) บรรทัดคำสั่งที่คุณกำลังสร้างมีลักษณะดังนี้:

msiexec /i {90160000-0011-0000-0000-0000000FF1CE} MSIPATCHREMOVE={9894BF35-19C1-4C89-A683-D40E94D08C77} /qn REBOOT=REALLYSUPPRESS

คำสั่งเพื่อเรียกใช้สคริปต์จะมีลักษณะเช่นนี้:

OfficeUpdateRemover.ps1 -kb 4484127

ป้องกันไม่ให้การปรับปรุงติดตั้ง

วิธีที่แนะนำที่นี่ดูเหมือนว่าจะหลบซ่อนตัวอยู่การปรับปรุง เห็นได้ชัดว่าสิ่งนี้สามารถทำได้ด้วยตนเอง แต่มีสคริปต์ PowerShell บางตัวที่สามารถช่วยเรื่องระบบอัตโนมัติได้ ลิงค์นี้: https://www.maketecheasier.com/hide-updates-in-windows-10/อธิบายกระบวนการโดยละเอียด แต่ฉันจะสรุปที่นี่

  1. ติดตั้งWindows Update PowerShell โมดูล
  2. ใช้คำสั่งต่อไปนี้เพื่อซ่อนการอัปเดตด้วยหมายเลข KB:

    ซ่อน -WUUpdate -KBArticleID KB4484127

หวังว่านี่จะช่วยคนอื่นได้


3

VBA- สคริปต์สำหรับ MS-Workaround:

ขอแนะนำให้ลบการอัปเดตของบั๊กกี้หากเป็นไปได้ (ถ้าไม่ลองใช้รหัสของฉัน) อย่างน้อยสำหรับรุ่น MSI ดูคำตอบhttps://stackoverflow.com/a/58833831/9439330

สำหรับเวอร์ชัน CTR (คลิกเพื่อเรียกใช้) คุณต้องลบ Office November-Updates ทั้งหมดสิ่งที่อาจทำให้เกิดปัญหาด้านความปลอดภัยที่ร้ายแรง (ไม่แน่ใจว่าจะลบการแก้ไขที่สำคัญใด ๆ )

จากความคิดเห็นของ @ Eric:

  • ถ้าคุณใช้Table.Tablenameในการผูกฟอร์มฟอร์มเหล่านั้นจะถูกยกเลิกการเชื่อมโยงเนื่องจากชื่อตารางเดิมตอนนี้เป็นชื่อแบบสอบถาม!
  • OpenRecordSet(FormerTableNowAQuery, dbOpenTable) จะล้มเหลว (เนื่องจากเป็นแบบสอบถามตอนนี้ไม่ใช่ตารางอีกต่อไป)

ข้อควรระวัง! เพียงทดสอบอย่างรวดเร็วกับNorthwind.accdbใน Office 2013 x86 CTR ไม่มีการรับประกัน!

Private Sub RenameTablesAndCreateQueryDefs()
With CurrentDb
    Dim tdf As DAO.TableDef
    For Each tdf In .TableDefs

        Dim oldName As String
        oldName = tdf.Name

        If Not (tdf.Attributes And dbSystemObject) Then 'credit to @lauxjpn for better check for system-tables
            Dim AllFields As String
            AllFields = vbNullString

            Dim fld As DAO.Field

            For Each fld In tdf.Fields
                AllFields = AllFields & "[" & fld.Name & "], "
            Next fld

            AllFields = Left(AllFields, Len(AllFields) - 2)
            Dim newName As String
            newName = oldName

            On Error Resume Next
            Do
                Err.Clear
                newName = newName & "_"
                tdf.Name = newName
            Loop While Err.Number = 3012
            On Error GoTo 0

            Dim qdf As DAO.QueryDef

            Set qdf = .CreateQueryDef(oldName)
            qdf.SQL = "SELECT " & AllFields & " FROM [" & newName & "]"
        End If
    Next
    .TableDefs.Refresh

End With
End Sub

สำหรับการทดสอบ:

Private Sub TestError()
With CurrentDb
    .Execute "Update customers Set City = 'a' Where 1=1", dbFailOnError 'works

    .Execute "Update customers_ Set City = 'b' Where 1=1", dbFailOnError 'fails
End With
End Sub

4
โปรดทราบว่าวิธีแก้ปัญหานี้จะทำลายรูปแบบย่อยที่ผูกไว้กับตาราง (จะต้องตอบกลับแบบสอบถาม) และรหัสการทำงานกับ tabledefs ด้วยชื่อตาราง hardcoded ใช้ด้วยความระมัดระวังอย่างยิ่งอัตราต่อรองนี้จะแก้ไขข้อบกพร่องหนึ่งข้อเท่านั้นเพื่อสร้างสองข้อใหม่ขึ้นอยู่กับสิ่งที่แอปพลิเคชันของคุณกำลังทำอยู่
เอริค

@ErikA แน่นอนเพียงวิธีแก้ปัญหา แต่ฉันสามารถผูกInventory to reorder Subform for HomeกับInventoryตารางในHomeรูปแบบโดยไม่มีปัญหา แม้ว่าจะไม่แนะนำให้ผูกฟอร์มกับคิวรีแทนที่จะเป็นตาราง (ไม่ผูกพันกับตารางเช่นนั้นSelect * From table)
ComputerVersteher

2
ถ้าฉันผูกฟอร์มย่อยกับตารางโดยทั่วไปฉันจะใช้Table.TableNameสัญกรณ์ ถ้าคุณทำSELECT * FROM TableNameแทนคุณก็สบายดี แต่ถ้าคุณใช้Table.TableNameฟอร์มย่อยของคุณจะไม่ถูกผูกไว้หากคุณเปลี่ยนชื่อตาราง
เอริค

@ErikA: จริง ประโยชน์ใด ๆ จากการทำเช่นนั้น?
ComputerVersteher

3
ไม่ไกลเท่าที่ฉันรู้ยกเว้นมันสั้นกว่า มีข้อได้เปรียบที่สำคัญTableDefs!MyTableName.OpenRecordset(dbOpenTable)คือแม้ว่า (สนับสนุนการค้นหาดัชนี) ซึ่งฉันมักจะใช้และจะทำให้เกิดข้อผิดพลาดกับวิธีการของคุณ
:

2

ฉันแทนที่currentDb.ExecuteและDocmd.RunSQLด้วยฟังก์ชันตัวช่วย ที่สามารถประมวลผลล่วงหน้าและเปลี่ยนแปลงคำสั่ง SQL หากคำสั่งการปรับปรุงใด ๆ มีเพียงหนึ่งตาราง ฉันมีตารางdual(แถวเดี่ยวคอลัมน์เดียว) อยู่แล้วดังนั้นฉันจึงไปกับตัวเลือก fakeTable

หมายเหตุ : สิ่งนี้จะไม่เปลี่ยนวัตถุแบบสอบถามของคุณ มันจะช่วยให้การประมวลผล SQL ผ่าน VBA เท่านั้นIf you would like to change your query objects, use FnQueryReplaceSingleTableUpdateStatements and update your sql in each of your querydefs. Shouldn't be a problem either.

(If it's a single table update modify the sql before execution)นี่เป็นเพียงแนวคิด ปรับมันตามความต้องการของคุณ วิธีนี้ไม่ได้สร้างคิวรีการแทนที่สำหรับแต่ละตาราง (ซึ่งอาจเป็นวิธีที่ง่ายที่สุด แต่มีข้อเสียของตัวเองเช่นปัญหาประสิทธิภาพ)

+ คะแนน: คุณสามารถใช้ตัวช่วยนี้ต่อไปได้แม้หลังจากที่ MS แก้ไขข้อผิดพลาดแล้วมันจะไม่เปลี่ยนแปลงอะไรเลย ในกรณีที่อนาคตนำปัญหาอื่นมาคุณพร้อมpre-processSQL ของคุณในที่เดียว ฉันไม่ได้ไปถอนการติดตั้งวิธีการอัปเดตเนื่องจากต้องมีสิทธิ์การเข้าถึงระดับผู้ดูแลระบบ + จะใช้เวลานานเกินไปในการทำให้ทุกคนได้รับเวอร์ชันที่ถูกต้อง + แม้ว่าคุณจะถอนการติดตั้งก็ตามนโยบายกลุ่มของผู้ใช้ปลายทาง คุณกลับไปที่ปัญหาเดียวกัน

หากคุณสามารถเข้าถึงซอร์สโค้ดuse this methodและคุณมั่นใจได้ 100% ว่าผู้ใช้ปลายทางไม่มีปัญหา

Public Function Execute(Query As String, Optional Options As Variant)
    'Direct replacement for currentDb.Execute

    If IsBlank(Query) Then Exit Function

    'invalid db options remove
    If Not IsMissing(Options) Then
        If (Options = True) Then
            'DoCmd RunSql query,True ' True should fail so transactions can be reverted
            'We are only doing this so DoCmd.RunSQL query, true can be directly replaced by helper.Execute query, true.
            Options = dbFailOnError
        End If
    End If

    'Preprocessing the sql command to remove single table updates
    Query = FnQueryReplaceSingleTableUpdateStatements(Query)

    'Execute the command
    If ((Not IsMissing(Options)) And (CLng(Options) > 0)) Then
        currentDb.Execute Query, Options
    Else
        currentDb.Execute Query
    End If

End Function

Public Function FnQueryReplaceSingleTableUpdateStatements(Query As String) As String
    ' ON November 2019 Microsoft released a buggy security update that affected single table updates.
    '/programming/58832269/getting-error-3340-query-is-corrupt-while-executing-queries-docmd-runsql

    Dim singleTableUpdate   As String
    Dim tableName           As String

    Const updateWord        As String = "update"
    Const setWord           As String = "set"

    If IsBlank(Query) Then Exit Function

    'Find the update statement between UPDATE ... SET
    singleTableUpdate = FnQueryContainsSingleTableUpdate(Query)

    'do we have any match? if any match found, that needs to be preprocessed
    If Not (IsBlank(singleTableUpdate)) Then

        'Remove UPDATe keyword
        If (VBA.Left(singleTableUpdate, Len(updateWord)) = updateWord) Then
            tableName = VBA.Right(singleTableUpdate, Len(singleTableUpdate) - Len(updateWord))
        End If

        'Remove SET keyword
        If (VBA.Right(tableName, Len(setWord)) = setWord) Then
            tableName = VBA.Left(tableName, Len(tableName) - Len(setWord))
        End If

        'Decide which method you want to go for. SingleRow table or Select?
        'I'm going with a fake/dual table.
        'If you are going with update (select * from T) as T, make sure table aliases are correctly assigned.
        tableName = gDll.sFormat("UPDATE {0},{1} SET ", tableName, ModTableNames.FakeTableName)

        'replace the query with the new statement
        Query = vba.Replace(Query, singleTableUpdate, tableName, compare:=vbDatabaseCompare, Count:=1)

    End If

    FnQueryReplaceSingleTableUpdateStatements = Query

End Function

Public Function FnQueryContainsSingleTableUpdate(Query As String) As String
    'Returns the update ... SET statment if it contains only one table.

    FnQueryContainsSingleTableUpdate = ""
    If IsBlank(Query) Then Exit Function

    Dim pattern     As String
    Dim firstMatch  As String

    'Get the pattern from your settings repository or hardcode it.
    pattern = "(update)+(\w|\s(?!join))*set"

    FnQueryContainsSingleTableUpdate = FN_REGEX_GET_FIRST_MATCH(Query, pattern, isGlobal:=True, isMultiline:=True, doIgnoreCase:=True)

End Function

Public Function FN_REGEX_GET_FIRST_MATCH(iText As String, iPattern As String, Optional isGlobal As Boolean = True, Optional isMultiline As Boolean = True, Optional doIgnoreCase As Boolean = True) As String
'Returns first match or ""

    If IsBlank(iText) Then Exit Function
    If IsBlank(iPattern) Then Exit Function

    Dim objRegex    As Object
    Dim allMatches  As Variant
    Dim I           As Long

    FN_REGEX_GET_FIRST_MATCH = ""

   On Error GoTo FN_REGEX_GET_FIRST_MATCH_Error

    Set objRegex = CreateObject("vbscript.regexp")
    With objRegex
        .Multiline = isMultiline
        .Global = isGlobal
        .IgnoreCase = doIgnoreCase
        .pattern = iPattern

        If .test(iText) Then
            Set allMatches = .Execute(iText)
            If allMatches.Count > 0 Then
                FN_REGEX_GET_FIRST_MATCH = allMatches.item(0)
            End If
        End If
    End With

    Set objRegex = Nothing

   On Error GoTo 0
   Exit Function

FN_REGEX_GET_FIRST_MATCH_Error:
    FN_REGEX_GET_FIRST_MATCH = ""

End Function

ตอนนี้แค่CTRL+F

ค้นหาและแทนที่docmd.RunSQLด้วยhelper.Execute

ค้นหาและแทนที่[currentdb|dbengine|or your dbobject].executeด้วยhelper.execute

มีความสุข!


0

ตกลงฉันจะตีระฆังที่นี่เช่นกันเพราะถึงแม้ว่าปัญหานี้จะได้รับการแก้ไขแล้ว แต่การแก้ไขนั้นยังไม่ได้เกิดขึ้นอย่างสมบูรณ์ผ่านองค์กรต่างๆที่ผู้ใช้อาจไม่สามารถอัปเดตได้ (เช่นนายจ้างของฉัน ... )

DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1"นี่คือวิธีแก้ปัญหาของฉัน เพียงแค่แสดงความคิดเห็นแบบสอบถามที่ละเมิดและวางรหัสด้านล่าง

    'DoCmd.RunSQL "UPDATE users SET uname= 'bob' WHERE usercode=1"
    Dim rst As DAO.Recordset
    Set rst = CurrentDb.OpenRecordset("users")
    rst.MoveLast
    rst.MoveFirst
    rst.FindFirst "[usercode] = 1" 'note: if field is text, use "[usercode] = '1'"
    rst.Edit
    rst![uname] = "bob"
    rst.Update
    rst.Close
    Set rst = Nothing

ฉันไม่สามารถพูดได้ว่ามันสวย แต่ทำงานได้สำเร็จ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.