I am working with Crystal Reports and MS SQL Server.
I need to remap the crystal report to point to a different database on the same SQL Server. Is there an automated way of doing this, or do I have to remap for every single report? I am currently doing this by adding a new data connection, and then updating the stored procedure with the specified paramether to change database(catalog). Also, after remaping, the .asp that displays the report crashes like this:
Active Server Pages, ASP 0115 (0x80004005)
A trappable error (E06D7363) occurred in an external object. The script cannot continue running.
The code is:
Set mainReportTableCollection = Session("oRpt").Database.Tables
For Each mnTable in mainReportTableCollection
With mnTable.ConnectionProperties
.Item("user ID") = "<some_login_name>"
.Item("Password") = "<some_password>"
.Item("DSN") = "<some_DSN>"
.Item("Database") ="<some_Database>"
End With
Next
It runs, however, if i comment out the last two assignations.
Thanks in advance.
Yours trully, Silviu.
You'll find hereafter the procedure I use (I simplified it on the fly, suppressing our own objects and global variables). This procedure allows to redirect a report from an original connection used at development time to the active SQL server. It is written in VB and uses 2 main objects:
The original report object opened through an instance of crystal report
An ADODB connection being the active connection (called P_currentConnection) to the current SQL server
This function (could be also a sub) is called before viewing/printing the report object in the application. It can be used when distributing reports among replicated databases where users, depending on their location, connect to different servers/databases.
Public Function connectReportToDatabase( _
P_report As CRAXDRT.Report)
Dim table As CRAXDRT.DatabaseTable, _
For Each table In P_report.Database.tables
If table.DllName <> "crdb_ado.dll" Then
table.DllName = "crdb_ado.dll"
End If
table.ConnectionProperties.DeleteAll
table.ConnectionProperties.Add "Provider", P_currentConnection.Provider
table.ConnectionProperties.Add "Data source", P_currentConnection.Properties("Data source").Value
table.ConnectionProperties.Add "Database", P_currentConnection.DefaultDatabase
table.ConnectionProperties.Add "Integrated security", P_currentConnection.Properties("Integrated security").Value
table.ConnectionProperties.Add "Persist Security Info", P_currentConnection.Properties("Persist Security Info").Value
table.ConnectionProperties.Add "Initial Catalog", P_currentConnection.Properties("Initial Catalog").Value
table.SetTableLocation table.location, "", P_currentConnection.ConnectionString
table.TestConnectivity
Next table
It can be called with a procedure such as:
Dim crystal As CRAXDRT.Application, _
m_report as CRAXDRT.report
Set crystal = New CRAXDRT.Application
Set m_rapport = crystal.OpenReport(nameOfTheReport & ".rpt")
connectreportToDatabase(m_report)
In case your report includes subreports, You might also have to redirect them to the active connection. In this case, you'll have to browse all objects in your report, check the ones that are of the report type and redirect them to the new connection. I am sure you'll have fun adding the corresponding extra lines to this original procedure.
You can get any of the info from the current report connection info. So if your not changing servers, then set the crystalServer variable to the reports current server.
'SET REPORT CONNECTION INFO
For i = 0 To rsource.ReportDocument.DataSourceConnections.Count - 1
rsource.ReportDocument.DataSourceConnections(i).SetConnection(crystalServer, crystalDB, crystalUser, crystalPassword)
Next
For i = 0 To rsource.ReportDocument.Subreports.Count - 1
For x = 0 To rsource.ReportDocument.Subreports(i).DataSourceConnections.Count - 1
rsource.ReportDocument.OpenSubreport(rsource.ReportDocument.Subreports(i).Name).DataSourceConnections(x).SetConnection(crystalServer, crystalDB, crystalUser, crystalPassword)
Next
Next
Related
My current project is troubleshooting our program and server performance and I got stuck on this:
Whenever I run a query in Access I get a massive amount of these errors in my log file:
Error: 18456, Severity: 14, State: 5.
Error message:
Login failed for user 'Jakob'. Reason: Could not find a login matching the name provided. [CLIENT: <named pipe>]
Weirdly enough the query resolves normally (although maybe a little slowly) and I get the expected results But my goal remains to fix this issue for the sake of deepening my understanding of the SQL Server environment and to increase performance.
Here are all the information I have gathered:
A lot of these errors occur, when opening a query and I get 1 to 2 of these errors when opening the 3 integrated tables in rapid succession. (Not when I open just 1 of them)
I have integrated 3 tables from the SQL Server on my local machine via ODBC with the following code:
Public Function ConnectTable(strTableName As String, strDateiname As String, Optional SQLSvrBo As Boolean = False, Optional strPreFix = "", Optional impBo As Boolean = False) As Boolean
On Error Resume Next
Dim DB As Database
Dim tdf As TableDef
Set DB = CurrentDb
DoCmd.DeleteObject acTable, strPreFix & strTableName
On Error GoTo Err_ConnectTable
If SQLSvrBo = False Then 'Connect to Access-Database'
Set tdf = DB.CreateTableDef(strPreFix & strTableName)
tdf.SourceTableName = strTableName
tdf.Connect = ";DATABASE=" & strDateiname
DB.TableDefs.Append tdf
ConnectTable = True
Else 'Connect to SQL-Server'
Set tdf = DB.CreateTableDef(strPreFix & strTableName)
tdf.SourceTableName = "dbo." & strTableName
tdf.Connect = "ODBC;DRIVER={" & SQLODBCDriver() & "};SERVER=" & SQLServerName() & ";DATABASE=" & SQLDatabase() & ";UID=" & SQLUID() & ";PWD=" & SQLPassword() & ";APP=Microsoft® Access;[LOGINTIMEOUT=25;]"
DB.TableDefs.Append tdf
ConnectTable = True
End If
Exit Function
'Error Handler'
End Function
On the "Frontend" we have "Query 0" which joins a local Access table with "Query 1". "Query 1" joins two of the integrated tables. The third integrated table is manipulated via a RecordSet, which writes data into "Query 0" by using a function. This function gets called 3 times per row and loops (max 3 times) if there are more than 1 entry for the corresponding record. I have triple checked the Extended Events and there are exactly an equal number of SQL-Statements and Error Messages.
I am running the newest versions of both MS Access and MS SQL-Server 2017 (EXPRESS) on my local machine, which has newest Windows 11 Updates installed.
What I have tried:
I have disabled the Named Pipes with the SQL Server Configuration Manager to no success. The Error message still mentions [Client: <named pipe>]!
"Managed" (: to replicate it on another system. But I didn't change anything from my setup, the same errors just happened to also occur there.
My guess is, that it has something to do with Access trying to connect to SQL Server via both SQL Server Authentication (which is obviously working, thanks to my flawless Copy-Paste-Skills) and Windows Authentication.
My ultimate goal is to run sql queries against sql-server and capture the returned data in a spreadsheet. The following code roughly reflects my current set-up and it works. The design allows me to read sql codes from text files and submit it to a sql-server. "Sub ExecuteCRUD" submits a first sql script to prepare data and dumps the result into a temp table. "Function loadRecordset" submits a relatively simple select query and captures the returned data in a recordset, which I then use to populate a spreadsheet.
There are a couple "variables" in my setup that could potentially be relevant for discussion.
My 4 set of Sql Codes
The ConnectionString (Part of my vba code)
The rest of my vba codes
a. Dbo.ConnectionString = "Provider=MSDASQL;DRIVER=SQL
Server;SERVER=myserver;UID=id;PWD=password;DATABASE=database;"
b. Dbo.ConnectionString = "Provider=SQLOLEDB;Data
Source=myserver;Initial Catalog=database;User
ID=id;Password=password;"
Initially, all I changed was the connection string. The immediate result was connection string version a works perfectly. Using b version, my setup would fail without any errors from sql-server.
Using Connection string version b, "Sub ExecuteCRUD" (data preparation step) would still work smoothly. I can verify that the temp table is created in tempdb as a result of my first sql script.
"Function loadRecordset" would run through the lines without any errors up to and including "rs.open". (I checked for errors, none whatsoever from the ado connection).
Only subsequent codes, when using the recordset to copy out the data would get an error: "Operation is not allowed when the object is closed."
Through some testing, I narrowed down the issue to the sql codes, sort of.
I have to reiterate here. My initial set of sql codes worked completely fine when using the ODBC provider. Things only went sideways using the OLEDB provider.
Using the OLEDB provider, the "offending" sql code was Use databaseABC. Furthermore, using ado, my setup submits 4 sets of sql codes to the sql server. The first set of sql codes prepares data (creating tables, inserting data, creating index, using while loops to populate data, using recursive ctes, etc). In this first set of sql codes, Use databaseABC was also included, and it would execute successfully. The other 3 set of sql codes submitted were only select queries aimed at obtaining data. When Use databaseABC was included in the select query sql codes, the operation failed without any errors. After I took out the Use databaseABC, everything would run correctly in the OLEDB provider world.
Use databaseABC is not a necessary part of the select queries. Using it saves me the trouble of specifying database names all the time in the join clauses.
At this point, my curiosity is two fold
why Use databaseABC causes failures, specifically only when using OLEDB provider, more specifically only when running select queries.
When the failure occurred, should sql-server or the driver generate any errors? What would be the proper way of checking and verifying that?
Private Dbo As New ADODB.Connection
Private rs As ADODB.Recordset
Public Sub ConnectServer()
If Dbo.State = adStateClosed Then
Dbo.ConnectionString = "Provider=SQLOLEDB;Data Source=*server*;" _
& "Initial Catalog=*database*;User ID=*id*;Password=*pwd*;"
Dbo.Open
End If
End Sub
Public Sub ExecuteCRUD(ByVal Sql As String)
On Error GoTo PANIC
Dbo.Execute Sql
Exit Sub
PANIC:
Debug.Print Err.Descript
Stop
End Sub
Public Function loadRecordset(ByVal Sql As String) As Long
On Error GoTo PANIC
Set rs = New ADODB.Recordset
With rs
.CursorLocation = adUseClient
.CursorType = adOpenStatic
.LockType = adLockReadOnly
.Source = Sql
Set .ActiveConnection = Dbo
End With
rs.Open
loadRecordset = rs.RecordCount
Exit Function
PANIC:
Debug.Print Err.Description
loadRecordset = 0
Stop
End Function
we have a large MS Access application which uses SQL Server for the database (about 200 tables).
We want to convert it to a multi-tenancy database, where we will have a single large SQL Server database. Inside the database each client will have their own set of tables in their own schema. Eg, ten clients using database - ten Schemas in that database.
We will then migrate it to Azure and run the MS Access application as an Azure RemoteApp.
We want to create an Active Directory User Group for each client, and map it across to the default SQL Server Schema for that client.
The idea is that new users are added to the relevant AD User Group, and by default get mapped across to the right Schema with their data,
The problem we have is the MS Access Linked Tables contain a hard-coded explicit Schema (dbo by default).
Can anyone think of a way to store a "Source"/external/linked table in MS Access without having to specify a Schema. Eg. just "tblSales", not "dbo.tblSales".
A typical relink code goes like this (a snip only):
For Each tdf In dbs.TableDefs
strName = tdf.Name
If Asc(strName) <> Asc("~") Then
If InStr(tdf.Connect, cstrDbType) = 1 Then
tdf.Connect = strConnect
tdf.RefreshLink
Debug.Print Timer, tdf.Name, tdf.SourceTableName, tdf.Connect
DoEvents
End If
End If
Next
I have no other schema than dbo to test with, and I'm not sure if the property SourceTableName is read-only. If not, it could be adjusted:
For Each tdf In dbs.TableDefs
strName = tdf.Name
If Asc(strName) <> Asc("~") Then
If InStr(tdf.Connect, cstrDbType) = 1 Then
tdf.Connect = strConnect
tdf.SourceTableName = strNewSchema & "." & Split(tdf.SourceTableName, ".")(1)
tdf.RefreshLink
Debug.Print Timer, tdf.Name, tdf.SourceTableName, tdf.Connect
DoEvents
End If
End If
Next
If it is read-only, you will have to delete the linked table and recreate the link.
That said, I'm not sure if your idea of a schema for each client is such a good idea. We had similar considerations and decided simply to create a database for each client. If for nothing else, backup and restore clientwise is greatly simplified.
I have created a table in my Access front end application, and try to connect it to the back end database with the following subroutine:
Sub createFlowTable()
Dim db As Database
Dim tblDef As TableDef
Set db = CurrentDb
Set tblDef = db.CreateTableDef("myTable")
tblDef.Connect = "ODBC;DRIVER=SQL Server;SERVER=myServer; Trusted_Connection=No;UID=<myUID>;PWD=<myPWD>;APP=2007 Microsoft Office system;DATABASE=myDataBase;Network=DBMSSOCN;TABLE=dbo.myTable"
tblDef.SourceTableName = "mySourceTableName"
db.TableDefs.Append tblDef
End Sub
After I close the front end Access database, and upon reopening it, the table fails to open. Even though I have set the Trusted_Connection to "No" in my string, the table still tries to use the Windows Authentication. Also, when I open the table on design view, I see in front of "Description":
ODBC;DRIVER=SQL Server;Server=myServer;APP=2007 Microsoft Office System;DATABASE=myDatabase;Network=DBMSSOCN;Table=dbo.myTable
So obviously Access has not saved the UID and PWD, nor has it saved the instruction on setting the Trusted_Connection to "No".
I insist to get this done with the connection string, and using DSN will not work for the purpose of my application. Help would be greatly appreciated.
You need to add the dbAttachSavePWD-Attribute to the created table to store your credentials with the linked table in Access.
Before appending the tabledef you should put this line of code:
tblDef.Attributes = (tblDef.Attributes Or dbAttachSavePWD)
I am using a VB6 application. Which was using the MSAccess database. Now i am changing the database access to sql server. to getting/updating the data from MSAccess the application was using the DAO object. So now i am also trying to connect SQL Server with DAO method. Now i am able to connect the database and also able to get the data. But when i am trying to Edit record it is giving the error "Runtime error '3027' cannot update. Database or object is read only". i am showing my code here:
Public LSWs As Workspace, LSDb As Database
Dim lsConnString As String
Dim l0 As Recordset, SQL0 As String
Dim lehReturn As Integer, retrycount As Integer
lsConnString = "ODBC;DRIVER=SQL Server;SERVER=SERVERName;DATABASE=" & DBname & ";APP=Visual Basic;UID=UID;PWD=PWD"
Set LSWs = DBEngine.Workspaces(0)
Set LSDb = LSWs.OpenDatabase(DBname, dbDriverNoPrompt, True, lsConnString)
retrycount = 0
SQL0 = "select * from schedule_hdr where status = '" & Trim(PCName) & "'"
Set l0 = LSDb.OpenRecordset(SQL0, dbOpenDynaset, dbSeeChanges, adLockPessimistic)
Do While Not (l0.EOF)
LSWs.BeginTrans
l0.Edit
l0!status = "R"
l0.Update
LSWs.CommitTrans
l0.MoveNext
Loop
l0.Close
but it is giving the error at l0.Edit this line code
giving the error
"Runtime error '3027' cannot update. Database or object is read only
Any Help! or suggesion please reply
Thanks in Advance!
Initially I'm thinking that the username and password you are using for the SQL server may possibly have read-only rights.
If this is not the case and you want to stick with DAO then I suggest using the built-in ODBC link feature of Access as this helps you connect successfully to your SQL server.
However, my advice has to be abandoning DAO and going with ADO, mainly because DAO restricts your data processing to client side which is slow, and the whole point of having a dedicated server is to run as much as you can server side to dramatically improve performance.