forging a sql statement that crosses db servers for use in a perl script using DBI - sql

perl 5.10
Access 2010
SqlServer 2008 R2
So I need to update a column in table A with data in table B where A and B have a column I can JOIN on.
This would work great
$sqlCmd = "UPDATE aa SET aa.foo = bb.fancyfoo " .
"FROM [dbo.serverOne] AS aa " .
"RIGHT JOIN [noteTable] AS bb " .
"ON aa.[recid] = bb.[recid] " ;
$sth = $dbh->prepare( $sqlCmd);
IF both tables were in the same database since there's only one database handle in play.
But my tables reside on different databases , and in fact in different servers -- dbo.ServerOne lives in an instance of SqlServer while noteTable resides in an Access database ( sorry ).
And for extra added spice, bb.fancyfoo is defined as a MEMO and aa.foo is defined as a nvarchar(max)
Frankly I can't see how this can be achieved in one pass - can a sql command make use of more than one db handle?
If not , and I have to use two separate commands ie an UPDATE on dbo.ServerOne and SELECT on noteTable, how do I set this up to work for MEMO/nvarchar(max) fields? I mean, how should I store the data while its in beteween tables? CLOB?
TIA,
Still-learning Steve

Your luck is in - both tables can be in the same database.
What you need to google for is "linked tables". There is a brief overview here but basically it lets you add an external table via ODBC (or other supported connection method).
You can either link the Access table in to the SQL Server DB or the other way around. Which will depend on whether the Access file is in a fixed location and where the majority of your data is. It's probably more efficient to link to the smaller from the larger.
Having said that, I'd expect SQL Server to be smarter about planning/executing the query so I'd try that first.

Since we're already schlepping data out the the Access tables into SqlServer tables I decided to do the JOIN via adding fields from both tables to a hashref keyed on the shared key field. Not as elegant as I'd like, but it works.
Thanks to all who replied!
CASE CLOSED
Still-learning Steve

Related

How to use a SQL Select statement with Power Query against an Access database?

