How to run thousands of queries in Ms Access? - sql

I've discovered the SQL VIEW in Ms Access to execute some queries, but I need to execute about 20.000 UPDATE queries I have in a .sql file.
When I paste in the SQL VIEW it says the "Text is too long to modify".
How can I run those UPDATE's ?

The limit to the number of characters in an Access SQL query is "about 64000" - see here https://support.office.com/en-us/article/Access-2010-specifications-HA010341462.aspx. And unfortunately you cannot execute multiple statements in a query. I think this will mean quite a bit of work for you in VBA. Here is an example approach (pseudocode):-
open file
read line into variable
while not EOF
currentdb.execute variable, dbfailonerror
read next line
wend
close file
Probably a nasty surprise for you if you are used to executing huge batches of statements using other RDBMS!
An alternative suggestion: we don't know exactly what your file looks like or where it comes from, but if it is generated from another RDBMS which you have access to, then I would very strongly recommend that you set up an ODBC connection to it, and query out the data you need (either by linking the tables or writing a pass through query), then inserting into your local Access tables. This will be many orders of magnitude faster than executing thousands of individual statements.
If your only source of the data is the SQL statements then you may still be better of if you can parse the SQL text into relevant columns (for example PK, and value to be updated, or if inserting, then all column values), then save as a csv file, import into Access, add keys as necessary, and then run a single update statement as an updateable query against the imported data and the existing tables. Dumping the file into Excel and using the various string functions may enable you to parse the data quite quickly.

There may be an easier way but you could write VBA code that reads the text file line by line and then uses DoCmd.RunSQL to run each query.

Related

Fill SQL temp table from results AFTER execution of SPROC

Is there a way to fill a temp table/other SQL variable after a SPROC has been executed?
I have the SQL results sitting in the SSMS results window, but I don't want to re-run the SPROC to fill a temp table because it takes over an hour.
I can export to CSV and re-import (using OPENROWSET, which is always difficult), but I was curious if there are any more elegant solutions?
I've run into this several times and have not found anything simple..
There's no way.
Also, watch out exporting from SSMS to CSV because
a)It formats things (especially dates and numbers) and
b)It truncates columns (43679 chars max, which might sound a lot but gets used up quickly if XML).
So your export might not be a true representation of results.

How to query access table with a subdatasheet that requires parameters

