Can a ADO.NET SQL command parameter contain a sub-query? - c#

Is it possible to create a SQL select max(id) as a variable inside a query?
This doesn't work:
command.CommandText = "INSERT INTO ordreid (ordrenr,ordreid) SELECT #ordrenr, #ordreid";
command.Parameters.AddWithValue("#ordrenr", nyordre);
command.Parameters.AddWithValue("#ordreid", ("MAX(ordreid)+1 FROM ordreid"));
command.ExecuteScalar();
Here is a photo of what I'd like to do. 5 customers have added items to their orders. Customer 1 has 3 items, customer 2 has 4 items, customer 3 has 1 item, and so on...
This way I have 1 ordreid even through the order could consist of 30 items.

Query parameters cannot include SQL verbatim.
This is how such prepared statements prevent SQL Injection as they are not directly inserted. Rather only the corresponding data is used in the query - in this case that is the string that contains SQL, and results in invalid SQL syntax.
The SQL text then needs to look similar to the following, although this probably does not do what is desired. (Asking how to do the higher level task will lead to actually useful queries/approaches.)
#"INSERT INTO ordreid (ordrenr, ordreid)
SELECT #ordrenr, MAX(ordreid)+1
FROM ordreid"

command.Parameters.AddWithValue("#ordreid", ("MAX(ordreid)+1 FROM ordreid"));
The method name AddWithValue hints at the reason why this won't work: Parameters contain data, that is: values. They cannot represent a part of a SQL statement.
Your intention appears to be that #ordreid should be replaced with that piece of SQL. If this is so, then there's no reason to even have a parameter. Simply perform the substitution manually and change the CommandText:
command.CommandText = #"INSERT INTO ordreid (ordrenr, ordreid)
VALUES (#ordrenr, (SELECT MAX(ordreid)+1 FROM ordreid));";
Note that I changed four things (apart from spreading the command text across two lines, for legibility's sake, using C#'s #"…" string syntax). Only the first two points are crucial:
I moved the MAX(…) SQL directly into your CommandText. This makes the (invalid) #ordreid parameter obsolete.
To determine the value of MAX(ordreid) FROM ordreid, you need a sub-query; thus the added SELECT before MAX. Otherwise, the syntax wouldn't be valid.
I replaced your SELECT with a VALUES table value constructor. (Otherwise, because of the previous point, we'd have two SELECTs very close to each other, which would look somewhat confusing.)
I added a ; at the end of your query. Current versions of SQL Server don't yet require such a statement terminator, but Microsoft has hinted that they might become compulsory in future versions of T-SQL. I therefore believe that it's a good habit to get into now.
That all being said, you should probably turn the ordreid column into an IDENTITY column and let SQL Server choose the value to be inserted (making the SELECT MAX(…) business obsolete). Otherwise, if two processes or threads execute the same INSERT command at the same time, you might end up with several rows having the same value for ordreid.

Related

Is there any way to shorten a query that has a large amount of fields?

I have a table that has 42 fields. However most of them a roughly similar. I have 20 fields that are named a01 to a20, and another 20 that are named b01 to b20. The other 2 are the PK and an FK.
Is there any way to shorten an INSERT query? Right now, because of the PK, I have to specify which columns I am using, Eg:
INSERT INTO Table01 (col_FK, a01, b01, a02, b02.....(etc)
However, the real trouble I am having is my SELECT query. My query basically allows a user to search one or more fields, and have NULL as a comparison, should a field be left empty.
SELECT * FROM Table01 WHERE
(#col_FK IS NULL OR col_FK LIKE #col_FK)
AND (#a01 IS NULL OR a01 LIKE #a01)
AND (#b01 IS NULL OR b01 LIKE #b01)
etc...
So for example, if I only entered something in to a01, and left the rest empty, the query would look something like this:
SELECT * FROM Table01 WHERE
(NULL IS NULL OR col_FK LIKE NULL)
AND ('text' IS NULL OR a01 LIKE 'text')
AND (NULL IS NULL OR b01 LIKE NULL)
etc...
I really don't want to have to do that for all 40 fields, so is there any way I could possibly make it shorter?
Note: the factoring above (#a01, #b01) is done in c# so I can pass in parameters to the query.
I'd specify the columns in the INSERT statement. That gives you a better chance that your statement will still "work" if new columns are added to the table. And your statement won't be effected if (ack!) the columns in the table are reordered.
As far as making the SELECT statement shorter... that's a matter of having a single static SQL statement, vs. multiple variations of a SQL statement. For databases other than MySQL (like Oracle or SQL Server, my personal preference is to use a single static SQL statement with bind placeholders. Then, I have just one SQL statement that needs to be tuned, it stays in the pool and gets reused, not a dozen or more different variations.
I opt for dynamic SQL when I've got an col IN (?,?,?), with a variable number of values in the list. Then it's a matter of how many bind placeholders, and how many corresponding bind parameters.
I'd also opt for dynamic SQL (multiple variants) when it gets me better query plans, that is, it gets a better execution time with fewer resources. That would be just a matter of some code to append AND a17 LIKE CONCAT('%',?,'%') to the SQL text, and corresponding code for the bind. Again, I'd only bother with doing that if it got me a performance boost.
I wouldn't "shorten" any SQL statements just for the sake of "shorter" SQL statements. That doesn't make sense to me, because I'd rather be herding a smaller herd of statements, even if some of those statements are huge. (In terms of managing the bucket of statements, one large statement is actually a easier to manage than a boatload of smaller statements that are all similar to each other.

Can I Insert the Results of a Select Statement Into Another Table Without a Roundtrip?

I have a web application that is written in MVC.Net using C# and LINQ-to-SQL (SQL Server 2008 R2).
I'd like to query the database for some values, and also insert those values into another table for later use. Obviously, I could do a normal select, then take those results and do a normal insert, but that will result in my application sending the values back to the SQL server, which is a waste as the server is where the values came from.
Is there any way I can get the select results in my application and insert them into another table without the information making a roundtrip from the the SQL server to my application and back again?
It would be cool if this was in one query, but that's less important than avoiding the roundtrip.
Assume whatever basic schema you like, I'll be extrapolating your simple example to a much more complex query.
Can I Insert the Results of a Select Statement Into Another Table Without a Roundtrip?
From a "single-query" and/or "avoid the round-trip" perspective: Yes.
From a "doing that purely in Linq to SQL" perspective: Well...mostly ;-).
The three pieces required are:
The INSERT...SELECT construct:
By using this we get half of the goal in that we have selected data and inserted it. And this is the only way to keep the data entirely at the database server and avoid the round-trip. Unfortunately, this construct is not supported by Linq-to-SQL (or Entity Framework): Insert/Select with Linq-To-SQL
The T-SQL OUTPUT clause:
This allows for doing what is essentially the tee command in Unix shell scripting: save and display the incoming rows at the same time. The OUTPUT clause just takes the set of inserted rows and sends it back to the caller, providing the other half of the goal. Unfortunately, this is also not supported by Linq-to-SQL (or Entity Framework). Now, this type of operation can also be achieved across multiple queries when not using OUTPUT, but there is really nothing gained since you then either need to a) create a temp table to dump the initial results into that will be used to insert into the table and then selected back to the caller, or b) have some way of knowing which rows that were just inserted into the table are new so that they can be properly selected back to the caller.
The DataContext.ExecuteQuery<TResult> (String, Object[]) method:
This is needed due to the two required T-SQL pieces not being supported directly in Linq-to-SQL. And even if the clunky approach to avoiding the OUTPUT clause is done (assuming it could be done in pure Linq/Lambda expressions), there is still no way around the INSERT...SELECT construct that would not be a round-trip.
Hence, multiple queries that are all pure Linq/Lambda expressions equates to a round-trip.
The only way to truly avoid the round-trip should be something like:
var _MyStuff = db.ExecuteQuery<Stuffs>(#"
INSERT INTO dbo.Table1 (Col1, Col2, Col2)
OUTPUT INSERTED.*
SELECT Col1, Col2, Col3
FROM dbo.Table2 t2
WHERE t2.Col4 = {0};",
_SomeID);
And just in case it helps anyone (since I already spent the time looking it up :), the equivalent command for Entity Framework is: Database.SqlQuery<TElement> (String, Object[])
try this query according your requirement
insert into IndentProcessDetails (DemandId,DemandMasterId,DemandQty) ( select DemandId,DemandMasterId,DemandQty from DemandDetails)

In ADO.NET, are there restrictions where SQL parameters can be used in the SQL query?

This question is merely for educational purposes, as I'm not currently building any application that builds SQL queries with user input.
That said, I know that in ADO.NET you can prevent SQL Injection by doing something like this:
OleDbCommand command = new OleDbCommand("SELECT * FROM Table WHERE Account = #2", connection);
command.Parameters.AddWithValue("#2", "ABC");
But assuming that your application is designed in such a way that the user can actually enter the name of the table, can you do the following? (I don't care if it's a bad idea to allow the users to supply the name of the table, I just want to know if the following is possible...)
OleDbCommand command = new OleDbCommand("SELECT * FROM #1 WHERE Account = #2", connection);
command.Parameters.AddWithValue("#1", "Table");
command.Parameters.AddWithValue("#2", "ABC");
I keep getting an exception when I run the second code, saying that the SQL query is incomplete, and I was wondering if the problem is that what I am trying to do simply cannot be done or if I am overlooking something.
No, a query parameter can substitue for one scalar value in your SQL statement.
For example, a single string literal, a date literal, or a numeric literal.
It doesn't have to be in the WHERE clause. Anywhere you can have an expression in SQL, you can include a scalar value, and therefore a parameter. For example, in join conditions, or in the select-list, or in ORDER BY or GROUP BY clauses.
You cannot use query parameters for:
Table identifiers
Column identifiers
SQL keywords
SQL expressions
Lists of values (for example in an IN() predicate)
If you need to make any of these parts of your query user-definable, then you need to build the SQL query string by interpolating or concatenating application variables into the string. This makes it difficult to defend against SQL injection.
The best defense in that case is to whitelist specific values that are safe to interpolate into your SQL string, for instance a set of table names that you define in your code. Let the user choose a table from these pre-approved values, but don't use their input verbatim in SQL code that you then execute.
User input may provide values, but should never provide code.
You may find my presentation SQL Injection Myths and Fallacies helpful. I cover whitelisting in that presentation (my examples are in PHP, but the idea applies to any programming language).

Is it possible to insert data in to table through coding with out using table name

My question is generally we write the following through code while we are inserting data to a table
insert into tblname values('"+txt.text+"','"+txt1.text+"');
As we pass the data form the text boxes like that is it possible to insert in to table with out using table name directlty
Well you obviously need to know what table to insert into, so there has to be a table name identified to the INSERT statement. The options include:
an INSERT statement with actual table name as per your existing example
an INSERT statement with a synonym as the target (alias for an actual table - see: http://blog.sqlauthority.com/2008/01/07/sql-server-2005-introduction-and-explanation-to-synonym-helpful-t-sql-feature-for-developer/)
an INSERT statement with an updateable view as the target
a sproc call whereby the sproc knows the table to INSERT into (but the calling code does not need to know)
You should also be aware of SQL injection risks with your example - avoid concatenating values directly into a SQL string to execute. Instead, parameterise the SQL.
If you need to dynamically specify the table to insert into at run time, you have to concatenate the table name into the SQL statement you then execute. However, be very wary of SQL injection - make sure you fully validate the tablename to make sure there are no nasties in it. You could even check it is a real table by checking for it in sys.tables.
Not possible without name of table.
But you can make use of Linq To SQL (i.e any ORM) or DataAdapter.Update if you have filled it with the proper table....
You cannot do that without the table name, no. However, the bigger problem is that your code is horribly dangerous and at rick from SQL injection. You should fix this right now, today, immediately. Injection, even for internal apps, is the single biggest risk. Better code would be:
insert into tblname (Foo, Bar) values(#foo, #bar)
adding the parameters #foo and #bar to your command (obviously, replace with sensible names).
Before you ask: no, the table name cannot be parameterised; you cannot use
insert into #tblname -- blah
The table name(s) is(/are) fundamental in any query or operation.
I suppose that if it's possible you have to use parameters.
Here you have a little example.

Is there any way to get the table hierarchy from a connection string in c#?

I have a current requirement to determine the table hierarchy from a sql statement within c#. For example, consider the following sql statement:
Select Table1.*, Table2.* from Table1
left join table2 on Table1.parentCol = Table2.childCol
That might return 7 columns, 3 for Table1 and 4 for table2. I need to know the column names, and ideally (though not mandatory) their types.
I have no control over what SQL Statement will be used, as this is a user entered field. In C# it's a very basic task to open a connection and create an SqlCommand using that statement. I have freedom to run the SQL into a SqlDataReader, or any other System.Data.SqlClient class if necessary, however I cannot find any combination that will return the columns, rather than the actual column values.
Is anyone able to help?
Many thanks and best regards
You cannot do what you are asking (easily).
More to the point, do not let users enter arbitrary TSQL (You will regret it at some point...).
Instead, create a 'Search' form that allows entering various params and use a parameterised query onto a view that joins all the tables/columns required.
There's no direct way. You'll need to parse names of all the tables from the sql query.
Once you have done that you'll need to write few queries on Information_Schema to get raw data for what you are looking for.
If you are on SQL Server, you may want to use Catalog View
ex-
Select * from sys.tables where [Name] = 'MyTable'

Categories