I have an admin page in a Classic ASP web application that allows the admin user to run queries against the database (SQL Server 2000)
Whats really strange is that if the query you send has an error in it (an invalid table join, a column you've forgotten to group by etc) the BROWSER hangs (CPU usage goes to maximum) until the SERVER script timeout is exceeded and then spits out a timeout exceeded error (server and browser are on different machines, so not sure how this happens!) I have tried this in IE 8 and FF 3 with the same result.
If you run that same query (with errors) directly from SQL Enterprise Manager, it returns the real error immediately. Is this a security feature? Does anyone know how to turn it off? It even happens when the connection to the database is using 'sa' credentials so I dont think its a security setting :(
Dim oRS
Set oRS = Server.CreateObject("ADODB.Recordset")
oRS.ActiveConnection = sConnectionString
// run the query - this is for the admin only so doesnt check for sql safe commands etc.
oRS.Open Request.Form("txtSQL")
If Not oRS.EOF Then
// list the field names from the recordset
For i = 0 to oRS.Fields.Count - 1
Response.Write oRS.Fields(i).name & " "
Next
// show the data for each record in the recordset
While Not oRS.EOF
For i = 0 to oRS.Fields.Count - 1
Response.Write oRS.Fields(i).value & " "
Next
Response.Write "<br />"
oRS.Movenext()
Wend
End If
Try taking the core contents of the ASP (the bit that does the work) and stick it into a pure VBS script and run that from a cmd prompt via cscript (i.e., cscript bit_wot_does_stuff.vbs) and see how quickly that comes back. [Change Server.CreateObject to CreateObject and any Response.Write to WScript.Echo for it to work in a cmd environment].
Hopefully this will tell you whether the problem lies either in ASP/IIS or within some oddity with the ADO libs (although the code looks okay, but I haven't executed it :-) ).
Hopefully it'll give you something to then trace a bit further.
SOLUTION (Just to close the post coz it aint gonna get solved!)
Upgrade to SQL Server 2005/2008/R2 - solved the problem :)
Related
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.
I don't normally program in MS Access VBA so forgive my question if it's stupid.
So I'm using MS Access 2010 as a front end and SQL Server 2014 as a backend. (I don't have a choice in frontend interface so please no suggestions on alternate options).
I'd like to programatically link SQL server's backend to my MS Access frontend. I read here at DJ Steele's DSN-less connection page that I can use the code he provided here to make a DSN-less connection to SQL server as a backend.
So I copied that into a VBA Access module and opened another module and ran this code to run the DJ Steele code in an attempt to connect to a small SQL Server database I made:
Option Compare Database
Sub runThis()
FixConnections "AServerNameHere", "MS_Access_BackEnd_Test"
End Sub
As far as I can tell from the VBA debugger it gets to
Set dbCurrent = DBEngine.Workspaces(0).Databases(0)
then that value seems to be empty. I'm not sure how else to proceed with this since as far as I was able to find this is one of the few full examples of a DSN-less connection I could find.
I'd like to not use the DSN method of linking a SQL server to a database since that would require me to go visit people and their computers in order to make the links. (And who'd want to to that? LOL)
I've also looked at similar questions that were linked to me while writing this question and this was close to what I wanted, but it kept giving me "Compile error: Constant expression required" for input of:
LinkTable "MS_Access_BackEnd_Test", "Table_1"
and
LinkTable "MS_Access_BackEnd_Test", "Table_1", , "AServerNameHere"
Again I'm not familiar with MS Access VBA so forgive the question if it's lame.
Looking at DJ Steele's code, I got it working apart from the line
' Unfortunately, I'm current unable to test this code,
' but I've been told trying this line of code is failing for most people...
' If it doesn't work for you, just leave it out.
tdfCurrent.Attributes = typNewTables(intLoop).Attributes
which I had to comment out.
Using Set dbCurrent = CurrentDb() does essentially the same thing as Set dbCurrent = DBEngine.Workspaces(0).Databases(0) but the latter is meant to be a lot faster ... which these days means it takes 10 microseconds instead of 100 :-o
You still need dbCurrent as a reference to the current Access front end which is where the linked table objects live, even if the data is coming from elsewhere.
Edit: working for me
I added a debug.print line to monitor what's going on
' Build a list of all of the connected TableDefs and
' the tables to which they're connected.
For Each tdfCurrent In dbCurrent.TableDefs
Debug.Print tdfCurrent.Name, tdfCurrent.Connect
If Len(tdfCurrent.Connect) > 0 Then
If UCase$(Left$(tdfCurrent.Connect, 5)) = "ODBC;" Then
...
and then
? currentdb().TableDefs("dbo_Person").Connect
ODBC;DSN=TacsData;APP=Microsoft Office 2003;WSID=TESTXP;DATABASE=TacsData;Trusted_Connection=Yes;QuotedId=No
FixConnections "TESTXP\SQLEXPRESS", "TacsData"
MSysAccessObjects
MSysAccessXML
...
MSysRelationships
Table1
dbo_Person ODBC;DSN=TacsData;APP=Microsoft Office 2003;WSID=TESTXP;DATABASE=TacsData;Trusted_Connection=Yes;QuotedId=No
? currentdb().TableDefs("dbo_Person").Connect
ODBC;DRIVER=sql server;SERVER=TESTXP\SQLEXPRESS;APP=Microsoft Office 2003;WSID=TESTXP;DATABASE=TacsData;Trusted_Connection=Yes
So I have this SSIS package that works flawlessly when I start it within Visual Studio Integration 2012. However when I deploy this package via the SQL Catalog it neither works or breaks. It just runs with no output.
I have no idea why this is. My package is simple.
Query a DB table
Place data into a Recordset Destination using a local variable
Pass the local variable along with some project parameters into a script that is embedded into a sequence > foreach container. The script then updates the same db table with a new value based on the logic within the script and it also sends out an email using the data pulled from the query.
I know that my query in #1 is working. I can see it through my job execution reports... it writes in all rows from the DB table. Then it just sits in my script doing God knows what... So I am guessing since it is not my query it must be one of the project params/connections (that I set using an environment). Here is my syntax for these. Do you see anything wrong with them? Please ignore the code I left out as I am sure it is not breaking there. Also I am 100% positive I am setting the values correctly in my environment and that they are properly assigned in the package.
Here is my relevant code snippets (do not mind order):
Dim oleDA As New OleDbDataAdapter
oleDA.Fill(dt, Dts.Variables("User::CustomerRows").Value)
ScriptMain.Wrapper = New ET_AutoRenewal.WrapperClass(Dts.Variables("$Project::etUserName").Value.ToString(), Dts.Variables("$Project::etPassword").Value.ToString())
Dim cm As ConnectionManager = Dts.Connections("test")
Dim sqlConn As SqlClient.SqlConnection
Dim sqlCmdText As String
sqlConn = DirectCast(Dts.Connections("test").AcquireConnection(Dts.Transaction), SqlClient.SqlConnection)
sqlCmdText = "UPDATE [" + Dts.Variables("$Project::sDatabaseName").Value.ToString() + "].[dbo].[temp_AutoRenewal_listpull] SET [process_flag] = 1 WHERE [confirmation_num] = '" + xmlDict.Item("confirmation_num") + "'"
So if that all looks good, which to me it does. How could this happen, it works fine in VS but not when deployed. What is more frustrating is nothing fails, it simply runs and there is no output (ie no table updates or emails sent out).
Are there any techniques to debug a deployed package?
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.
I'm facing timeout issues when performing multiple SELECTs after moving database to a different server, in a relic (VB6 application) I've been tasked to patch up. Things worked flawlessly in the old environemnt, the new one contains carbon copies of the old tables.
NOTE! The new database was built from scratch (that is, DBA ran many CREATE TABLE + INSERT scripts to create carbon copies of tables then fill them with the old data).
This is the error source:
// "conn" is being initialized outside the function
Public Function PerformOperation(ByRef conn as ADODB.Connection, query as string) as Boolean
Dim rs as ADODB.Recordset
//This below is the timeout source
rs.Open conn, query, adOpenStatic, adLockReadOnly
If Not (rs.EOF or rs.BOF) Then
rs.MoveFirst
//assign data to many variables
End If
ExitPoint:
If Not (rs Is Nothing) Then
If (rs.State = adStateOpen) Then rs.Close
Set rs = Nothing
End If
Exit Function
Error:
MsgBox "Blah blah"
Resume ExitPoint
Resume 0
End Function
Function is called like this
conn = New ADODB.Connection
conn.ConnectionString = "..."
conn.Open
For i = 1 To RowCount //reading data from a grid component (data is correct!)
//very long select here... kept short
query = "SELECT something FROM somewhere WHERE <manyFields> = <manyValues>"
If PerformOperation(conn, query) = True Then
//UPDATE another table based on the SELECT data
// NOTE: this occurs on a DIFFERENT, INDEPENDENT ADODB.Connection object
End If
Next i
The first time PerformOperation is called it goes through fine, second time through it times out no matter how long i set the CommandTimeout. It also works OK if the cycle "cycles" a single time.
Big problem here is, all I have to try things out is the production environment so I'll need to be extra careful. I also don't have a very deep DBA knowledge at hand... Just a very very old piece of software which will eventually be ported to .NET but needs to be dealt with in the meantime...
How can I check and/or fix this issue ? This has to work for any length of the For cycle
Many thanks for any suggestion (as always, if i missed any essential detail point it out and i'll provide it if i can).
EDIT #1
I've expanded the first and secondo code blocks to provide deeper details about what's going on. Comments changed in order to try and fix highlighting (single quotes mess up coloring).
EDIT #2
Enabling Multiple Active Result Sets (MARS) in the connection string didn't help either.
I'm a bit suprised that it has worked so well so far.
You have to close the recordset that you open, otherwise you will use up one database connection for each query you run. The database will reclaim the unused connections after a while, but if you use up too many connections too fast you will reach the limit for the number of connections per user, and the database will refuse any more connections.
The reason that it worked at all with the older database is probably because it created new connections as needed. This has been changed in later versions, and you would have to change the settings to allow the older, more resource wasteful behaviour. Changing that setting is however not a good solution to the problem.
Close the recordset and remove the reference when you don't need it any more. That will free up the connection so that you can use it for another query:
Public Function PerformOperation(ByRef conn as ADODB.Connection, query as string) as Boolean
Dim rs as ADODB.Recordset
'This below is the timeout source
rs.Open conn, query, adOpenStatic, adLockReadOnly
rs.Close()
Set rs = Nothing
' [cut]: PerformOperation returns true if SELECT returns something
End Function
Edit:
There are other open states than adStateOpen, you should probably check against the closed state instead:
If (rs.State <> adStateClosed) Then rs.Close
Issue was solved editing this line:
If PerformOperation(conn, query) = True Then
like this
If PerformOperation(connOther, query) = True Then
Basically, method call has been moved to its own connection, declared exactly like the other one. Now it works, though I don't really know why: this is the result of some wild editing in an attempt to patch things up.