My company wants to have approximately 100 of their sales people (distributed around the country) to be able to run stored procedures from excel and return the data onto the spreadsheet.
We have sql server 2008. i need to figure out a safe way to do this.
i will create a form in excel where the user can push a command button to refresh the data based on the parameters that they choose.
how can i ensure that the connection from excel to the sql server is secure?
how do i run a stored procedure from excel?
i found this to be very good information: http://office.microsoft.com/en-us/excel-help/connect-to-import-sql-server-data-HA010217956.aspx
Windows Authentication Select this option to use the Windows user
name and password of the current user. This is the most secure method,
but it can affect performance when many users are connected to the
server.
however, i would like your input on this.
yes, the sales reps do have windows logins, but can i use this solution if they will actually be entering specifying the data criteria, then sending the criteria over into the stored procedure and then getting the data from the server?
Allowing users direct connections to your database is tricky. First off, you expose yourself to attack from without, as user accounts are compromised more frequently than well-isolated admin and service accounts. Having said that, the user account does need to be compromised to allow an attacker into the system, and you have good granularity of control built into SQL Server if every user has their own credentials.
Using the Excel-native interfaces isn't that different from doing it via VBA or VSTA, which is how most developers did it for the last decade or so. Those methods are about as secure as your network. I believe the Excel-native functionality works without extraneous references, as well, which is particularly nice for maintenance purposes. The main difference seems to be in the ability to do arbitrary queries. For security and data integrity purposes, this is probably for the best.
Running a stored procedure is probably not a good idea, as you can get into massive support requirements if your users start needing(wanting) tweaks frequently. Can you make do with a view? Excel's inbuilt filtering and sorting abilities are pretty powerful. That would be my first approach.
There are several approaches depending on your needs:
1 - modify your schema to allow the database to tie data to individual users
2 - move the access code into a VBA macro associated to the workbook. This is not recommended, but it will allow you to use ADO directly. Be SURE you have a solid security configuration on the database side if you do this, as an attacker who gains access to a user's account will be able to do anything that user can do.
To go the VBA route, in the VBA environment Tools->References to find the latest Microsoft ADO version. The VBA code looks something like this:
Dim Connection as ADODB.Connection
Set Connection = new ADODB.Connection
Connection.Open"Provider=SQLNCLI;Server=myServerAddress;Database=myDataBase;Trusted_Connection=yes;"
Dim command As ADODB.command
command.CommandText = "exec sp_something"
Dim Parameters(2) As ADODB.Parameter
Set Parameters(1) = New ADODB.Parameter
Parameters(1).Name = "field_name"
Parameters(1).Type = adVarChar
Parameters(1).Size = 50
Set Parameters(2) = New ADODB.Parameter
Parameters(2).Name = "field_name_2"
Parameters(2).Type = adVarChar
Parameters(2).Size = 50
Dim i As Integer
For i = LBound(Parameters) To UBound(Parameters)
command.Parameters.Append Parameters(i)
Next i
Dim Records As ADODB.Recordset
Set Records = command.Execute
Tie that macro to your button, set up your values via the sheet or an input box, and fire away. But I'll repeat my warning: Going this way leads to massive support requirements. If people want to extract custom data, then they get very particular about it.
Instead of the article you linked, I'd rather use VBA script with reference to the ADO library and a normal connection string with a technical SQL user.
Since the password would be in the connection string in this case, this technical user should have no other rights than executing your stored procedures.
Let me know if you need more details.
Related
I am calling oracle stored procedures via Pass Through Query in MS Access.
In pass through query properties we are saving connection string with password. I don't want to allow the user to see the password.
Is there any way to encrypt the password in pass through query.
Connection string contains
ODBC;DSN=NEW_ODBC;UID=XXXXX;PWD=XXXXXXX;DBQ=XXXXXX;DBA=W;APA=T;EXC=F;FEN=T;QTO=T;FRC=10;FDL=10;LOB=T;RST=T;BTD=F;BNF=F;BAM=IfAllSuccessful;NUM=NLS;DPM=F;MTS=T;MDI=F;CSR=F;FWC=F;FBS=64000;TLO=O;MLD=0;ODA=F;
I am using docmd to call the pass through query
DoCmd.OpenQuery "qry_into_table", acViewNormal, acEdit
If i remove the PWD from the above string, every time it ask for the password to enter. I heard about the concept to use DSN less connection but i am not sure how to create dsn less connection for odbc. I am using user dsn.
Is there any way to encrypt the password or user can not see the password??
Thanks
If you link all your tables and also that of pass-though queries and LEAVE OUT the uid/password, then your quires and linked tables etc. will run just fine. You need to execute JUST ONE logon command at application start.
So in your DSNless re-link code, include the pass-though queries.
How to eliminate the need to include the user id and password in linked tables it outlined here:
Power Tip: Improve the security of database connections
https://www.microsoft.com/en-us/microsoft-365/blog/2011/04/08/power-tip-improve-the-security-of-database-connections/
The above also works for pass-through queries.
The result is then you can execute the pass though query like this in code:
Currentdb.Execute "qry_into_table"
And you can even pass values to a stored procedure with this code:
With Currentdb.QueryDefs("MyPass")
.SQL = "exec sp_MyUpdate " & strParm1
.execute
End With
Note how clean, and how we don't have to deal with connection strings in code with the above.
So the above power tip really eliminates huge amounts of code, eliminates the need to introduce ADO for calling stored procedures, and removes the need of having to deal with messy connection strings in code.
I'm opening an ADODB connection in Excel 2007 to query one of the worksheets of the current workbook. When trying to add a custom VBA function, an error raises "Undefined function name". The connection:
Dim connection As String
Dim records As ADODB.Recordset
Dim query As String
Dim fileName As String
fileName = ThisWorkbook.FullName
connection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & fileName & ";Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1"";"
query = "select t.[Col1] from [Sheet1$] As t"
Set records = New ADODB.Recordset
records.Open query, connection
Sheets(2).Range("A1").CopyFromRecordset records
What I would like to achieve is to have another column in the select, like
query = "select t.[Col1], myFunc() from [Sheet1$] As t"
where myFunc is a Function defined in the workbook.
I know that something like this is possible in Access (to have custom VBA functions in a query). Is this possible in Excel too?
What's the best practice or workaround for this scenario?
I think you need some basic explanations here, and maybe an answer to this question:
Where do the functions in SQL come from?
If you're sending queries to any database server that supports ANSI-Standard SQL, the database engine will parse and run 'inline' functions that are native to SQL: LEFT(), SUBSTRING(), SIN(), SQR(), etc. There's a short list here:
http://www.smallsql.de/doc/sql-functions/index.html
Oracle servers will expose additional functions that extend ANSI SQL, as will Microsoft SQL Servers; both PL-SQL and T-SQL have functions that are not available in standard SQL. Both of them allow the DB Owner to create their own functions, which reside on the server and are also available to SQL queries.
Microsoft Jet SQL, which isn't quite the same as ANSI SQL, has a rather limited set of native functions; but nobody minds when they are running Jet SQL in an MS-Access environment, because almost all of the Visual basic for Applications functions are made available to the SQL engine by MS-Access.
Furthermore, all of the globally-declared VBA functions that they've written and made visible in the local MS-Access project are made available to the SQL engine, too.
As long as you're running the query from Microsoft Access.
That's the easy part...
Once you move outside the MS-Access environment, you can't see the VBA.
You can query the data using Jet SQL (and the Microsoft.ACE.OLEDB.12.0 provider is doing exactly that) but, if you're running it from Excel, you're not going to enjoy the MS-Access database engine's ability to use VBA: you've got the native Jet SQL function list, and nothing else
The functions are listed here, and very few other places:
MS Access: Functions - Listed by Category
That list now includes IIF() - the inline 'IF' function - which is all you've got in Jet SQL if you want a CASE statement in your SELECT clause; you'll find that useful if your first lesson in native Jet-SQL is that all the VBA NZ() functions in your query have stopped working.
Many of these functions look like the familiar VBA functions: and this is a source of confusion, because you're not running VBA, you're running SQL.
Very few people understand that this list of native Jet functions is not the same as the list of native VBA functions made available to SQL by MS-Access, and Microsoft do not make this explicit in their documentation.
This is a complete PITA because everyone querying a SQL server or an Oracle DB expects that the server will run all and any functions in their SQL query that are declared, imported or 'native' to the dialect of SQL running on that server. You've declared VBA functions in the Access mdb, and you expected they would be visible to SQL too!
How not to fix this:
I have seen a Sybase server where the brilliant but misguided database owner had imported functions from an external library that you have definitely used without realising that it's there in every MS-Access database: vbaen32.dll, the VBA function enumeration dll. This required quite a lot of work, and never quite worked: please do not attempt to replicate this feat of genius.
So the short answer is 'No'.
Now for the useful answer:
Recordset.GetRows() will return your recordset as a 2-Dimensional VBA array, and you can run your VBA functions on that after the SQL engine has done the heavy lifting of sorting, filtering and aggregation.
You can do this efficiently on a large data set, without an excessive memory footprint, if you run your vba sequentially in chunks on a Forward-Only cursor, calling Recordset.GetRows(Rows:=1024) until you hit the end of the data.
Although you might want to ask: "Why am I doing this?", as it's very difficult to think of a process where better analysis and design wouldn't reveal a better solution. Me, I had to implement that hack for a team whose Excel-dependent process ran on csv files that grew, and grew... And grew to terabyte sizes that could only be read by a database driver. And they work in an environment where getting a proper database server takes 2-3 years of sustained managerial effort.
If you are the fortunate son who inherited that particular process after I quit, I recommend trying my GetRows 'solution' after nuking the site from orbit.
Footnote: Do, please, expand this answer if you find a better online listing for Jet SQL functions.
Meanwhile, I would urge any other 'Stack contributor who reads this to add their own links to a good listing of Jet SQL native functions - if you can find one. Most are wrong and none are comprehensive, and very few are explicit in stating that there's a difference between native functions and imported VBA. For all I know, the Jet Engine is importing and running a restricted set of functions from VBAEN32.dll - but Jet under ADODB definitely isn't a fully-featured VBA host application, and that limitation needs to be clearly understood when you're using it outside MS-Access.
I see only 1 option here:
As the "myFunc()" function does not have any parameters you can input the function to a separate worksheet (e.g. to Sheet2 in A2, in A1 put a header like "A") and reference the cell in the SQL query like:
select t.[Col1], myFunc.A from [Sheet1$] As t, [Sheet2$] as myFunc
One of my managers created a Access database and is working on some data analysis - what if scenarios. Based on different conditions, he produces a report in Access.
He asked me to do some data manipulation, so I imported the database into SQL and wrote a routine with a cursor that'll do what he wants. I then export the results back into Access. Before I get any heat for using a cursor, this was supposed to be a one time only deal, so that was the fastest way for me to get it done.
As you'd expect, now he wants me to run it all the time and asked me to convert my routine to Access so he can just run it. Before you tell me to just use SQL, he's very set on Access and is often traveling and off line.
So, my question is: is there a "easy" way to convert a T-SQL query with a cursor into Access? It's been a long time since I worked with Access, but I suspect it'd have to be re-written in VBA. I'm thinking that maybe another solution would be to call the query from Access and run it in SQL, but I don't know if that can be done or if it'd work on my case because of him being off line (maybe install SQL express in his laptop?)
Any suggestions would be appreciated.
Thanks,
Alex
This is how I got around it:
1.Downloaded and install SQL server express in the user's machine.
2.uploaded Access database structure and data to the local SQL.
3.created the stored procedure that I wanted to run in the local SQL server.
4.back in Access, deleted all the tables and recreated them as linked tables to SQL
5.Create a form in Access with a big button that executes the stored procedure
`Private Sub Command0_Click()
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.CreateQueryDef("")
qdf.Connect = CurrentDb.TableDefs("ANY TABLE").Connect
qdf.SQL = "EXEC dbo.[stored procedure name]"
qdf.ReturnsRecords = False
qdf.Execute
Set qdf = Nothing`
The stored procedure truncates one re-populates one of the tables. So after executing it I can open up the table in Access and see the changes. My manager can continue to use Access and SQL server is used in the back-end. Happy Ending! :)
We have a system with an Oracle backend to which we have access (though possibly not administrative access) and a front end to which we do not have the source code. The database is quite large and not easily understood - we have no documentation. I'm also not particularly knowledgable about Oracle in general.
One aspect of the front end queries the database for a particular set of data and displays it. We have a need to determine what query is being made so that we can replicate and automate it without the front end (e.g. by generating a csv file periodically).
What methods would you use to determine the SQL required to retrieve this set of data?
Currently I'm leaning towards the use of an EeePC, Wireshark and a hub (installing Wireshark on the client machines may not be possible), but I'm curious to hear any other ideas and whether anyone can think of any pitfalls with this particular approach.
Clearly there are many methods. The one that I find easiest is:
(1) Connect to the database as SYS or SYSTEM
(2) Query V$SESSION to identify the database session you are interested in.
Record the SID and SERIAL# values.
(3) Execute the following commands to activate tracing for the session:
exec sys.dbms_system.set_bool_param_in_session( *sid*, *serial#*, 'timed_statistics', true )
exec sys.dbms_system.set_int_param_in_session( *sid*, *serial#*, 'max_dump_file_size', 2000000000 )
exec sys.dbms_system.set_ev( *sid*, *serial#*, 10046, 5, '' )
(4) Perform some actions in the client app
(5) Either terminate the database session (e.g. by closing the client) or deactivate tracing ( exec sys.dbms_system.set_ev( sid, serial#, 10046, 0, '' ) )
(6) Locate the udump folder on the database server. There will be a trace file for the database session showing the statements executed and the bind values used in each execution.
This method does not require any access to the client machine, which could be a benefit. It does require access to the database server, which may be problematic if you're not the DBA and they don't let you onto the machine. Also, identifying the proper session to trace can be difficult if you have many clients or if the client application opens more than one session.
Start with querying Oracle system views like V$SQL, v$sqlarea and
v$sqltext.
Which version of Oracle? If it is 10+ and if you have administrative access (sysdba), then you can relatively easy find executed queries through Oracle enterprise manager.
For older versions, you'll need access to views that tuinstoel mentioned in his answer.
Same data you can get through TOAD for oracle which is quite capable piece of software, but expensive.
Wireshark is indeed a good idea, it has Oracle support and nicely displays the whole conversation.
A packet sniffer like Wireshark is especially interesting if you don't have admin' access to the database server but you have access to the network (for instance because there is port mirroring on the Ethernet switch).
I have used these instructions successfully several times:
http://www.orafaq.com/wiki/SQL_Trace#Tracing_a_SQL_session
"though possibly not administrative access". Someone should have administrative access, probably whoever is responsible for backups. At the very least, I expect you'd have a user with root/Administrator access to the machine on which the oracle database is running. Administrator should be able to login with a
"SQLPLUS / AS SYSDBA" syntax which will give full access (which can be quite dangerous). root could 'su' to the oracle user and do the same.
If you really can't get admin access then as an alternative to wireshark, if your front-end connects to the database through an Oracle client, look for the file sqlnet.ora. You can set trace_level_client, trace_file_client and trace_directory_client and get it to log the Oracle network traffic between the client and database server.
However it is possible that the client will call a stored procedure and retrieve the data as output parameters or a ref cursor, which means you may not see the query being executed through that mechanism. If so, you will need admin access to the db server, and trace as per Dave Costa's answer
A quick and dirty way to do this, if you can catch the SQL statement(s) in the act, is to run this in SQL*Plus:-
set verify off lines 140 head on pagesize 300
column sql_text format a65
column username format a12
column osuser format a15
break on username on sid on osuser
select S.USERNAME, s.sid, s.osuser,sql_text
from v$sqltext_with_newlines t,V$SESSION s
where t.address =s.sql_address
and t.hash_value = s.sql_hash_value
order by s.sid,t.piece
/
You need access those v$ views for this to work. Generally that means connecting as system.
We have an Access DB which has a set of local tables and input forms etc. in which a user maintains their data.
We also have a SQL DB with the same tables which is used to displays the data in a web search form.
What is the best way to allow the user to udate his changes to the SQL db while keeping the working copy local so he can work offline and then push the files when he is happy with new version of the data?
My first thought was add the SQL tables as linked tables I could then truncate (access does like that) or delete the content in each table and then do an insert for each table.
Can I call a SP from access on the SQL to truncate the tables as I am have problem running deletes
I really do want to get it down to the user running a macro/sql call that is repeatable etc.
Thanks for your help
You should be able to use the ADODB.Command object to execute stored procedures.
EDIT:
This example is copied from Using ADO in VB and Access
Sub ADO_COMMAND_CONNECTION_TEST()
Dim cmd As New ADODB.Command
Dim rs As ADODB.Recordset
Dim strConn As String
cmd.ActiveConnection = " DRIVER={SQL Server};" & _
"Server=UKDUDE;DATABASE=pubs;UID=sa;PWD=;"
cmd.CommandText = "byroyalty"
cmd.CommandType = adCmdStoredProc
cmd.Parameters.Refresh
cmd.Parameters(1).Value = 25
Set rs = cmd.Execute
' Recordset now has authors with 25% royalty.....
End Sub
Don't ever use MS Access linked tables with MS SQL.
Not only are they slow, but Access can leave open client-side write cursors on the tables referenced. That's a really dumb way to create lots of deadlocks, but Access does it anyway.
Microsoft significantly improved this when they added Access Data Projects - in these the entire back end is replaced with SQL and Access just supplies the forms.
If you want user actions to write directly back then ADPs are by far the best method.
If you want to cache changes locally in your Access DB and then send them up to SQL you have a far more complex problem. You will need to be far more specific on exactly how you want synchronisation to happen - for instance if two users make offline changes who wins when they connect?
I don't understand why you just don't link directly to the SQL Server data and use it directly, rather than going to the trouble of maintaining a second copy of it. This is the standard Access way to do things -- why are you resisting the natural capabilities of the tool you're using?