I know that you can increment a value in SQL by doing the following:
"UPDATE Table SET value=value+1 where Id=#Id"
Now, I'm wondering if it's possible to do the equivalent with parameters?
I've tried
string sql = "UPDATE Table SET value=#value where Id=#Id"
var cmd = new SQLiteCommand(sql, conn);
cmd.Parameters.Add("#value", DBType.Int).Value = "value+1";
but it didn't work, unsurprisingly. Is there any way to accomplish this with Parameters? If not and I use the first query, is it safe regarding injections?
You can't pass an expression as a parameter, only a value. If you know that you want to increment but you don't know by how much then you can use this SQL:
UPDATE SomeTable SET SomeColumn = SomeColumn + #Increment WHERE Id = #Id
and then you can pass 1 to that parameter to increment by 1, etc. Unless you pass all the SQL code in as a string and tell the database to parse that and execute it as SQL, you have to include all the logic in the SQL code and the parameters can only be data values. It's just how C# works. You couldn't pass part of the logic into a method as a string and expect it to be executed.
Related
Is it possible to add the alias of a column as an SqlParameter to an SQL command? If so, how is it specified?
As a simplified example, say I have an SQL command that is constructed like this:
SqlCommand GetCommand(string columnName)
{
string filter = String.Format("SELECT MyColumn1 AS '{0}' FROM MyTable", columnName);
return new SqlCommand(filter);
}
This command does nothing to prevent an SQL Injection attack, so I want to follow the standard procedure and parameterize the command.
I'm used to converting statements in the WHERE clause to use parameters. The statements look similar to the above, for example:
SqlCommand command("SELECT * FROM MyTable WHERE name = '{0}'", name);
When I convert this, it becomes:
SqlCommand command("SELECT * FROM MyTable WHERE name = #name");
command.Parameters.Add(new SqlParameter("name", SqlDbType.NVarChar) { Value = name });
That works well. Taking the same approach here with the GetCommand() method gives:
SqlCommand GetCommand(string columnName)
{
string filter = "SELECT MyColumn1 AS #columnName FROM MyTable";
SqlCommand command = new SqlCommand(filter);
command.Parameters.Add(new SqlParameter("columnName", SqlDbType.NVarChar)
{ Value = columnName });
return command;
}
But, when the command is executed, it results in:
An exception of type 'System.Data.SqlClient.SqlException' occurred in MyApplication.exe but was not handled in user code
Additional information: Incorrect syntax near '#columnName'.
I see there are plenty of questions on SO and the web in general about use of SqlParameter, but seemingly none that touch on their use with column aliases.
There's no indication in Microsoft's SqlParameter documention either. From this, I noticed that the SqlParameter.Direction property defaults to ParameterDirection.Input; the column alias is used in output, so I tried InputOutput and Output, but it made no difference to the results.
Short answer: you can't.
Column Aliases are not parameterizable. They are identifiers in the SQL language, not values - just like the column name itself, or the table name.
"Get me column X from table Y and name it Z in the result set." None of X, Y or Z are parameterizable.
Note that this is not a limitation of SqlParameter but of the SQL language as implemented by Sql Server.
Parameters are not designed for aliasing TSQL columns. If you need an alias, just give it one in the TSQL. Additionally, the In/Out aspect of the parameter is for cases where the query modifies the parameter during running. Such as an output parameter of a stored procedure.
In truth, what it appears you're trying to do is get a dataset where the returned column name is based upon an inputted value.
I would use a data adapter to fill a data table, and then just rename the column to the desired value.
dataTable.Columns["MyColumn1"].ColumnName = columnName;
Strange thing to do, but you can build some sql with the parameter and then exec it.
Declare #sql VarChar(255)
Set #sql = 'SELECT ClientNumber AS ' + #columnName + ' FROM Ib01'
Exec(#sql)
You can't parameterize schema names and aliases. If you must have dynamic aliases, you'll need to protect yourself from SQL injection in the application layer.
Consider creating a whitelist of valid aliases, and only select from the whitelist.
If the alias comes from user input, you'll have to validate/sanitize the input.
Edit: It's a bad practice to rely on the application layer to prevent SQL injection attacks. But sometimes business drivers or other reasons force this to happen. My suggestions here are ways to mitigate the risk of SQL injection if you are forced to do this.
I am currently passing an SQL Parameter with one value.
So right now I have :
SqlParameter sqlParameter = new SqlParameter("#Parameter", SqlDbType.VarChar);
sqlParameter.Value = ParameterValue
and this is working fine in my WHERE clause in my SQL query.
However now I want to leave the option to have multiple values passed in my WHERE.
Instead of passing a regular string, I was thinking of passing a string with commas to separate the values.
So SqlParameter.Value = "value1, value2, value3";
and I want it to act like
WHERE Parameter = value1 OR Parameter = value2 OR Parameter = value3
Is there an easy way to do this where I dont actually have to modify my SQL query?
Bottom line: you're going to have to change either the SQL Statement or Stored Procedure to support what you are trying to do.
There are many different approaches to do what you are trying to accomplish but none are ideal, in my opinion. Erland Sommarskog wrote a great article explaining the many ways to pass in arrays and lists to SQL Server (http://www.sommarskog.se/arrays-in-sql-2005.html) which I recommend reading. A clean approach, if you are using SQL Server 2008 or greater, is using Table Valued Parameters (http://www.sommarskog.se/arrays-in-sql-2008.html). With this approach, you are basically passing an array of values into SQL Server.
If you go the Table Valued Parameters approach, your parameter will behave like a table where you can SELECT values from. So, for instance, you might modify your Stored Procedure (or SQL Statement) like so:
CREATE PROCEDURE get_products #Parameter myCustomParameterType READONLY AS
SELECT p.ProductID, p.ProductName
FROM Products p
WHERE p.ProductID IN (SELECT n FROM #Parameter)
There is another SO question/answer which provides more detail on this approach here: How to pass table value parameters to stored procedure from .net code
More info on Table Valued Parameters can be found here: http://msdn.microsoft.com/en-us/library/bb675163.aspx
Not if your query is "where parameter = #paramter".
Either change your query to "where parameter in..."
Or get your values into another table/table variable and join them.
If you want to pass in a comma separated list to check values against you can take the list, split it down and insert it into a temporary table or a table variable and then you can do
all the normal table statements such as JOIN, IN, EXISTS.
Here is a good article on how to take a Comma separated string and turn it into a table.
http://blogs.msdn.com/b/amitjet/archive/2009/12/11/sql-server-comma-separated-string-to-table.aspx
My Code:
SqlCommand command = new SqlCommand("SELECT min(Score) FROM MenAthletics WHERE [(#sportevent)] < (#result);", connect);
command.Parameters.AddWithValue("#sportevent", sportEvent);
command.Parameters.AddWithValue("#result", result);
the #result works fine (just a double variable)
the #sportevent doesnt't work (error: invalid columnname) (sportEvent is a string)
how can I choose a column by giving in a string?
You can parameterize values in SQL statements, but you cannot parameterize column or table names. You need to change the column name in the SQL string itself, for example, with string.Format:
SqlCommand command = new SqlCommand(
string.Format("SELECT min(Score) FROM MenAthletics WHERE [{0}] < (#result);", sportEvent)
, connect
);
command.Parameters.AddWithValue("#result", result);
Make sure that the column name does not come from user's input, otherwise you would open up your code to SQL injection attacks. In case the column name does come from user's input, you can validate the string against a list of available table columns, which could be made statically or by examining the structure of your table at runtime.
You could dynamically build the SQL query, instead of passing the column name as a parameter.
You can't use a column name as a parameter; you should instead consider constructing your query this way:
SqlCommand command =
new SqlCommand(
String.Format(#"SELECT min(Score)
FROM MenAthletics WHERE [{0}] < #result;",
sportEvent),
connect);
command.Parameters.AddWithValue("#result", result);
This kind of sql is called "dynamic sql" and can be an effective way of constructing queries on the fly.
However, there are pitfalls. As well as validating the user input, also make sure that the user you are connecting to the database with only has enough permissions to carry out the actions you want to do.
Another approach, which is less elegant, but can be placed directly into a stored procedure, is to use a CASE statement;
For example:
SELECT min(Score)
FROM MenAthletics
WHERE
CASE
WHEN #sportEvent = 'SomeColumnName' THEN SomeColumnName
WHEN #sportEvent = 'SomeColumnName2' THEN SomeColumnName2
END < #result;
This gets very tedious to both create and maintain on large tables. The advantage is that the query is not dynamic.
This is because value in the sportEvent string which you are passing as a parameter is not matching with actual column existing in your database table.
Make sure that both of them matches and then only this error will go.
Otherwise dont pass table's column name as a parameter, directly write it in the query and let its column value be a parameter.
Hope it helps.
I am converting data from a CSV file into a database. I put the data from the CSV file into a DataTable and am trying to validate the data.
One thing I want to check is that all of the values in a certain column of the DataTable (let's call it PersonID) are found in the columns of a table in the database I'm converting to (let's call that PeopleID).
So, I want to check if all of the values of PersonID are listed in the PeopleId table.
I have the results of the DataTable as follows:
var listOfPersonIdsInData = arguments.DataTable.Select("PersonId");
And I query the database to get the values of the PeopleId column:
var listOfPeopleIdsInDatabase = checkQuery.Execute<DataColumn>(#"SELECT DISTINCT PeopleId FROM People");`
What would be the best way to go about checking this in C#? I realize it's a somewhat basic question but the way I'm thinking of doing it is using two arrays. Read in the results of each into an array, then cycle through each value of array 1 to check if it's in array 2.
I feel like I'm re-inventing the wheel. I would really like to know a better way if there is one. If anyone could provide any advice I'd greatly appreciate it.
If you're using SQL 2008 I would recommend that you just pass the DataTable as parameter as a Table-Valued Parameter to a stored procedure or a Parameterized query and then use an Anti Join or Not In or Not Exists to determine if there are any rows in the DataTable that aren't in the SQL Table.
e.g.
Create the type
CREATE TYPE dbo.PersonTable AS TABLE
( PersonId int )
Then the proc
CREATE PROCEDURE usp_ValidateDataTable
(#CheckTable dbo.PersonTable READONLY) as
BEGIN
SELECT c.PersonID
FROM
#CheckTable c
WHERE
c.Person NOT IN (SELECT PersonID from dbo.People)
END
C# Code
SP Call
SqlCommand cmd= new SqlCommand("usp_ValidateDataTable" , cnn);
SqlParameter tvpParam = cmd.Parameters.AddWithValue("#CheckTable", listOfPersonIdsInData );
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.PersonTable";
SqlDataReader rdr = cmd.ExcuteReader();
C# Code
Parameterized Query Call
string query = #" SELECT c.PersonID
FROM #CheckTable c
WHERE c.Person NOT IN (SELECT PersonID from dbo.People)";
SqlCommand cmd= new SqlCommand(query , cnn);
SqlParameter tvpParam = cmd.Parameters.AddWithValue("#CheckTable", listOfPersonIdsInData );
tvpParam.SqlDbType = SqlDbType.Structured;
tvpParam.TypeName = "dbo.PersonTable";
SqlDataReader rdr = cmd.ExcuteReader();
I have had to migrate much information and so far I think the best is:
Create a flat table with the information from the CSV and load all the data there
Create in the same SQL methods to extract standardized information
Construct a method in the same SQL crossing normalized information with the raw data
is really fast especially when the number of records is quite large (greater than 1M), plus you avoid the problem of optimizing your RAM management script/program. also load CSV to MySQL data is really easy check this
a tip: parameterized method for import and verify with an offset and limit value
my practice is that i fill use databinded listboxes and using a tablebindingsource and tableadapter. Then to get selective records in listbox i build stored procedure and select required records.
But now i want that the stored procedure must take some parameter from some textbox value.
like i to implement the following query
string query = "SELECT Patient_ID, Patient_Name FROM Patient WHERE ( Patient_Name LIKE '"+ textbox1.Text +"%' )";
how to do it in a stored procedure. cuz what i know is that i can only give a query like this in stored procedure
SELECT Patient_ID, Patient_Name FROM dbo.Patient WHERE ( Patient_Name LIKE 'DAV%' )
And then you make a stored procedure and fill the tableadapter with that stored procedure. like
this.accountsTableAdapter.FillBy_I(this.junaidDataSet.Patient);
My knowledge is limited ti Visual Studio 2008's interface and how to do stuff on it.
F1F1
you will have to pass a parameter using out / ref keyword and parameters
As yo are using TableAdapters, you need to select the storedproceedure rather than a query for this operation.
when you select that, it will recognise the parameters itself.
when you call the method over your TableAdapter, which is SelectByName in this case, it is going to be something similar . Modify accordingly
// your TableAdapter
PatientTableAdapter adapter = new PatientTableAdapter();
// your input and output variables
string name = "somePatientName";
int patientID? = 0;
string returnedName? = "";
// TableAdapter Method, wired to Stored Proceedure
adapter.SelectByName("somePatientName", out patientID, out returnedName);
hope this helps