I have been tasked with creating a method to copy the contents of an entire database to a central database. There are a number of source databases, all in Access. I've managed to copy the majority of the tables properly, 1:1. I'm using VBScript and ADO to copy the data. It actually works surprisingly well, considering that it's Access.
However
I have 3 tables that include subdatasheets (to those that don't know, a subdatasheet is a visual representation of a 1 to many relationship. You can see related records in another table inside the main table). When My script runs, I get an error. "No value given for one or more required parameters." When I open Access and try to run the same query that I've written in SQL, It pops up message boxes asking for parameters.
If I use the query wizard inside Access to build the select query, no parameters are required and I get no subdatasheet in the result set.
My question is this: how do I write a vanilla SQL query in my VBScript that does not require parameters and just gives me the data that I want?
I've tried copying the SQL from Access and running it through my VBScript and that doesn't seem to do the trick.
Any help is greatly appreciated!
As it turns out, you need to make sure that you've spelled all of the field names properly in your source query. If you've included additional fields that aren't actually in the source or destination table they'll need to be removed too.

Moving from Access backend to SQL Server as be. Efficiency help needed

I am working on developing an application for my company. From the beginning we were planning on having a split DB with an access front end, and storing the back end data on our shared server. However, after doing some research we realized that storing the data in a back end access DB on a shared drive isn’t the best idea for many reasons (vpn is so slow to shared drive from remote offices, access might not be the best with millions of records, etc.). Anyways, we decided to still use the access front end, but host the data on our SQL server.
I have a couple questions about storing data on our SQL server. Right now when I insert a record I do it with something like this:
Private Sub addButton_Click()
Dim rsToRun As DAO.Recordset
Set rsToRun = CurrentDb.OpenRecordset("SELECT * FROM ToRun")
rsToRun.AddNew
rsToRun("MemNum").Value = memNumTextEntry.Value
rsToRun.Update
memNumTextEntry.Value = Null
End Sub
It seems like it is inefficient to have to use a sql statement like SELECT * FROM ToRun and then make a recordset, add to the recordset, and update it. If there are millions of records in ToRun will this take forever to run? Would it be more efficient just to use an insert statement? If so, how do you do it? Our program is still young in development so we can easily make pretty substantial changes. Nobody on my team is an access or SQL expert so any help is really appreciated.
If you're working with SQL Server, use ADO. It handles server access much better than DAO.
If you are inserting data into a SQL Server table, an INSERT statement can have (in SQL 2008) up to 1000 comma-separated VALUES groups. You therefore need only one INSERT for each 1000 records. You can just append additional inserts after the first, and do your entire data transfer through one string:
INSERT INTO ToRun (MemNum) VALUES ('abc'),('def'),...,('xyz');
INSERT INTO ToRun (MemNum) VALUES ('abcd'),('efgh'),...,('wxyz');
...
You can assemble this in a string, then use an ADO Connection.Execute to do the work. It is frequently faster than multiple DAO or ADO .AddNew/.Update pairs. You just need to remember to requery your recordset afterwards if you need it to be populated with your newly-inserted data.
There are actually two questions in your post:
Will OpenRecordset("SELECT * FROM ToRun") immediately load all recordsets?
No. By default, DAO's OpenRecordset opens a server-side cursor, so the data is not retrieved until you actually start to move around the recordset. Still, it's bad practice to select lots of rows if you don't need to. This leads to the next question:
How should I add records in an attached SQL Server database?
There are a few ways to do that (in order of preference):
Use an INSERT statment. That's the most elegant and direct solution: You want to insert something, so you execute INSERT, not SELECT and AddNew. As Monty Wild explained in his answer, ADO is prefered. In particular, ADO allows you to use parameterized commands, which means that you don't have to put-into-quotes-and-escape your strings and correctly format your dates, which is not so easy to do right.
(DAO also allows you to execute INSERT statements (via CurrentDb.Execute), but it does not allow you to use parameters.)
That said, ADO also supports the AddNew syntax familiar to you. This is a bit less elegant but requires less changes to your existing code.
And, finally, your old DAO code will still work. As always: If you think you have a performance problem, measure if you really have one. Clean code is great, but refactoring has a cost and it makes sense to optimize those places first where it really matters. Test, measure... then optimize.
It seems like it is inefficient to have to use a sql statement like SELECT * FROM ToRun and then make a recordset, add to the recordset, and update it. If there are millions of records in ToRun will this take forever to run?
Yes, you do need to load something from the table in order to get your Recordset, but you don't have to load any actual data.
Just add a WHERE clause to the query that doesn't return anything, like this:
Set rsToRun = CurrentDb.OpenRecordset("SELECT * FROM ToRun WHERE 1=0")
Both INSERT statements and Recordsets have their pros and cons.
With INSERTs, you can insert many records with relatively little code, as shown in Monty Wild's answer.
On the other hand, INSERTs in the basic form shown there are prone to SQL Injection and you need to take care of "illegal" characters like ' inside your values, ideally by using parameters.
With a Recordset, you obviously need to type more code to insert a record, as shown in your question.
But in exchange, a Recordset does some of the work for you:
For example, in the line rsToRun("MemNum").Value = memNumTextEntry.Value you don't have to care about:
characters like ' in the input, which would break an INSERT query unless you use parameters
SQL Injection
getting the date format right when inserting date/time values

Removing unwanted SQL queries based on a condition

I have not had experience in SQL queries or SQL database , so please excuse me if my terminology is wrong.
So, I have a file containing around 17,000 SQL insert statements where I enter data for 5 columns/attributes in a database. In those 17,000 statements there are only around 1200 statements which have data for all of the 5 columns/attributes while the rest have data only for 4 columns. I need to delete all those unwanted statements( which dont have data for all 5 columns).
Is there a simple way/process to do it other than going one by one and deleting? If so, it would be great if someone could help me out with it.
A different approach from my fine colleagues here would be to run the file into a staging/disposable database. Use the delete that #Rob called out in his response to pare the table down to the desired dataset. Then use an excellent, free tool like SSMS Tools Pack to reverse engineer those insert statements.
I can think of two approaches:
1: Using SQL: insert all the data and then run a query that removes any records where it does not have all of the necessary data. If the table is not currently empty, keep track of the ID where your current data "ends" so that your query can use that as a WHERE statement.
DELETE FROM myTable WHERE a IS NULL OR b IS NULL /* etc. */
2: Process the SQL file with a regular expression: Use a text editor or command line to match either "bad" records or "good" records. Most text editors have a find and replace that allows you to use regular expressions. And command line you can use grep or other tools to process. Or even a script that parses in your language of choice, for that matter.
Open file in notepad++, replace all "bad" lines using regular expressions.

MS Access SQL DELETE - why would someone specify column names?

I'm having to support an Access .mdb file that someone else has written. One of the button functions in this .mdb calls out to delete some data in an external MSSQL database. All very straightforward, but this syntax isn't something I've seen before:
DELETE
tblEquipmentConnections.SourceEquip,
tblEquipmentConnections.EquipmentConnectionID
FROM tblEquipmentConnections
WHERE
tblEquipmentConnections.SourceEquip = [Forms]![frmEquipment]![EquipmentID];
Is that any different than this?
DELETE
FROM tblEquipmentConnections
WHERE
tblEquipmentConnections.SourceEquip = [Forms]![frmEquipment]![EquipmentID];
I can't find a case where specifying specific columns does anything - but I don't spend much time in Access, so I'm not sure how different the SQL syntax is...
Thanks!
Specifying the column names makes no difference. It's just an Access thing.
The reason they might be there is because Access used to generate DELETE statements that way (not sure if it still does).
The second form without columns names is obviously preferable.
I think the query has been built directly into Access query editor.
And generally we begin by building a select query. Then we change the query type from "Select query" to "Delete query". Then we display the query source by selecting "SQL Mode" where we copy / paste a sql statement like this one :
DELETE qc_Boxes.idBox, qc_Boxes.idScreen, qc_Boxes.title
FROM qc_Boxes;
This is absolutely redundant. The place between DELETE and FROM is used only when the deletion is performed based on a multi-table condition, but even in this case it contains table names and not field names. Also it can contain * which is also redundant. In MySQL, for example it's an incorrect syntax.