MS-Access 2003 trigger an append query from a command button click - sql

I have an append query that I would like to trigger off of a command button click. I have my splash screen with a command button that executes a Close & Open command. I want to combind the append query to execute during this click event.
My VBA for the splash screen
Option Compare Database
Private Sub SplCls_Click()
On Error GoTo Err_SplCls_Click
DoCmd.Close
stDocName = "Switchboard"
DoCmd.OpenForm stDocName
Exit_SplCls_Click:
Exit Sub
Err_SplCls_Click:
MsgBox Err.Description
Resume Exit_SplCls_Click
End Sub
I know enoug to know it needs to go in between the DoCmd.Close & DoCmd.OpenForm. The Append query is named "qry_YOS" Any guidance on this segment of code would be greatly appreciated.

Use the DAO Database Excute method to run your append query. If you want that to happen between .Close and .OpenForm ...
DoCmd.Close ' close what? If it works, fine. '
CurrentDb.Execute "qry_YOS", dbFailonerror
stDocName = "Switchboard"
DoCmd.OpenForm stDocName
BTW, always include Option Explict in the Declarations of your code modules like this:
Option Compare Database
Option Explicit
From the VB Editor's main menu, select Tools->Options. Then on the Editor tab of the Options dialog, place a check mark next to "Require Variable Declaration". That setting will ensure Option Explict is included in all new code modules. I strongly recommend you manually add it to any of your existing code modules which don't already have it. Then choose Debug->Compile from the VB Editor's main menu and fix anything the compiler complains about. Hopefully that won't be too much, but in the long run it's a good investment.
Life as a VBA developer without Option Explicit is unnecessarily complicated. Just always use it to save yourself grief. You can thank me later. :-)

Related

How can I quickly start typing SQL in Microsoft Access?

In Microsoft Access 2016, I would like to click somewhere and start typing SQL of new query right away. But the shortest way to start typing SQL (which I found so far) is:
Select menu Create > Query Design.
In Show Table window, press Close button.
Switch to SQL view.
Start typing SQL.
Too cumbersome. Can be the above steps 1–3 reduced to a shorter procedure? Did I overlook some command?
The fastest I can do is to put commands for steps 1 and 3 to Quick Access Toolbar and then I can for example do Alt+5, Esc, Alt+6. But this still only executes steps 1–3.
The function below creates or alters a simple placeholder query, opens it in Design View, switches to SQL View with its text highlighted, and then deletes the text.
Use the function as the RunCode action of a macro and add the macro to the Quick Access Toolbar. Then you can click that icon and start typing your SQL.
Public Function NewQuery()
Const cstrQueryName As String = "USysQuery0"
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strSql As String
strSql = "SELECT Date() AS Today;"
Set db = CurrentDb
For Each qdf In db.QueryDefs
If qdf.Name = cstrQueryName Then
Exit For
End If
Next
If qdf Is Nothing Then
Set qdf = db.CreateQueryDef(cstrQueryName)
End If
qdf.SQL = strSql
qdf.Close
DoCmd.OpenQuery cstrQueryName, acViewDesign
DoCmd.RunCommand acCmdSQLView
DoCmd.RunCommand acCmdDelete
End Function
Option 1: deal with it.
By default, Access doesn't support anything faster than this.
Option 2: create a macro in your Access database to automate the task, and bind this to a key combination
You could write a macro to automate command bar actions, and bind that macro to a shortcut. I currently don't have time to look up the required commands but am certain it's possible.
Option 3: buy a plugin
There are plugins out there that immediately go to SQL view, support having the SQL and results on the same pane, have syntax highlighting, etc.
An example of such a plugin is Access SQL editor (I'm not affiliated in any way)
Option 4: Create your own.
Writing your own SQL editor that's better than what Access offers by default is very simple, because Access offers very little by default.
You can start off with a form with a textbox that takes the SQL, a save button, an execute button (requires a little VBA), and a subform that displays the query results. Then you already have something that allows you to open it and start typing right away.
While waiting for better answer, I created an AutoHotKey solution – a keyboard shortcut (restricted only to Access) to perform the above steps in English language version of Microsoft Access 2016:
SendMode Input ; // Choose mode of sending keystrokes
#IfWinActive, ahk_class OMain ahk_exe MSACCESS.EXE ; // Only in scope of MS Access app
+^n:: ; // Routine for Ctrl+Shift+N starts
Send !cqd ; // Run "Query Design" menu command
WinWaitActive,Show Table ahk_class #32770 ; // Wait for "Show Table" window
Send {Esc}!jqwq{End}{Left}{Space} ; // Send the rest of the keys
Return
#IfWinActive ; // end of #IfWinActive section
After pressing Ctrl+Shift+N and waiting a bit*, a new query window is open in SQL view and I can start typing SQL.
*) Sometimes, MS Access can be really slow on keyboard shortcuts accessing the ribbon and on switching from query Design View to SQL View.

