Unrecognizable database format vb6? - database

I am trying to open up a database to read values and input into a list view. When I open the form containing the database initialization it gives me the error Unrecognizable database format and then displays my database location string. This is how I'm connecting to the database right now,
Dim dbcasegoods As Database
Dim rscasegoods As Recordset
Dim strdatabase As String
Private Sub Form_Load()
strdatabase = ("I:\Casegoods\database\ContractCasegoods.mdb")
Set dbcasegoods = OpenDatabase(strdatabase, False)
End Sub
The part that I don't understand is that I've used this method to connect to a database before, in the same project even, and I've used this database today in a different project.

VB6 (aka VB98) only works with certain Access formats (up to Access97 by default, if I recall). This can be extended to Access 2000/2002 with SP6.
But many of the post Access 2000 versions (at least to 2003) allow you to create MDB in 1997 format because VB6 just wont go away. The title bar of the DB object window may display the format (e.g. dbname DataBAse (Access 2000 file format)). I dont know how similar the menu will be in 2007, but
Tools -> ConvertDatabase -> 97 | 2000 | 2002-2003 formats
allows you to convert to various formats.

Related

With only the Select and View Definitions permission on a view, can SQL queries be sent from Excel without needing to type the query each time?

I have views that my users often only need to check for one particular person at a time. To do this, they do the following in Excel 365 desktop:
Open a blank workbook
Click on the 'Data' ribbon
Click 'Get Data'
Click 'From Database'
Click 'From SQL Server Database'
Fill in the 'Server' and 'Database' fields
In the advanced options, type SELECT * FROM [VEIWS].[VIEW_NAME] WHERE [EMP.ID] = '123456'
Click OK.
This is tedious for my users. If they want to check another person, they have to repeat the entire process. I'd love for them to just be able to use the query editor and change the only line that matters (see step 7), but they've only got the Select and View Definitions permission, which causes the query editor to complain. I'm afraid that I don't have the specific error message, but it's certainly to do with permissions.
Is there a less-repetitive way to do this from Excel? In an ideal world, I'd just make a sheet that lets them type in the EMP.ID immediately and then fetches the info. I think that it can be done with macros, but they're never my first choice and seem to require that I save passwords in the workbook.
Note that my users can't just fetch the entire view and filter it down in Excel. There are too many rows for Excel to handle.
I have no idea what permissions error you’re hitting, but people commonly use Windows credentials instead of Database credentials and get stuck. Power Query saves credentials on each computer, so you are relying on them signing in correctly. The first time someone connects to a data source, they are prompted for credentials. The default is for a Windows credential, and likely they need to enter a Database credential. If they get this wrong, they have to go into the Data Source settings to edit or clear the credential to fix it.
As far as changing the value in the SQL, you can easily have a parameter in Excel that changes the EMP.ID value in your query. Ken Puls has a nice write up on the process here. Reply back if you’re stuck.
You could use a SSAS Cube with a PivotTable in Excel with a filter on EMP.ID.
I guess it is not possible to change the query in Excel without Power Query Editor and I think it was not intended to do so (regulary).
If it does not need to be Excel you cloud just use SSMS or any similar alternative.
did you try to Un-tick the box that says "Require user approval for new native database queries" ?
you can set the ID as a parameter as suggested above... check my sample file for running an SQL query with a parameter. Sample File
also you can automatically refresh the worksheet with something like :
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("datachange")) Is Nothing Then Exit Sub
Application.EnableEvents = False 'to prevent endless loop
'Application.Goto Reference:="Tum_Santiyelerin_Satinalinan_Malzemeleri"
Range("EMP_ID").ListObject.QueryTable.Refresh BackgroundQuery:=False
ActiveWorkbook.RefreshAll
Application.EnableEvents = True
End Sub
I had a similar requirement in the past. My solution was to use the QueryTables object to send a query to the database using user-supplied data from a cell on the worksheet. It does use a macro, but I didn't have to save the credentials in the workbook.
This solution requires an ODBC driver for SQL Server.
(I seem to recall that I also had to check the references in Visual Basic - in toolbar Tools>References - but it was a while ago and I don't remember the exact details.)
Add the vb code below to a new workbook. Then if you enter the [EMP.ID] value in cell A1 of Sheet1 and run the macro 'ReadData', it will pull out the records and display them starting in cell A3.
Save the workbook as macro-enabled .xlsm and it can be shared with your users. (You could also assign the macro to a keyboard shortcut or command button to speed things up for your users.)
(This approach attempts to connect to the database using a trusted connection, i.e. using windows log-in credentials. I also use another database which requires separate credentials. I have another example below for that scenario.)
The vb code for the macro is below. Check the connection string that it has the correct driver and server IP address etc. and that the query string it reading the correct table.
Sub ReadData()
''' read database using filter supplied in cell A1
Dim ConnectionString As String
Dim QueryString As String
' Create connection string using credentials
ConnectionString = "ODBC; DRIVER={SQL Server}; SERVER=XX.XX.X.XXX; DATABASE=XXXXXXXXX; SCHEMA=dbo; REGION=yes;"
' Create query string to read data using value of cell A1
QueryString = "SELECT * FROM [VEIWS].[VIEW_NAME] WHERE [EMP.ID] = '" & Range("Sheet1!A1").Value & "'"
' The lines below can be un-commented if you get errors - it might help with debugging
'Range("Sheet1!C1").Value = ConnectionString
'Range("Sheet1!C2").Value = QueryString
' This code sends the query to the database and drops the results starting at cell A3
With Sheets("Sheet1").QueryTables.Add(Connection:=ConnectionString, _
Destination:=Range("Sheet1!A3"), Sql:=QueryString)
.RefreshStyle = xlOverwriteCells ' this stops excel from inserting new columns when the query is re-run
.Refresh False
End With
' Remove connections to avoid wasting memory
For Each con In Sheets("Sheet1").QueryTables
con.Delete
Next
End Sub
When the database requires different credentials
For this I created a user form to get the username and password, which I then incorporated into the connection string.
The steps I followed were:
In a new workbook, go to Visual Basic and create a new user form. Re-name it LoginForm
Create 2 text boxes on the form, named Username and Password. (You can also add labels and set the PasswordChar to '*' to make it look more like a login window.)
Create a command button ('OK' or 'Done'). Right click on it and select View Code. Enter the line Me.Hide in the code window so it looks like:
Private Sub CommandButton1_Click()
Me.Hide
End Sub
The vb code for the macro changes to :
Sub ReadData()
''' read database using filter supplied in cell A1
Dim ConnectionString As String
Dim QueryString As String
' First time you run, need to show form to get credentials
If LoginForm.Username = "" Or LoginForm.Password = "" Then LoginForm.Show
' Create connection string using credentials
ConnectionString = "ODBC; DRIVER={SQL Server}; SERVER=XX.XX.X.XXX; DATABASE=XXXXXXXXX; SCHEMA=dbo; REGION=yes; uid=" _
& LoginForm.Username & "; pwd=" & LoginForm.Password
' Create query string to read data
QueryString = "SELECT * FROM [VEIWS].[VIEW_NAME] WHERE [EMP.ID] = '" & Range("Sheet1!A1").Value & "'"
' The lines below can be un-commented if you get errors - it might help with debugging
'Range("Sheet1!C1").Value = ConnectionString
'Range("Sheet1!C2").Value = QueryString
' This code sends the query to the database and drops the results starting at cell A3
With Sheets("Sheet1").QueryTables.Add(Connection:=ConnectionString, _
Destination:=Range("Sheet1!A3"), Sql:=QueryString)
.RefreshStyle = xlOverwriteCells ' this stops excel from inserting new columns when the query is re-run
.Refresh False
End With
' Remove connections to avoid wasting memory
For Each con In Sheets("Sheet1").QueryTables
con.Delete
Next
End Sub
Now, the first time the user runs the code, it will prompt them for username and password, but for the rest of their session it will keep using these values. They will not be saved when the workbook is closed. (If the macro hits an error they will probably be asked for credentials again next time it is run).
Hopefully this helps you. I did this work some time ago and I may have forgotten if there were any other set-up requirements needed.

Query data from SQL to MS Access: Local Tables vs Pass-Through Tables

I've created an application that uses the following logic to query data from SQL to my MS Access App.
Using an ODBC connection I execute a stored procedure
Using This is assigned as a Pass-Through Query to pull the data locally.
It looks something like this:
strSQL = "EXEC StoredProcedure " & Variable & "
Call ChangeQueryDef("qryPassThrough", strSQL)
Call SQLPassThrough(strQDFName:="qryPassThrough", _
strSQL:=strSQL, strConnect:=gODBCConn)
Me.frmDataSheet.Form.RecordSource = "qryPassThrough"
But, recently we have upgraded our SQL Server to 2016 using a high availability failover system - hence our connection string has changed to connect to a listener like so:
gODBCConn = "ODBC;Driver= {SQL Server Native Client 11.0};Trusted_Connection=Yes;Regional=Yes;Database=" & varDB & ";MultiSubnetFailover=Yes;IntegratedSecurity=SSPI;Server=tcp:SERVER_LISTENER,1433;"
However, it looks like using SQL Server Native Client in the connection string is not the same as what we originally had which was SQL Server. Certain data types have changed and do not work in Access.
Is there a better way for me to query data from SQL and persist/display this data in access using ADO or an alternative method?
EDIT Based on Comment:
The issue I'm having is that I have tables in SQL using the data type: Decimal(12,2). With some testing and experimenting this seems to fail when using an ODBC pass-through query. But changing the data type to Float seems to work fine. Then there are other datatypes which seem to error too which I've not managed to find yet. It just seems there are a few difference which I'm not aware of and I'm keen to find a better way to load data into my Access App.
EDIT 2
This is the error message I get relating to the data type issue.
Sounds like you're not really interested in making the underlying data structure compatible with Access, so:
How to load an ADODB recordset into a datasheet form
Create the form
First, create a datasheet form. For this example, we're going to name our form frmDynDS. Populate the form with 256 text boxes, named Text0 to Text255. To populate the form with the text boxes, you can use the following helper function while the form is in design view:
Public Sub DynDsPopulateControls()
Dim i As Long
Dim myCtl As Control
For i = 0 To 255
Set myCtl = Application.CreateControl("frmDynDS", acTextBox, acDetail)
myCtl.NAME = "Text" & i
Next i
End Sub
VBA to bind a recordset to the form
First, we're going to allow the form to persist, by allowing it to reference itself:
(all on in the code module for frmDynDS)
Public Myself As Object
Then, we're going to add VBA to make it load a recordset. I'm using Object instead of ADODB.Recordset to allow it to both take DAO and ADODB recordsets.
Public Sub LoadRS(myRS As Object)
Dim i As Long
Dim myTextbox As textbox
Dim fld As Object
i = 0
With myRS
For Each fld In myRS.Fields
Set myTextbox = Me.Controls("Text" & i)
myTextbox.Properties("DatasheetCaption").Value = fld.NAME
myTextbox.ControlSource = fld.NAME
myTextbox.ColumnHidden = False
i = i + 1
Next fld
End With
For i = i To 255
Set myTextbox = Me.Controls("Text" & i)
myTextbox.ColumnHidden = True
Next i
Set Me.Recordset = myRS
End Sub
Use the form
(all in the module of the form using frmDynDS)
As an independent datasheet form
Dim frmDS As New Form_frmDynDS
frmDS.Caption = "My ADO Recordset"
frmDS.LoadRS MyAdoRS 'Where MyAdoRS is an open ADODB recordset
Set frmDS.Myself = frmDS
frmDS.Visible = True
frmDS.SetFocus
Note that you're allowed to have multiple instances of this form open, each bound to different recordsets.
As a subform (leave the subform control unbound)
Me.MySubformControl.SourceObject = "frmDynDS"
Me.MySubformControl.Form.LoadRS MyAdoRS 'Where MyAdoRS is an open ADODB recordset
Warning: Access uses the command text when sorting and filtering the datasheet form. If it contains a syntax error for Access (because it's T-SQL), you will get an error when trying to sort/filter. However, when the syntax is valid, but the SQL can't be executed (for example, because you're using parameters, which are no longer available), then Access will hard crash, losing any unsaved changes and possibly corrupting your database. Even if you disable sorting/filtering, you can still trigger the hard crash when attempting to sort. You can use comments in your SQL to invalidate the syntax, avoiding these crashes.
You previously used the pretty ancient, original ODBC Driver for SQL Server simply named SQL Server. You made the right decision to use a newer driver to support your failover cluster. But I would not recommend to use SQL Server Native Client. Microsoft says, It is not recommended to use this driver for new development.
Instead I would use the Microsoft ODBC Driver 13.1 for SQL Server. This is the most recent and recommended (by Microsoft) ODBC Driver for SQL Server.
Your main issue seems to be a translation issue between Access and SQL Server via the ODBC layer. So, using the more modern driver might very well make this problem go away. - I do not know if it solves your problem, but this is the very first thing I would try.

SQL Server Datetime object persistent reformatting issue in Excel

I have an annoying issue working with SQL Server DATETIME objects in Excel 2013. The problem has been stated several times here in SO, and I know that the work around is to just reformat the DATETIME objects in Excel by doing this:
Right click the cell
Choose Format Cells
Choose Custom
In the Type: input field enter yyyy-mm-dd hh:mm:ss.000
This works fine BUT I loathe having to do this every time. Is there a permanent work around to this aside from creating macros? I need to maintain the granularity of the DATETIME object so I cannot use a SMALLDATETIME. I am currently using Microsoft SQL Server Management Studio 2008 r2 on a win7 machine.
Thanks in advance.
-Stelio K.
Without any code it's hard to guess how the data gets from SQL Server to Excel. I assume it's not through a data connection, because Excel wouldn't have any issues displaying the data as dates directly.
What about data connections?
Excel doesn't support any kind of formatting or any useful designer for that matter, when working with data connections only. That functionality is provided by Power Query or the PivotTable designer. Power Query is integrated in Excel 2016 and available as a download for Excel 2010+.
Why you need to format dates
Excel doesn't preserve type information. Everything is a string or number and its display is governed by the cell's format.
Dates are stored as decimals using the OLE Automation format - the integral part is the number of dates since 1900-01-01 and the fractional part is the time. This is why the System.DateTime has those FromOADate and ToOADate functions.
To create an Excel sheet with dates, you should set the cell format at the same time you generate the cell.
How to format cells
Doing this is relatively if you use the Open XML SDK or a library like EPPlus. The following example creates an Excel sheet from a list of customers:
static void Main(string[] args)
{
var customers = new[]
{
new Customer("A",DateTime.Now),
new Customer("B",DateTime.Today.AddDays(-1))
};
File.Delete("customers.xlsx");
var newFile = new FileInfo(#"customers.xlsx");
using (ExcelPackage pck = new ExcelPackage(newFile))
{
var ws = pck.Workbook.Worksheets.Add("Content");
// This format string *is* affected by the user locale!
// and so is "mm-dd-yy"!
ws.Column(2).Style.Numberformat.Format = "m/d/yy h:mm";
//That's all it needs to load the data
ws.Cells.LoadFromCollection(customers,true);
pck.Save();
}
}
The code uses the LoadFromCollection method to load a list of customers directly, without dealing with cells. true means that a header is generated.
There are equivalent methods to load data from other source: LoadFromDatatable, LoadFromDataReader, LoadFromText for CSV data and even LoadFromArrays for jagged object arrays.
The weird thing is that specifying the m/d/yy h:mm or mm-dd-yy format uses the user's locale for formatting, not the US format! That's because these formats are built-in into Excel and are treated as the locale-dependent formats. In the list of date formats they are shown with an asterisk, meaning they are affected by the user's locale.
The reason for this weirdness is that when Excel moved to the XML-based XLSX format 10 years ago, it preserved the quirks of the older XLS format for backward-compatibility reasons.
When EPPlus saves the xlsx file it detects them and stores a reference to the built-in format ID (22 and 14 respectively) instead of storing the entire format string.
Finding Format IDs
The list of standard format IDs is shown in the NumberingFormat element documentation page of the Open XML standard. Excel originally defined IDs 0 (General) through 49.
EPPlus doesn't allow setting the ID directly. It checks the format string and maps only the formats 0-49 as shown in the GetBfromBuildIdFromFormat method of ExcelNumberFormat. In order to get ID 22 we need to set the Format property to "m/d/yy h:mm"
Another trick is to check the stylesheets of an existing sheet. xlsx is a zipped package of XML files that can be opened with any decompression utility. The styles are stored in the xl\styles.xml file.

How to dynamically change server url withing http connection manager SSIS?

I am fairly new to SSIS, Visual studio. Thought that might be good to mention in the beginning.
What I wanted to achieve was to download a certain xls file from http://www.ads-slo.org/statistika/ website and store it in a certain folder on my computer. I have achieved that, but the problem is that I know how to do it one file at a time. I did it by opening new connection, going to http connection and in the manager typing the server url: which in my case if lets say we start with January 2016 was this:http://www.ads-slo.org/media/xls/2016/Januar-2016.xls. After doing so I've constructed a script task or more or less copied it from a website that downloads the file given a certain url based on the connection manager.
My problem is that I would like to download all of the files on this site, so starting with January 2007 and ending with January 2016 with a single package and by not changing my connection manager server url settings 100 times.
Is there any way you might help me. I would be forever grateful.
Thank you in advance.
Kind regards, Domen
Here is one very simple example (it can be improved - see comments after code block) of changing a connection string dynamically by using a Script Task. You can also dynamically change connection strings using expressions and the Connection Manager's expressions property. However, since you are using a Script Task to handle the downloads, I have demonstrated it using one.
As you haven't tagged the Script language (VB or C#) you are using, I have written a rough draft in VB.
I have added comments, but stackoverflow syntax highlighting interprets it strangely; apologies.
Public Sub Main()
' Get the HTTP Connection
Dim connObj As Object = Dts.Connections("HTTP Connection Manager").AcquireConnection(Nothing)
Dim connection As New HttpClientConnection(connObj)
' Static list of month names for dynamic connection string (obviously add as many as needed)
Dim monthNames As String() = New String() {"Januar", "February", "March"}
' Nested loop - for each year and month, try to download the Excel file
For Y As Integer = 2007 To 2016 Step 1
For M As Integer = 0 To monthNames.Length - 1 Step 1
' Set the assumed name of the remote file
Dim remoteFileName As String = monthNames(M) + "-" + Y.ToString() + ".xls"
' Change the connection string a.k.a dynamic connection string
connection.ServerURL = "http://www.ads-slo.org/media/xls/" + Y.ToString() + "/" + remoteFileName
' Set where to download the file to
Dim localFileName As String = "C:\Temp\" + remoteFileName
Try
connection.DownloadFile(localFileName, True)
Dim buffer As Byte() = connection.DownloadData()
Dim data As String = Encoding.ASCII.GetString(buffer)
Catch E As Exception
' File may not exist on remote server, delete the blank copy it attempted to create
File.Delete(localFileName)
End Try
Next
Next
Dts.TaskResult = DTSExecResult.Success
End Sub
How can this be improved?
One potential improvement is to parse the remote server for the folders and directory contents (to save having static lists of month names, hardcoded start and end years and building file names) using a HttpWebRequest.
However, there might be an issue with the remote server permissions in allowing such requests to be made so you would have to investigate further and speak with the server administrator.
Testing the above code, it successfully downloaded the Januar-2015 and Januar-2016 Excel files from the website.

Unable to query nVarChar(Max) field in Access 2010

have used Stack Overflow as a resource hundreds of times, but my first time posting a question for some help!
I've got a table in SQL Server 2005 which contains 4 nVarChar(Max) fields.
I'm trying to pull out the data from an Access (2010) VBA Module using ADO 2.8
I'm connecting using SQL driver SQLNCLI10
(I can't use a linked table, as the 'table' I will ultimately be querying is a Table-Valued Function)
When I then print / use the recordset, the data is getting jumbled and concatenated with other fields in the same record - with a bunch of obscure characters thrown in.
The VBA: (various other methods were tried with the same result)
Sub TestWithoutCasting()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim i As Integer
cn.Open "Data Source=ART;DataTypeCompatibility=80;MARS Connection=True;"
Set rs = cn.Execute("SELECT * FROM JobDetail WHERE JobID = 2558 ORDER BY SeqNo ASC")
Do While Not rs.EOF
For i = 1 To rs.Fields.Count
Debug.Print rs.Fields(i).Name & ": " & rs.Fields(i).Value
Next i
rs.MoveNext
Loop
End Sub
Example Output:
SeqNo: 1
CommandID: 2
Parameter1: 2 Daily Report é [& some other chars not showing on here]
Parameter2: [Null]
Parameter3: [Null]
Parameter4: [Null]
Description: Daily Report
Active: False
Expected Output:
SeqNo: 1
CommandID: 2
Parameter1: SELECT Day_Number ,Day_Text ,Channel_Group_ID [...etc]
Parameter2: [Null]
Parameter3: [Null]
Parameter4: [Null]
Description: Daily Report
Active: False
So, it's grabbing bits of data from other fields instead of the correct data (in this case, it's an SQL statement)
I then tried casting the nvarchar(max) fields as text at source
View Created:
CREATE VIEW TestWithCast
AS
SELECT jd.JobID, jd.SeqNo, jd.CommandID
,cast(jd.Parameter1 as text) as Parameter1
,cast(jd.Parameter2 as text) as Parameter2
,cast(jd.Parameter3 as text) as Parameter3
,cast(jd.Parameter4 as text) as Parameter4
,jd.[Description]
,jd.Active
FROM JobDetail jd
Now, I initially had some luck here - using the same code as above does bring back data - but when I use this code in my main code (which jumps in & out of other procedures); as soon as I've queried the first result of the recordset, it appears to wipe the rest of the records / fields, setting them to Null. I also tried setting the value of each field to a variable whilst the rest of the vba runs before getting the next record - but this doesn't help either.
It almost feels like I need to dump the recordset into a local Access table, and query from there - which is a bazaar workaround for what is already a workaround (by casting as text).
I there something I'm completely missing here, or do I indeed need to cast as text and load to a local table?
Thanks for any help - it's driving me mad!
ps. Hope I've given the right level of detail / info - please let me know if I missed anything key.
EDIT:
Yikes, I think I've done it / found the issue...
I changed the driver to SQLSRV32 (v6.01) - and seems to work fine directly against the text casted field.
So... why would it work with an older driver but not the newer 'recommended' (by various sources I read) as the one to use.
And... will there be a significant drawback in using this over the native client?
EDIT 2:
Ok, I've tried a few drivers on a few machines, in each case with both the TEXT CASTING and Directly to VARCHAR MAX..
[On my windows 7 machine w/ SQLSMS 2008]
SQL Native Client 10.0 - Neither method works reliably with this driver
SQL Server 6.01 - BOTH methods appear to work reliably - further testing needed though
[On our production server w/ SQLS 2005]
SQL Native Client (v2005.90) - Does not work at all with varchar(max), but DOES work with text casting
SQL Server (v2008.86) - BOTH methods appear to work reliably - further testing needed though
This should make deployment interesting!
It's not a real answer, because I did not test it, but ... You are using a "DataTypeCompatibility=80" parameter in your connection. As far as I know, DataTypeCompatibility=80 refers to SQL Server 2000, where the nvarchar(max) field type was still not implemented.
I had the same problem, solved it by converting the field to an nvarchar(1000). Would be an easy, compatible solution for your problem if 1000 chars is enough.

Resources