|
So you're working in a large financial institution where they won't let you create a stored procedure but give you direct update access to tables !!!!!!!!
Tell me which one so I can change my accounts
seriously - the most sensible advantage of SPs over inline code is security - you can give the application(s) access ONLY to stored procedures (and only to certain stored procs if you want) and then easily manage the changing of those stored procedures to avoid someone accidentally or deliberately stuffing something up.
In any decently secured DB the application should never have direct access to the tables (certainly not to update the tables) - as this doesn't prevent the simplest mistake
Update AccountBalance Set Balance = 0;
for example - oops, forgot the 'where'
Making all updates tothe DB go via a stored procedure allows you not only to monitor changes to the processes, but also so make modifications without changing the application and redeploying, and allows you to add (for example) logging easily.
Granted your example was for implementing a reporting system - in that case you may have read-only access to tables and I guess it's a matter of taste as much as anything as to whether you code sql inline or not.
that said, you can unit test an SP, you can check it works independently, you can add logging if it is doing something strange, all without having to redeploy the damn application - so it can be very useful indeed to use them all the time.
Oh, and a nicely formatted SP is much easier to read than inline code - especially where that code is build up out of many strings, so the only way to work out what it actually dies is to run in debug and look at the runtime value...
Hmm - I sound like a SP evangelist, don't I?
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
I'm an anti-SP evangelist. I have been ever since I had some SPs disappear and bring a system down (granted that was SQL Server 6, but I still don't know the cause).
Having said that, I do see that SPs (at least with SQL Server) offer the things you mention -- but I wonder how many companies actually implement the security and logging features that are available. And mightn't that only be appropriate for in-house systems where you can enforce it, and not so much for software for sale, where the buyer may demand "it's my database and I want access".
My primary concern with SPs is the ease of changing them that you mention -- I see that as a Very Bad Thing. I want all code changes to go through change control, testing, and a proper deployment. Certainly you may have a process for that in place, but in my opinion SPs are too easy to change in the field. They are too open to a properly-authorized but malicious (or inexperienced) employee.
Additionally, what happens to changes to SPs when a database is restored from backup? Don't you have to reapply any changes you made since the backup? That sounds like additional maintenance to me.
As a bonus, not being able to implement a change instantaneously allows a cooling-off period -- you may be able to convince the customer that the change they want is a bad idea.
|
|
|
|
|
PIEBALDconsult wrote: some SPs disappear and bring a system down (granted that was SQL Server 6, but I still don't know the cause).
I can understand your point - but what if a DLL had disapeared without explanation? There's nothing magical about SPs thery are just Database objects.
PIEBALDconsult wrote: software for sale, where the buyer may demand "it's my database and I want access".
I've found that it depends onthe size and computer-savviness of the customer. small customers, yes, customers with any sort of IT dept really hate having their users have access, but demand full access to the IT staff.
If all access to your data is through SPs, then you can give execute only access to everyone (and even require a password as a parameter if you're paranoid) but restrict changing of SPs to only those few.
PIEBALDconsult wrote: all code changes to go through change control, testing, and a proper deployment.
sure - in fact most large sites are much more diligent about this in DB than in code. You can put SP scripts in source control, you can set up tests to test them, you can do source compare and versioning etc. etc. You can do all that you can do with any other source code because the source code for an SP is just that - source code.
PIEBALDconsult wrote: They are too open to a properly-authorized but malicious (or inexperienced) employee.
.. who has open slather to the entire database, in your model, tables data and all! Sure a sufficiently irate tachie could change a SP to regularly do womething - equally they could just change the data, write a tigger etc.
PIEBALDconsult wrote: when a database is restored from backup? Don't you have to reapply any changes you made since the backup?
No - you usually back up databases as a whole - SPs, views, tables, data, keys, foregin keysm constraints etc.etc.etc. and restore them the same - so no additional work at all.
PIEBALDconsult wrote: As a bonus, not being able to implement a change instantaneously allows a cooling-off period -- you may be able to convince the customer that the change they want is a bad idea.
it's rare to make a change to a live site without some thought and process - especially if it is a customer who is likely to be paying for it! Think more of the time when you haven't noticed that this particular bit of program is including customers with the 'inactive' flag set.
With SP, you quickly add 'and active = true' test against the current live code base, and deploy to the database.
With SQL in code you find the code (hopefully only in one place and reasonably formatted to amke it easy to change) and add + " and active = true". Them you test - but hang on - you need to apply that change to the last live version not the current dev version - so you probably need to branch first, then test and deploy the executable to all workstations.
as you are a self confessed evangelist, there'll be no convincing you - so try to keep an open mind and look at the pros and cons. I did some years ago and was persuaded to move to the dark side of SPs - and I haven't looked back.
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
_Maxxx_ wrote: No - you usually back up databases as a whole - SPs, views, tables, data, keys, foregin keysm constraints etc.etc.etc. and restore them the same
That's my point, you would lose recent code changes and have to reapply them.
_Maxxx_ wrote: + " and active = true".
I've never written code like that. Currently I use C# verbatim strings.
cmd.CommandText = @"
SELECT
blah
, blah
, blah
FROM table
WHERE something
AND something else
" ;
Having linefeeds in the SQL makes them easier to read when logged with error messages.
Lately I've been thinking about storing SQL statements as resources.
_Maxxx_ wrote: keep an open mind and look at the pros and cons.
As I have, but also remember that many of the features we've discussed are unique to SQL Server. I use a lot if different database systems and try to stay as database-agnostic as I can.
|
|
|
|
|
PIEBALDconsult wrote: That's my point, you would lose recent code changes and have to reapply them.
? I don't follow?
You release a change to the database, which is backed up that night. Unless you want to roll back the change before the next backup, I don't seee the problem - or am I missing something?
PIEBALDconsult wrote: Lately I've been thinking about storing SQL statements as resources.
Good idea. You could write them as text and then save them to the database - call them, erm, I dunno, well, they're SQL procedures and you'
re storing them - hey call them Stored Procedures
___________________________________________
.\\axxx
(That's an 'M')
|
|
|
|
|
I mean add or modify a stored procedure, then have to restore from an earlier backup. (Consider a client who doesn't have a well-run shop.)
If I stored my SQL in a database, it wouldn't be in the database they act upon; just as I have a database that contains nothing but user-defined functions which I can use on any of my databases. Plus it would allow for multiple versions of a statement. At any rate, I meant resources within the application.
|
|
|
|
|
No, i'm not working in the financial sector. And yes, my example was a reporting system having read-only access to everything - not just implementing a SP but also to your savings account
|
|
|
|
|
tinko101 wrote: SQL injection attacks
That's only due to this particular command not using parameters.
tinko101 wrote: raise maintenance issues
Stored procedures raise maintenance issues too.
And how will you execute your stored procedure from code without having SQL in your code?
|
|
|
|
|
You can avoid the SQL injection attacks by using parameterized SQL, instead of String.Format. String.Format should not be used to create SQL statements. Parameterizing the query is a much better option.
Personally I find having the SQL in the code is more maintainable then having it buried in a SP in the database. I still have to call the stored proc, and code is easier (for me) to debug.
|
|
|
|
|
In many cases a stored procedure would offer some benefits.
The real horror here is that the parameters were added with string formatting. Command parameters would have been a far better choice. This way, depending on where the parameters come from, the door is open for SQL injection attacks.
A while ago he asked me what he should have printed on my business cards. I said 'Wizard'.
I read books which nobody else understand. Then I do something which nobody understands. After that the computer does something which nobody understands. When asked, I say things about the results which nobody understand. But everybody expects miracles from me on a regular basis. Looks to me like the classical definition of a wizard.
|
|
|
|
|
I think in that case you can use a in code SQL, but using SQL parameters.
Then, in you SQL command you add the parameters.
Something like this:
string query = "select * from table where column = @value";
SqlCommand cmd = new SqlCommand(query);
cmd.Parameters.Add("@value", textBox1.Text);
This SQL statments are cached (so if you execute it in short time intervals the SQL plan will be computed) and aren't vunerable to SQL injection.
|
|
|
|
|
How would you add the parameter for a query like: SELECT * FROM Table WHERE ID IN (123,124,125); ?
Lists are a bit tougher to handle in a proper way...
"When did ignorance become a point of view" - Dilbert
|
|
|
|
|
Personally I wouldn't. I wouldn't use IN at all, I'd find a way to have a table on which to JOIN instead.
The statement you present is a symptom of a poorly implemented system.
|
|
|
|
|
There was a thread on here recently discussing this, comparing IN, EXISTS and JOIN. I can't find it now, but if I remember correctly there was a link on there to a blog from one of the SQL Server tech-heads that explained why and how the three are not interchangeable.
|
|
|
|
|
That might be an interesting read; I'll take a look to see if I can find it.
On the other hand, JOIN can do what IN and EXISTS can do, but IN and EXISTS can't do what JOIN does.
P.S. I just searched the general database forum back to May 1 and didn't find it.
modified on Thursday, August 5, 2010 12:02 AM
|
|
|
|
|
That's because it wasn't in the general database forum.
You'll find it here.[^]
"When did ignorance become a point of view" - Dilbert
|
|
|
|
|
|
Using an SQL IN-clause is definetely not a design flaw. Forcing everything into JOIN's is on the other hand an odd self-imposed hinderence.
|
|
|
|
|
While it is true that one should "use the right tool for the right job", I have never used EXISTS (I have an Oracle background), and I have not used IN/NOT IN for many years, and never with SQL Server.
JOIN tends to scale better -- you may have an IN, EXISTS, or even a BETWEEN that has to be converted to a JOIN as the project becomes more complex; using a JOIN to begin with eases such maintenance.
JOIN allows you to configure a system by maintaining a table rather than modifying the code.
As with Jörgen's post, an IN with hard-coded values I especially discourage; they reek of the "magic numbers" code smell. A subquery on some table would at least improve maintainability.
|
|
|
|
|
PIEBALDconsult wrote: As with Jörgen's post, an IN with hard-coded values I especially discourage; they reek of the "magic numbers" code smell. A subquery on some table would at least improve maintainability.
I think I might have been unclear in my post. I never said they were hardcoded, I only wondered if he knew an easy way to add a list as a parameter and gave an example with using a list. Assume that that this list is dynamic and comes from the application.
Normally I would add that list to a temporary table and make a subquery or a join on that table. But it would be nice to be able to add that list as a parameter.
"When did ignorance become a point of view" - Dilbert
|
|
|
|
|
Jörgen Andersson wrote: list as a parameter
Indeed, you have me wondering whether or not a DataTable may be passed as a parameter. Though I'm sure that if so, that only SQL Server would support it, so it wouldn't be a general solution.
P.S. This[^] looks interesting.
P.P.S. And this[^].
modified on Friday, July 9, 2010 5:21 PM
|
|
|
|
|
Well, it seems that you can pass an array as a parameter to a stored procedure in both SQL serever[^] and Oracle[^]
"When did ignorance become a point of view" - Dilbert
|
|
|
|
|
Eureka!
In SQL Server 2008 (Express):
I created an Account table with ID (int) and Name (nvarchar) fields.
I populated the Account table with some records.
I created an IDdef User Defined Table Type with an ID (int) field.
In C# I instantiated a DataTable, added an ID (int) column.
Added some rows to the DataTable.
Then set up the following (db is an instance of one of my DALs, dt is the DataTable):
db.Command.CommandText = "SELECT * FROM Account WHERE ID IN ( SELECT ID FROM @IDs )" ;
System.Data.SqlClient.SqlParameter p =
new System.Data.SqlClient.SqlParameter
( "@IDs" , System.Data.SqlDbType.Structured ) ;
p.TypeName = "dbo.IDdef" ;
p.Value = dt ;
db.Command.Parameters.Add ( p ) ;
db.Open() ;
System.Data.IDataReader dr = db.Command.ExecuteReader
( System.Data.CommandBehavior.CloseConnection ) ;
And it works!
I then changed the statement to SELECT * FROM Account INNER JOIN @IDs IDs ON Account.ID=IDs.ID
and that works too!
|
|
|
|
|
My wife is going to kill me, I'm supposed to put up new wallpaper in the livingroom tomorrow. Not sit in front of the computer again.
"When did ignorance become a point of view" - Dilbert
|
|
|
|
|
It'll keep.
The wallpaper, that is.
|
|
|
|
|