Disable Save As but not Save in Word 2010

I am looking to disable Save As in a Word 2010 file but still allow save. In other words I want users to be able to update the existing file but not create copies. I realize that this is impossible to truly do for people who know workarounds but for the general user I have successfully done this in Excel but am pretty new to word VBA.
When I add the following to a brand new document everything works as intended:
Sub FileSaveAs()
MsgBox "Copies of this file cannot be created. Please save changes in the original document." & _
, , "Copy Cannot be Created"
End Sub
My document has other macros for various command buttons but none of them involve saving the document (under original name or save as). There is also a macro running on open but that is 1 line going to a bookmark. When I try to "save as" in this document I get the message box as intended. When I try to "save" though things get strange: I get the save as dialogue (problem 1). Whether I try to save either under same name or other name the dialogue behaves as it normally would except it doesn't save and the dialogue box opens again automatically essentially creating an endless loop until I hit cancel (problem 2). I also intermittently get a "disk is full" warning pop-up after trying to save which I can dismiss but appears a few minutes later as long as he file is open (perhaps related to autosave?)
Since the macro works in the test file I assumed this strange behavior must be something elsewhere in my code but my document with the other macros saves normally as long as I don't include the save as code above so now I'm totally confused. Before I put up the rest of my code which is lengthy and for the reasons stated above I would not think impact things, I figured I'd ask this:
1. Is there any place other than my other command button macros that could be causing this behavior?
2. Is there a better method people recommend to achieve my ultimate goal of disabling save as but not save?
Thanks in advance for any advice you can provide.
The Word application has a DocumentBeforeSave event. To enable application events I suggest to create a class module by the name of ThisApplication and paste the following code into it.
Option Explicit
Private WithEvents App As Application
Private Sub Class_Initialize()
Set App = Word.Application
End Sub
Private Sub App_DocumentBeforeSave(ByVal Doc As Document, _
SaveAsUI As Boolean, _
Cancel As Boolean)
If SaveAsUI Then
MsgBox "Please always use the ""Save"" command" & vbCr & _
"to save this file.", _
vbExclamation, "SaveAs is not allowed"
Cancel = True
End If
End Sub
Add the following code to your ThisDocument module.
Dim WdApp As ThisApplication
Private Sub Document_Open()
Set WdApp = New ThisApplication
End Sub
You may add the Set App = ... line to your existing Document_Open procedure. After the WdApp variable has been initialised all application events will be received by the ThisApplication class where the DocumentBeforeSave event procedure is programmed not to allow SaveAs.
Of course, this is a blanket refusal for all documents. Therefore you may wish to add code to the procedure to limit the restriction to certain documents only. The proc receives the entire document object with all its properties, including Name, Path, FullName and built-in as well as custom properties. You can identify the files you wish to be affected by any of these.
Note that the WdApp variable will be erased in case of a program crash. If this happens the application events will no longer fire. It may be useful to know that application events occur before document events. This is if you wish to use the application's DocumentOpen event as well as or instead of the document's Document_Open event.

Access VBA unable to refresh a form