I've got a query that joins 4 tables that I need to run against 4 different Access .mdb files (all have the same schema) so I can compare the results in Excel. Instead of creating 16 Power Queries and joining them into 4 queries (20 total query objects) I want to write a SQL statement that joins the tables and run it against each of the 4 different data sources. There's a chance that the SQL statement may need to be updated, so having it stored in one place will make future maintenance easier.
I could not find examples of this online and the way that Power Query writes M for an Access connection is based on one table at a time. I did not want a solution that used VBA.
Poking around with the various Power Query connectors I found that I can use the ODBC connector to connect to an Access database. I was able to adjust the parameters and pass it a standard SQL statement.
I put the SQL statement in a cell (C16 in the image) and named that range Package_SQL. I also have 4 cells where I put the path and filename of the 4 Access .mdb files I want to query. I name those ranges Database1 through Database4.
This is the configuration screen to set the database paths and set the SQL statement
let
// Get the Access database to work with.
dbPath = Excel.CurrentWorkbook(){[Name="Database1"]}[Content]{0}[Column1],
// Get the SQL statement from the named range
SQL = Excel.CurrentWorkbook(){[Name="Package_SQL"]}[Content]{0}[Column1],
Source = Odbc.Query("dbq=" & dbPath & "; defaultdir=C:\Temp;driverid=25;
fil=MS Access;maxbuffersize=2048;pagetimeout=5;dsn=MS Access Database", SQL),
#"Changed Type" = Table.TransformColumnTypes(Source,
{{"Issue_Date", type date}, {"Revision_Issue_Date", type date}})
in
#"Changed Type"
As you can see the magic is done in the following line. I didn't want the defaultdir to be hard coded to a folder that everyone may not have so I set it to C:\Temp. You may need to change it or even remove it and see if it makes a difference.
Source = Odbc.Query("dbq=" & dbPath & "; defaultdir=C:\Temp; driverid=25;
fil=MS Access;maxbuffersize=2048; pagetimeout=5; dsn=MS Access Database", SQL),
I made 4 instances of that query and created another query to combine the results. The query runs as fast as most any other Access query. I am very satisfied with this solution. The query can be altered and/or repurposed from the Excel sheet without digging through the Power Query scripts.
Note that this solution does not use any VBA.

List visible databases in Teradata SQL Assistant?

I am working w the Teradata SQL Assistant. What I am trying to do, is to list all databases visible in the 'Database Explorer'. At first, I have tried simple query:
select DatabaseName from DBC.Databases;
but this returned thousands of databases I don't even have an access to. The DBC.Databases table seems not to have any field allowing me to filter results to only visible databases, or I am just unable to find it. And I am almost sure there is no such field in any table like '%database%'.
Is there any way to list those visible databases with SQL query?
Never use a system view without a trailing V or VX, those are old legacy views which will truncate object names over 30 characters.
In your case you need to switch to dbc.DatabasesVX, the X indicates that all objects where you don't have any access right are filtered automatically. But this might still return more databases than Database Explorer where you can add databases to the list manually.

UPDATE query is not "an updateable query" [duplicate]

On some Microsoft Access queries, I get the following message: Operation must use an updatable query. (Error 3073). I work around it by using temporary tables, but I'm wondering if there's a better way. All the tables involved have a primary key. Here's the code:
UPDATE CLOG SET CLOG.NEXTDUE = (
SELECT H1.paidthru
FROM CTRHIST as H1
WHERE H1.ACCT = clog.ACCT AND
H1.SEQNO = (
SELECT MAX(SEQNO)
FROM CTRHIST
WHERE CTRHIST.ACCT = Clog.ACCT AND
CTRHIST.AMTPAID > 0 AND
CTRHIST.DATEPAID < CLOG.UPDATED_ON
)
)
WHERE CLOG.NEXTDUE IS NULL;
Since Jet 4, all queries that have a join to a SQL statement that summarizes data will be non-updatable. You aren't using a JOIN, but the WHERE clause is exactly equivalent to a join, and thus, the Jet query optimizer treats it the same way it treats a join.
I'm afraid you're out of luck without a temp table, though maybe somebody with greater Jet SQL knowledge than I can come up with a workaround.
BTW, it might have been updatable in Jet 3.5 (Access 97), as a whole lot of queries were updatable then that became non-updatable when upgraded to Jet 4.
--
I had a similar problem where the following queries wouldn't work;
update tbl_Lot_Valuation_Details as LVD
set LVD.LGAName = (select LGA.LGA_NAME from tbl_Prop_LGA as LGA where LGA.LGA_CODE = LVD.LGCode)
where LVD.LGAName is null;
update tbl_LOT_VALUATION_DETAILS inner join tbl_prop_LGA on tbl_LOT_VALUATION_DETAILS.LGCode = tbl_prop_LGA.LGA_CODE
set tbl_LOT_VALUATION_DETAILS.LGAName = [tbl_Prop_LGA].[LGA_NAME]
where tbl_LOT_VALUATION_DETAILS.LGAName is null;
However using DLookup resolved the problem;
update tbl_Lot_Valuation_Details as LVD
set LVD.LGAName = dlookup("LGA_NAME", "tbl_Prop_LGA", "LGA_CODE="+LVD.LGCode)
where LVD.LGAName is null;
This solution was originally proposed at https://stackoverflow.com/questions/537161/sql-update-woes-in-ms-access-operation-must-use-an-updateable-query
The problem defintely relates to the use of (in this case) the max() function. Any aggregation function used during a join (e.g. to retrieve the max or min or avg value from a joined table) will cause the error. And the same applies to using subqueries instead of joins (as in the original code).
This is incredibly annoying (and unjustified!) as it is a reasonably common thing to want to do. I've also had to use temp tables to get around it (pull the aggregated value into a temp table with an insert statement, then join to this table with your update, then drop the temp table).
Glenn
There is no error in the code. But the error is Thrown because of the following reason.
- Please check weather you have given Read-write permission to MS-Access database file.
- The Database file where it is stored (say in Folder1) is read-only..?
suppose you are stored the database (MS-Access file) in read only folder, while running your application the connection is not force-fully opened. Hence change the file permission / its containing folder permission like in C:\Program files all most all c drive files been set read-only so changing this permission solves this Problem.
I know my answer is 7 years late, but here's my suggestion anyway:
When Access complains about an UPDATE query that includes a JOIN, just save the query, with RecordsetType property set to Dynaset (Inconsistent Updates).
This will sometimes allow the UPDATE to work.
Thirteen years later I face the same issue. DISTINCTROW did not solve my problem, but dlookup did.
I need to update a table from an aggregate query. As far as I understand, MS Access always assumes that de junction between the to-update table and the aggregate query is one-to-many., even though unique records are assured in the query.
The use of dlookup is:
DLOOKUP(Field, SetOfRecords, Criteria)
Field: a string that identifies the field from which the data is retrieved.
SetOfRecords: a string that identifies the set o record from which the field is retrieved, being a table name or a (saved) query name (that doesn’t require parameters).
Criteria: A string used to restrict the range of data on which the DLookup function is performed, equivalent to the WHERE clause in an SQL expression, without the word WHERE.
Remark
If more than one field meets criteria, the DLookup function returns the first occurrence. You should specify criteria that will ensure that the field value returned by the DLookup function is unique.
The query that worked for me is:
UPDATE tblTarifaDeCorretagem
SET tblTarifaDeCorretagem.ValorCorretagem =
[tblTarifaDeCorretagem].[TarifaParteFixa]+
DLookUp(
"[ParteVariável]",
"cstParteVariavelPorOrdem",
"[IdTarifaDeCorretagem] = " & [tblTarifaDeCorretagem].[IdTarifaDeCorretagem]
);
I would try building the UPDATE query in Access. I had an UPDATE query I wrote myself like
UPDATE TABLE1
SET Field1 =
(SELECT Table2.Field2
FROM Table2
WHERE Table2.UniqueIDColumn = Table1.UniqueIDColumn)
The query gave me that error you're seeing. This worked on my SQL Server though, but just like earlier answers noted, Access UPDATE syntax isn't standard syntax. However, when I rebuilt it using Access's query wizard (it used the JOIN syntax) it worked fine. Normally I'd just make the UPDATE query a passthrough to use the non-JET syntax, but one of the tables I was joining with was a local Access table.
This occurs when there is not a UNIQUE MS-ACCESS key for the table(s) being updated. (Regardless of the SQL schema).
When creating MS-Access Links to SQL tables, you are asked to specify the index (key) at link time. If this is done incorrectly, or not at all, the query against the linked table is not updatable
When linking SQL tables into Access MAKE SURE that when Access prompts you for the index (key) you use exactly what SQL uses to avoid problem(s), although specifying any unique key is all Access needs to update the table.
If you were not the person who originally linked the table, delete the linked table from MS-ACCESS (the link only gets deleted) and re-link it specifying the key properly and all will work correctly.
(A little late to the party...)
The three ways I've gotten around this problem in the past are:
Reference a text box on an open form
DSum
DLookup
I had the same issue.
My solution is to first create a table from the non updatable query and then do the update from table to table and it works.
Mine failed with a simple INSERT statement. Fixed by starting the application with 'Run as Administrator' access.
MS Access - joining tables in an update query... how to make it updatable
Open the query in design view
Click once on the link b/w tables/view
In the “properties” window, change the value for “unique records” to “yes”
Save the query as an update query and run it.
You can always write the code in VBA that updates similarly. I had this problem too, and my workaround was making a select query, with all the joins, that had all the data I was looking for to be able to update, making that a recordset and running the update query repeatedly as an update query of only the updating table, only searching the criteria you're looking for
Dim updatingItems As Recordset
Dim clientName As String
Dim tableID As String
Set updatingItems = CurrentDb.OpenRecordset("*insert SELECT SQL here*");", dbOpenDynaset)
Do Until updatingItems .EOF
clientName = updatingItems .Fields("strName")
tableID = updatingItems .Fields("ID")
DoCmd.RunSQL "UPDATE *ONLY TABLE TO UPDATE* SET *TABLE*.strClientName= '" & clientName & "' WHERE (((*TABLE*.ID)=" & tableID & "))"
updatingItems.MoveNext
Loop
I'm only doing this to about 60 records a day, doing it to a few thousand could take much longer, as the query is running from start to finish multiple times, instead of just selecting an overall group and making changes. You might need ' ' around the quotes for tableID, as it's a string, but I'm pretty sure this is what worked for me.
I kept getting the same error until I made the connecting field a unique index in both connecting tables. Only then did the query become updatable.
Philip Stilianos
In essence, while your SQL looks perfectly reasonable, Jet has never supported the SQL standard syntax for UPDATE. Instead, it uses its own proprietary syntax (different again from SQL Server's proprietary UPDATE syntax) which is very limited. Often, the only workarounds "Operation must use an updatable query" are very painful. Seriously consider switching to a more capable SQL product.
For some more details about your specific problems and some possible workarounds, see Update Query Based on Totals Query Fails.
I kept getting the same error, but all SQLs execute in Access very well.
and when I amended the permission of AccessFile.
the problem fixed!!
I give 'Network Service' account full control permission, this account if for IIS
When I got this error, it may have been because of my UPDATE syntax being wrong, but after I fixed the update query I got the same error again...so I went to the ODBC Data Source Administrator and found that my connection was read-only. After I made the connection read-write and re-connected it worked just fine.
Today in my MS-Access 2003 with an ODBC tabla pointing to a SQL Server 2000 with sa password gave me the same error.
I defined a Primary Key on the table in the SQL Server database, and the issue was gone.
There is another scenario here that would apply. A file that was checked out of Visual Source Safe, for anyone still using it, that was not given "Writeablity", either in the View option or Check Out, will also recieve this error message.
Solution is to re-acquire the file from Source Safe and apply the Writeability setting.
To further answer what DRUA referred to in his/her answer...
I develop my databases in Access 2007. My users are using access 2007 runtime. They have read permissions to a database_Front (front end) folder, and read/write permissions to the database_Back folder.
In rolling out a new database, the user did not follow the full instructions of copying the front end to their computer, and instead created a shortcut. Running the Front-end through the shortcut will create a condition where the query is not updateable because of the file write restrictions.
Copying the front end to their documents folder solves the problem.
Yes, it complicates things when the users have to get an updated version of the front-end, but at least the query works without having to resort to temp tables and such.
check your DB (Database permission) and give full permission
Go to DB folder-> right click properties->security->edit-> give full control
& Start menu ->run->type "uac" make it down (if it high)
The answer given above by iDevlop worked for me. Note that I wasn't able to find the RecordsetType property in my update query. However, I was able to find that property by changing my query to a select query, setting that property as iDevlop noted and then changing my query to an update query. This worked, no need for a temp table.
I'd have liked for this to just be a comment to what iDevlop posted so that it flowed from his solution, but I don't have a high enough score.
I solved this by adding "DISTINCTROW"
so here this would be
UPDATE DISTINCTROW CLOG SET CLOG.NEXTDUE

dynamic from statement based on column name

Background info:
I got ms access 2010 database with >10 (and growing) linked tables, sources: csv & xls from scattered tools that needs to be combined and queried. The sources are 'dirty' and I use insert queries with additional code to clean them and store the records in a local table with indexing for better performance later. The local tables are emptied first with a delete query. The insert queries are logged with a data macro After Insert: LogEvent on the local table in USysApplicationLog. Data macro produces loads of records in USysApplicationLog, while 1 per table per insert would be sufficient for my cause. Open issue, but less important at this time.
The local tables have the same name as the linked table with the postfix "-local".
Examples: csvMachines / cvsMachines-local, csvCustomers / csvCustomers-local, etc.
At the moment I'm manually checking everything, doing all the queries, etc. But looking for a way to automate this more.
Before using the database with local tables I want to check if:
the local tables are up to date
got this kinda covered with querying the USysApplicationLog and UDF function to check modification date of sources
the local tables are filled
reason for my question here
Looking for a smart way (sql, vba or udf) to combine following working query
SELECT MSysObjects.NAME AS LinkedTableName
,[LinkedTableName] & "-local" AS LocalTableName
FROM MSysObjects
WHERE (((MSysObjects.DATABASE) IS NOT NULL));
with a simple SELECT count(*) per local table name.
Tried following but Access can't find LocalTableName as table.
SELECT MSysObjects.NAME AS LinkedTableName
,[LinkedTableName] & "-local" AS LocalTableName
,(
SELECT count(*)
FROM [LocalTableName]
) AS LocalTableRecordCount
FROM MSysObjects
WHERE (((MSysObjects.DATABASE) IS NOT NULL));
Looked at old similar questions as Create table - dynamic name of table and MS Access query with dynamic from statements, but didnt see how to implement their solutions in my situation.
Access will not let you provide a name for the FROM data source at runtime. It just does not support that capability.
Since you have a VBA tag on this question, perhaps you would consider a procedure which loops through your table names and retrieves the record count for each.
For each table name ...
strSelect = "SELECT Count(*) FROM " & LocalTableName
MsgBox CurrentDb.OpenRecordset(strSelect)(0)
Or look at the TableDef.RecordCount property ...
MsgBox CurrentDb.TableDefs(LocalTableName).RecordCount
Looking for a solution for another issue, I found an alternative anwser for this question in the Access Help: expression.DCount(Expr, Domain, Criteria)
Working query for my situation:
SELECT MSysObjects.NAME AS LinkedTableName
,[LinkedTableName] & "-local" AS LocalTableName
,DCount("*", [LinkedTableName] & "-local") AS LocalTableRecordCount
FROM MSysObjects
WHERE (((MSysObjects.DATABASE) IS NOT NULL));

How do I construct a cross database query in MySQL?

I've got two databases on the same server. The Google gave me some hints but there wasn't anything "official" that I could find. Could someone point me to the documentation that explains how to do this? An explanation using PHP would be useful as well. Thanks!
I've got two databases on the same server. ...How do I construct a cross database query in MySQL?
You access other databases on the same MySQL instance by prefixing the table with the appropriate database name. IE:
SELECT *
FROM this_database.table_1 t1
JOIN that_database.table_2 t2 ON t2.column = t1.column
Keep in mind
A query executes with the credentials of the authentication used to set up the
connection. If you want to query two tables simultaneously across two (or more)
databases, the user used to run the query will need SELECT access to all
databases involved.
Reference:
Identity Qualifiers
SELECT * FROM DB1.myTable1 AS db1, DB2.myTable2 AS db2
http://www.dottedidesign.com/node/14 provides the following example:
SELECT
arbogast.node.nid as anid,
mcguffin.node.nid as mnid,
arbogast.node.title as atitle,
mcguffin.node.title as mtitle
FROM arbogast.node, mcguffin.node
WHERE arbogast.node.nid = 1
AND mcguffin.node.nid = arbogast.node.nid;
Where arbogast and mcguffin are different databases.