Does MS Access support stored procedures on .accdb or .mdb databases? Or are stored procedures only supported when the backend is SQL Server or something else that supports an Access DB engine (Jet / ACE/ MSDE)?
Information is mixed and not quite complete from what I have found on MS Access and Stored Procedures from various sources. For example this Access help file initially looks like Access supports stored procedures.
https://support.microsoft.com/en-us/office/create-procedure-statement-91c700d1-8076-4040-896a-a0b7cf9d9888?ns=msaccess&version=90&ui=en-us&rs=en-us&ad=us
When I try to run the following query, it errors saying I have incorrect syntax for CREATE TABLE statement. The table is in an .accdb file on my local laptop.
CREATE PROCEDURE GetReport (pFileId Integer)
AS
SELECT * FROM FileInfoTable WHERE FileId = pFileId
Some Access DDL features are only available when the statement is executed with ADO. Your statement will succeed if you execute it from CurrentProject.Connection.Execute as this Immediate window example demonstrates:
strSql = "CREATE PROCEDURE GetReport (pFileId Integer)" & vbCrLf & _
"AS" & vbCrLf & _
"SELECT * FROM FileInfoTable WHERE FileId = pFileId"
CurrentProject.Connection.Execute strSql
However notice that the SQL text in the saved query object does not exactly match the text in the CREATE PROCEDURE statement. But I think it's functionally equivalent.
Debug.Print CurrentDb.QueryDefs("GetReport").SQL
PARAMETERS pFileId Long;
SELECT *
FROM FileInfoTable
WHERE FileId = pFileId;
Well, yes, access does have what is called table triggers, and access also has what we call stored procedures (procedural code that can run at the table level - or in fact you can even call such stored procedures from VBA, or macros).
However, just like MySQL, SQL server, Oracle and more? They ALL HAVE their OWN type of code system for these stored procedures. Access is no different.
This feature and ability was introduced in Access 2010. However, this feature, this ability has ZERO to do with the SQL supported CREATE procedure command.
That command was introduced to give "some" compatibility with SQL Server syntax - but it is quite lame, and limited. WHEN you use CREATE PROCEDURE in Access SQL, it ONLY creates a select command. As such, the select command is JUST THAT - ONLY a select command and is NOT procedural code.
However, as noted, you can write stored procedures in Access, and they run by the data engine, and they run at engine level. To write these routines, you have to use the macro language. This language is NOT VBA, and not T-SQL (SQL Server code), but Access has its OWN syntax and code.
These so called table routines are thus created when working on a table in design mode.
While such code is limited, it is REAL procedural code, does not use SQL syntax in most cases, and such routines can be called from table events.
And these so called "data macros" are not created with SQL data create commands, you are limited to using the built in macro editor for this purpose.
Keep in mind that while Access has this stored procedure code ability, they are not transaction based. But, they can be of GREAT use, since they even function when using OLEDB or ODBC sources to Access.
So, if you write such code, and then say open Access with FoxPro, or even c# in .net? And then you update a row? The procedural table code and triggers WILL run.
You can see these options here:
So, I could for example maintain the total cost of an invoice for each change, or edit, or adding of rows to a sub form.
The macro language editor looks like say this:
So you can loop over data, you have if/then else etc.
It is a very limited language - but they are in fact true real stored procedure code that runs at the table level, and they run 100% independent of VBA or any other code.
And these table stored procedures run:
when edit data in a form - even forms without code
when you issue SQL update or modify statements
when you modify data via VBA + recordset code
if an external ODBC or OLEDB source such as .net c# or whatever modifies data
Related
I am creating an ETL in SSIS in which I which I want my data source to be a restricted query, like select * from table_name where id='Variable'. This variable is what I defined as User created variable.
I do not understand how I can have my source query interact with the SSIS scoped Variable.
The only present options are
Table
Table from variable
SQL Command
SQL command from a variable
What I want is to have a SQL statement having a variable as parameter
Simple. Choose SQL command as the Data Access Mode. Enter your query with a question mark as a parameter placeholder. Then click the Parameters button and map your variable to Parameter0 in the Set Query Parameters dialog:
More information is available on MSDN.
An inferior alternative to #Edmund's approach is to use an Expression on another Variable to build your string. Assuming you have #[User::FirstName] already defined, you would then create another variable, #[User::SourceQuery].
In the properties for this variable, set EvaluateAsExpression to True and then set an Expression like "SELECT FirstName, LastName, FROM Person.Person WHERE FirstName = '" + #[User::FirstName] +"'" The double quotes are required because we are building an SSIS String.
There are two big reasons this approach should not be implored.
Caching
This approach is going to bloat your plan cache in SQL Server with N copies of essentially the same query. The first time it runs and the value is "Edmund" SQL Server will create an execution plan and save it (because it can be expensive to build them). You then run the package and the value is "Bill". SQL Server checks to see if it has a plan for this. It doesn't, it only has one for Edmund and so it creates another copy of the plan, this time hard coded to Bill. Lather-rinse-repeat and watch your available memory dwindle until it unloads some plans.
By using the parameter approach, when the plan is submitted to SQL Server, it should be creating a parameterized version of the plan internally and assumes that all parameters supplied will result in equal costing executions. Generally speaking, this is the desired behaviour.
If your database is optimized for ad-hoc workload (it's a setting turned off by default), that should be mitigated as every plan is going to get parameterized.
SQL Injection
The other big nasty you will run into with building your own string is that you open yourself up to SQL Injection attacks or at the least, you can get runtime errors. It's as simple as having a value of "d'Artagnan." That single quote will cause your query to fail resulting in package failure. Changing the value to "';DROP TABLE Person.Person;--" will result in great pain.
You might think it's trivial to safe quote everything but the effort of implementing it consistently everywhere you query is beyond what your employer is paying you. All the more so since there is native functionality provided to do the same thing.
When using OLEDB Connection manager (with SQL Server Native Client 11.0 provider in my case) you can catch an error like this:
Parameters cannot be extracted from the SQL command. The provider
might not help to parse parameter information from the command. In
that case, use the "SQL command from variable" access mode, in which
the entire SQL command is stored in a variable.
So you need to explicitly specify database name in OLEDB Connection manager properties. Otherwise SQL Server Native Client can use different database name then you mean (e.g. master in MSSQL Server).
For some cases you can explicitly specify database name for each database object used in query, e.g.:
select Name
from MyDatabase.MySchema.MyTable
where id = ?
We host multiple SQL Server 2008 databases provided by another group. Every so often, they provide a backup of a new version of one of the databases, and we run through a routine of deleting the old one, restoring the new one, and then going into the newly restored database and adding an existing SQL login as a user in that database and assigning it a standard role that exists in all of these databases.
The routine is the same, except that each database has a different name and different logical and OS names for its data and log files. My inclination was to set up an auxiliary database with a table defining the set of names associated with each database, and then create a stored procedure accepting the name of the database to be replaced and the name of the backup file as parameters. The SP would look up the associated logical and OS file names and then do the work.
This would require building the commands as strings and then exec'ing them, which is fine. However, the stored procedure, after restoring a database, would then have to USE it before it would be able to add the SQL login to the database as a user and assign it to the database role. A stored procedure can't do this.
What alternative is there for creating an automated procedure with the pieces filled in dynamically and that can operate cross-database like this?
I came up with my own solution.
Create a job to do the work, specifying that the job should be run out of the master database, and defining one Transact-SQL step for it that contains the code to be executed.
In a utility database created just for the purpose of hosting objects to be used by the job, create a table meant to contain at most one row, whose data will be the parameters for the job.
In that database, create a stored procedure that can be called with the parameters that should be stored for use by the job (including the name of the database to be replaced). The SP should validate the parameters, report any errors, and, if successful, write them to the parameter table and start the job using msdb..sp_start_job.
In the job, for any statement where the job needs to reference the database to be replaced, build the statement as a string and EXECUTE it.
For any statement that needs to be run in the database that's been re-created, doubly-quote the statement to use as an argument for the instance of sp_executesql IN THAT DATABASE, and use EXECUTE to run the whole thing:
SET #statement = #dbName + '..sp_executesql ''[statement to execute in database #dbName]''';
EXEC (#statement);
Configure the job to write output to a log file.
I have been following Richard Siddaway's Awesome Series on Powershell+Access2007.
Unfortunately it ends before discussing creating/running/modifying access 2007 queries in powershell. How could this be done?
The cited series of articles uses a definition of stored procedure that is problematic. It says:
An SP is a piece of code that we have
defined, and saved in the database".
While this may be correct in a metaphorical sort of way, it's incorrect for Access/Jet/ACE. There is no CODE in the objects in a Jet/ACE database that are referred to by the generic term "procedure. In Access/Jet/ACE, a "procedure" is just a stored QueryDef, as there is no procedural code allowed. I don't know if the OLEDB interface restricts it or not, but my guess is that PROCEDURE means DML query and VIEW means SELECT.
So (and I'm just guessing here -- I'm an Access developer so have no need for doing any of this externally), if you want to create/update a DML QueryDef, you'd use the PROCEDURE keyword and the relevant DML for creating/altering PROCEDUREs. Likewise, with SELECTs, you'd use VIEW (I'm assuming).
I wanted to find out if it is possible to call MS Access Stored Queries with parameters using DAAB.
I am using the Northwind sample database to test this scenario I have created the following Stored Query with parameter in MS Access:
PARAMETERS FirstName Text ( 255 );
SELECT Employees.ID
FROM Employees
WHERE (((Employees.[First Name])=[#FirstName]));
This query is stored with name: GetEmployeeIDByName
I have created a wrapper over the DAAB to allow access to various databases like SQL, Oracle, any OLEDB and and ODBC database.
Below is the sample code for my test:
Database db = new GenericDatabase("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=C:\Database\Access\Northwind 20071.accdb",OleDbFactory.Instance);
DbCommand cmd = db.GetStoredProcedure("GetEmployeeIDByName");
db.AddInParameter(cmd,"#FirstName",DbType.String,40);
object employeeID = db.ExecuteScalar();
I get an error Invalid Operation. I am not sure if I am calling the stored Queries correctly as I am able to call Stored Queries that do not have any parameter without any errors.
I was able to resolve the issue. The issue was with the Northwind sample database. I then imported Northwind database from SQL Server into MS Access and also created the stored queries in MS Access. Here is the detailed discussion that I had with the Enterprise Library DAAB's team: entlib.codeplex.com/Thread/View.aspx?ThreadId=223653 Hope it helps. Access does not care about the # character you can call the parameter with or without the # character.
How do I make a stored procedure in MS Access?
Access 2010 has both stored procedures, and also has table triggers. And, both features are available even when you not using a server (so, in 100% file based mode).
If you using SQL Server with Access, then of course the stored procedures are built using SQL Server and not Access.
For Access 2010, you open up the table (non-design view), and then choose the table tab. You see options there to create store procedures and table triggers.
For example:
Note that the stored procedure language is its own flavor just like Oracle or SQL Server (T-SQL). Here is example code to update an inventory of fruits as a result of an update in the fruit order table
Keep in mind these are true engine-level table triggers. In fact if you open up that table with VB6, VB.NET, FoxPro or even modify the table on a computer WITHOUT Access having been installed, the procedural code and the trigger at the table level will execute. So, this is a new feature of the data engine jet (now called ACE) for Access 2010. As noted, this is procedural code that runs, not just a single statement.
If you mean the type of procedure you find in SQL Server, prior to 2010, you can't. If you want a query that accepts a parameter, you can use the query design window:
PARAMETERS SomeParam Text(10);
SELECT Field FROM Table
WHERE OtherField=SomeParam
You can also say:
CREATE PROCEDURE ProcedureName
(Parameter1 datatype, Parameter2 datatype) AS
SQLStatement
From: http://msdn.microsoft.com/en-us/library/aa139977(office.10).aspx#acadvsql_procs
Note that the procedure contains only one statement.