I have a form (frmDropDownEdit) that has a filtered table as the data. A "New" button is created that opens another form (frmDropDownNew) and the user can enter new data. When complete the new form is closed and the user is back to the original form. The code for frmDropDownNew correctly add the info to the table, then the code refreshes the frmDropDownEdit form but it does not refresh. If I click the refresh button in the ribbon, it also does not refresh. But refresh all does work.
How can I have my code refresh the data in frmDropDownEdit. I also put code me.refresh on the OnGotFocus event but that does not even run.
Here is my source code
Private Sub Command5_Click()
'Add Button
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("tblDropDown")
rst.AddNew
rst!DdCategory = Me.txtCategory.Value
rst!DdDescription = UCase(Me.txtDescription.Value)
rst.Update
rst.Close
DoCmd.Close
Forms!frmDropDownEdit.Refresh
End Sub
On my MS Access 2010 ×64 single user PC, Forms![AnyForm] .Refresh never worked in VBA, independently where it is placed in any database's code. Form_Current() doesn't run either as it should after data are modified (verified by putting a Stop therein). Moreover, records with modified data are neither marked dirty nor refreshed before the vba code has finished. Procedures which should run without delay when data are modified don't run, even when placed into the modified fields' events.
Thus, one has to use a work-around. Many people recommend to use .Requery instead of .Refresh and then to return by vba code to the desired record, but this requires a field with a primary key.
My solution for tables without primary key is the following:
'…
' ESSENTIAL: this code must be run from ANOTHER module !
' (it runs without error in MyForm's own code [eg. in Form_Activate(),
' but then MyForm is NOT immediately refreshed as desired,)
' one still has to repeat these steps by hand afterwards…
DoCmd.GoToRecord acForm, "MyForm", acNext
DoCmd.GoToRecord acForm, "MyForm", acPrevious
' NB: Forms![MyForm].Refresh doesn't work
' at this place in "MyOtherModule" either.
'…
As mentioned in above code comments: this code must be run from another module ("MyOtherModule") - in my case, a form-independent procedure called upon closing a pop-up form opened from the first form, which interactively modifies data. These data should be updated/refreshed immediately when closing the pop-up form, reflecting all changes and their consequences (for example, automatic filling-in/deleting of other data and/or en/disabling controls or making them [in]visible, depending on the modified fields' values).

User level security?

I have a table that has usernames, passwords, and a yes/no column for isadmin.
How do I make it so if they login with an account that has a check mark under "isadmin" they get access to design view, the ribbon, etc? Though if they log in with an account that doesn't have a check mark under the isadmin box they only can view the forms, not edit them, and the ribbon is inaccessible?
I just don't know where to start, as I had assumed there was a way to save the database as a seperate copy that only users can view forms in, and if the admin runs his copy he gets all the changes to the tables (via the forms) the users made. So when the admin edits a form, and saves it it doesn't remove all the user's data as when it was saved, it was saved to the admin's copy too. I'm really confused.
I am using Access 2013
This is a simple solution for user level security being removed in newer releases of Access; using a lot of VBA.
STEP 1: Creating The Table
First, create a table. I will name mine LogininfoT. Now, for the columns inside of the table, name them EmployeeID, LoginID, LoginPassword, EmployeeName, and lastly IsAdmin. Make EmployeeID your key, and IsAdmin a YES/NO field.
For testing, add two users to this table. With this information:
EmployeeID LoginID LoginPassword EmployeeName IsAdmin
1 1111 1234 Bob [x]
2 2222 1234 Stewert [ ]
STEP 2: Creating The Forms
Now that we have the table made, let's design the form to use this set of data.
I will name my form LoginF. Go into design view, and slap down a text box, a combo box, and a button. For the combo box rename the text to say something like Login ID (you can change this to whatever fits your need) and for the text box, put the text as Password (once again, change this to whatever you want it doesn't effect the outcome). The text in the button can be whatever you want, I will be putting Login on it.
Click the combo box and rename it. I will be naming it LoginCmBx. Next, click the text box and rename it, I will be naming it PasswordTxt. Lastly, click the button and rename it, I will be naming it LoginBtn.
Click the combo box again and under the event tab, go into the After Update scripting. Use code and type this in:
Private Sub LoginCmBx_AfterUpdate()
Me.PasswordTxt.SetFocus
End Sub
This makes it so after you select a username, it automatically puts the focus onto the password text box so you can start typing right away without using TAB on your keyboard, or using your mouse.
Next, go to the button and under the event tab, go into the On Click scripting. Use code and type this in:
Private Sub LoginBtn_Click()
If IsNull(Me.LoginCmBx) Or Me.LoginCmBx = "" Then
MsgBox "You must enter a User Name.", vbOKOnly, "Required Data"
Me.LoginCmBx.SetFocus
Exit Sub
End If
If IsNull(Me.PasswordTxt) Or Me.PasswordTxt = "" Then
MsgBox "You must enter a Password.", vbOKOnly, "Required Data"
Me.PasswordTxt.SetFocus
Exit Sub
End If
If Me.PasswordTxt.Value = DLookup("LoginPassword", "LoginInfoT", _
"[EmployeeID]=" & Me.LoginCmBx.Value) Then
EmployeeID = Me.LoginCmBx.Value
On Error Resume Next
DoCmd.DeleteObject acQuery, "IsAdminQ"
On Error GoTo Err_LoginBtn_Click
Dim qdef As DAO.QueryDef
Set qdef = CurrentDb.CreateQueryDef("IsAdminQ", _
"SELECT IsAdmin " & _
"FROM LoginInfoT " & _
"WHERE EmployeeID = " & LoginCmBx.Value)
Exit_LoginBtn_Click:
DoCmd.Close acForm, "LoginF", acSaveNo
DoCmd.OpenForm "MenuF"
Exit Sub
Err_LoginBtn_Click:
MsgBox Err.Description
Resume Exit_LoginBtn_Click
Else
MsgBox "Password Invalid. Please Try Again", vbOKOnly, _
"Invalid Entry!"
Me.PasswordTxt.SetFocus
End If
End Sub
What this does is check if you selected a username, if not it spits out an error telling the user to select one. If you did, it checks if you entered a password. If they didn't, it spits out another error saying they didn't enter a password. If they selected both, and the password doesn't match the one in the table for the username you selected it spits out an error saying you got the password wrong. If you got the password right to the username you selected, it logs you in. It will then close the current form you are on, and open up a new one named "MenuF" it will also create a query with that little bit of information under the username you selected, either if it's an admin or not.. We haven't created MenuF yet, so lets quickly do that. We aren't done with LoginF just quite yet though, so be prepared to come back to that later!
Create the form, and put down a button. Here is your menu form, you can create as many buttons as you want going to other forms or even just put a subform on here and have your entire database. Taht button you put down, you can name the text to whatever you want. I put mine as Log out. Name the button MenuLogOutBtn. Go into the event tab, and under the On Click scripting click code and type this in:
Private Sub MenuLogOutBtn_Click()
DoCmd.DeleteObject acQuery, "IsAdminQ"
DoCmd.OpenForm "LoginF"
DoCmd.Close acForm, "MenuF", acSaveNo
End Sub
What this does is delete the query the login button created, opens the login form again, and closes the menu. Simple!
Now I need you to throw down a checkbox, and name it MyCheckbox. This box requires no special coding, or control sources. Though I do suggest changing visible as no, and deleting the text that comes along with it.
Now, go to the form's event properties and under the Open scripting go to code and type this in:
Private Sub Form_Open(Cancel As Integer)
Me.MyCheckbox.Value = GetLoginStateIsAdmin()
If GetLoginStateIsAdmin = True Then
Me.ShortcutMenu = True
DoCmd.ShowToolbar "Ribbon", acToolbarYes
DoCmd.ShowToolbar "Menu Bar", acToolbarYes
Application.SetOption "ShowWindowsinTaskbar", True
DoCmd.SelectObject acTable, , True
Else
Me.ShortcutMenu = False
DoCmd.ShowToolbar "Ribbon", acToolbarNo
DoCmd.ShowToolbar "Menu Bar", acToolbarNo
Application.SetOption "ShowWindowsinTaskbar", False
DoCmd.NavigateTo "acNavigationCategoryObjectType"
DoCmd.RunCommand acCmdWindowHide
End If
End Sub
What this does is checkbox's information which is attached to query's IsAdmin column and give GetLoginStateIsAdmin that boolean variable. After it does that, it starts a simple If statement that turns off menu bars and disabled right click if you aren't an admin; if you are, it allows you do right click and all menu bars are visible.
Though if you didn't notice yet, our checkbox doesn't get the information from the query yet! Oh no!
STEP 3: Creating The Public Modules
If you were on your toes, you would notice even the login code wouldn't work at this point. First, we need some public modules. Go to the Create tab in the ribbon, and create a module. Type this in:
Public EmployeeID As Long
Save this module as LoginModule.
Create another module, and type this in:
Function GetLoginStateIsAdmin()
'
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("IsAdminQ")
GetLoginStateIsAdmin = Nz(rst(0), False)
Set rst = Nothing
'
End Function
Save this one as GetAdmin.
Lets create one more module; so the user opening the database can't by bass stuff by using the shift key to launch it.
Type this in it:
Function ap_DisableShift()
'This function disable the shift at startup. This action causes
'the Autoexec macro and Startup properties to always be executed.
On Error GoTo errDisableShift
Dim db As DAO.Database
Dim prop As DAO.Property
Const conPropNotFound = 3270
Set db = CurrentDb()
'This next line disables the shift key on startup.
db.Properties("AllowByPassKey") = False
'The function is successful.
Exit Function
errDisableShift:
'The first part of this error routine creates the "AllowByPassKey
'property if it does not exist.
If Err = conPropNotFound Then
Set prop = db.CreateProperty("AllowByPassKey", _
dbBoolean, False)
db.Properties.Append prop
Resume Next
Else
MsgBox "Function 'ap_DisableShift' did not complete successfully."
Exit Function
End If
End Function
Save that as ShiftModule.
We are done the modules! Lets go back to the LoginF now.
STEP 4: Finishing Up LoginF
Go to the form's event tab, and click the on load scripting. Click code, then type this in:
Private Sub Form_Load()
On Error Resume Next
DoCmd.DeleteObject acQuery, "CustomerMoreInfoQ"
End Sub
What this does is make sure that the query the login button creates is deleted when this form starts up, just in case the user closes the database without logging out. So if you click login, it won't cause errors because the query isn't still there.
STEP 5: Testing It Out.
Run the form LoginF in form view, and select Bob as the username. Type in the password 1234 into the password text box, and click login. It should open up the MenuF and you see all menus and you can right click. Good. Now, log out and login with Stewert, using the same password. Now you see all the menus remove themselves, and you can't right click! Yay!
For extra security, in the LoginF's Other tab, make sure Shortcut Menu is set to No. This will set right click to be disabled always; as you aren't logged in as a user at this point. It doesn't know if you are an admin or not.
STEP 6: Disabling The Toolbars On Start Up & launching LoginF On Start Up.
Go to File > Options > Current Database.
Under Display Form, select FormF.
Under the Navigation section, unclick Display Navigation Pane.
Click okay, then go back to LoginF; go into the On Load code and add this just before the End Sub:
DoCmd.ShowToolbar "Ribbon", acToolbarNo
You are done! Save your database, then close it and open it again. It should load the LoginF form where you can't right click, there are no menus etc. The only way to get the menus to edit things is to log into an admin account!
Step 7: Expanding
This doesn't automatically expand the more you add forms though. You need to add that checkbox named MyCheckbox (I suggest copy + pasting it) to each form you add, and add this code to each form you add:
Private Sub Form_Open(Cancel As Integer)
Me.MyCheckbox.Value = GetLoginStateIsAdmin()
If GetLoginStateIsAdmin = True Then
Me.ShortcutMenu = True
Else
Me.ShortcutMenu = False
End If
End Sub
Though once you do that to every form, the security works and you need to log in to an admin account to change anything. If you are just a user, you can use the form normally (click buttons, edit data on subforms, etc) You can't edit the form it self though.

Make a Query in MS Access default to landscape when printed

How can I programmatically make a query in MS Access default to landscape when printed, specifically when viewing it as a PivotChart? I'm currently attempting this in MS Access 2003, but would like to see a solution for any version.
The following function should do the trick:
Function SetLandscape()
Application.Printer.Orientation = acPRORLandscape
End Function
Should be able to call this from the autoexec function to ensure it always runs.
Yes ahockley's call sets the application's printer orientation to landscape. I tried an experiment and it worked well. I know this doesn't produce a pivot table, but I didn't setup one to use, so it opens and prints a regular query.
Private sub
Application.Printer.Orientation = acPRORLandscape
DoCmd.OpenQuery "qry1", acViewNormal, acReadOnly
DoCmd.PrintOut acPrintAll
End Sub
If you want to close the query after printing it, add:
docmd.Close acQuery, "qry1", acSaveNo