My query is supposed to add an additional column "_DisableAccounting" to the "Settings_Global" table, specifying a DEFAULT value using a SQLiteParemeter.
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT #defaultValue;
When the SQLiteCommand is executed, #defaultValue should be replaced by the supplied parameter.
// ....
SQLiteParameter defaultValueParam = null;
if (defaultValue != null) {
query += " DEFAULT #defaultValue`";
defaultValueParam = new SQLiteParameter { ParameterName = "#defaultValue", Value = defaultValue };
}
query += ";";
using (SQLiteCommand cmd = _Connection.CreateCommand()) {
cmd.CommandText = query;
if (defaultValueParam != null) {
cmd.Parameters.Add(defaultValueParam);
}
cmd.ExecuteNonQuery();
}
// ....
However, I get the error "'SQL logic error or missing database near
#defaultValue": syntax error'". So it seems that the command is never replacing #defaultValue with the actual value.
Why isn't this working? I am doing essentially the same with MySQL (my application can optionally use MySQL) and it is working.
You appear to have a spurious grave accent. That is #defaultValue is followed grave accent, when it likely shouldn't be.
Try changing
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT #defaultValue`;
to
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT #defaultValue;
or to
ALTER TABLE Settings_Global ADD COLUMN `_DisableAccounting` BOOL NOT NULL DEFAULT `#defaultValue`;
When doing ALTER TABLE, SQLite does not modify the column definition in any way and just inserts it directly at the end of the CREATE TABLE statement.
This means that the parameter marker would end up in that CREATE TABLE statement, which would result in the parameter value not being available when the statement is interpreted later.
You have to insert the default value directly into the SQL command.
Related
I am developing an ASP.net application using MySQL and have a question related to a stored procedure return value.
This is my stored procedure:
CREATE DEFINER=`pcg`#`%` PROCEDURE `UpdatePreSellerProfile`(
IN UserID INT(11),
IN SellerImageID INT(11),
IN BusinessImageID INT(11),
OUT ProfileUpdated INT(1)
)
BEGIN
SET #Approved = 'APPROVED';
UPDATE user SET
SELLER_IMAGE_ID = COALESCE((SELECT IMAGE_ID FROM image_url WHERE IMAGE_USER_ID = UserID AND IMAGE_ID=SellerImageID),SELLER_IMAGE_ID),
SELLER_BUSINESS_LOGO_ID = COALESCE((SELECT IMAGE_ID FROM image_url WHERE IMAGE_USER_ID = UserID AND IMAGE_ID=BusinessImageID),SELLER_BUSINESS_LOGO_ID)
WHERE (USER_LOGIN_ID = UserID AND USER_PROFILE_STATUS = #Approved);
SET ProfileUpdated = ROW_COUNT();
END
When I test this code with following MySQL script I get 0 (#ProfileUpdated) always when there is no update.
call UpdatePreSellerProfile(#UserID, #SellerImageID, #BusinessImageID ,#ProfileUpdated);
But when I check this in my C# code, it is always showing 1 (ProfileUpdated).
if (oMySQLConnecion.State == System.Data.ConnectionState.Open)
{
MySqlCommand oCommand = new MySqlCommand("UpdatePreSellerProfile", oMySQLConnecion);
oCommand.CommandType = System.Data.CommandType.StoredProcedure;
MySqlParameter sqlProfileUpdated = new MySqlParameter("#ProfileUpdated", MySqlDbType.VarString);
sqlProfileUpdated.Direction = System.Data.ParameterDirection.Output;
oCommand.Parameters.Add(sqlProfileUpdated);
oCommand.Parameters.AddWithValue("#UserID", UserID);
oCommand.Parameters.AddWithValue("#SellerImageID", oSeller.SellerImageID);
oCommand.Parameters.AddWithValue("#BusinessImageID", oSeller.BusinessLogoID);
oCommand.ExecuteNonQuery();
Int16 ProfileUpdated = Convert.ToInt16(oCommand.Parameters["#ProfileUpdated"].Value);
if (ProfileUpdated > 0) // <<-- Should be greater only if it is updated is sucessfull
{
oDBStatus.Type = DBOperation.SUCCESS;
oDBStatus.Message.Add(DBMessageType.SUCCESSFULLY_DATA_UPDATED);
}
else
{
oDBStatus.Type = DBOperation.ERROR;
oDBStatus.Message.Add(DBMessageType.ERROR_NO_RECORDS_UPDATED);
}
oMySQLConnecion.Close();
}
Why is the difference between MySQL script vs C# code?
Unless you have set the UseAffectedRows connection string option, it defaults to false. This means:
When false (default), the connection reports found rows instead of changed (affected) rows. Set to true to report only the number of rows actually changed by UPDATE or INSERT … ON DUPLICATE KEY UPDATE statements.
Additionally, from the documentation of the ROW_COUNT function:
For UPDATE statements, the affected-rows value by default is the number of rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to mysql_real_connect() when connecting to mysqld [ed. note: this is the same as UseAffectedRows], the affected-rows value is the number of rows “found”; that is, matched by the WHERE clause.
Thus, the UPDATE user statement in your stored procedure will return the number of rows that were found by the query, not the number that were actually updated.
To fix this, either:
Set UseAffectedRows=true; in your connection string; this may cause changes to other UPDATE queries.
Add more conditions to the WHERE clause, e.g., WHERE ... AND SELLER_IMAGE_ID != SellerImageID AND SELLER_BUSINESS_LOGO_ID != BusinessImageID, to make sure the row is only found and updated if it actually needs to change.
I am using c# to insert a record into the SQLite DB table 'VS_Types' with one parameter from table 'VS_Groups'. I test it with SQLite Browser and it works. While I implement the same sqlite command inside the C# with System.Data.SQlite. It doesn't work.
I modify the commandText to as following it works. Looks like the parameter '#value0' influence the c# SQLite command execution.
cmd.CommandText = "INSERT INTO VS_Types(Name, Group_id, Color) Values('20', 10, 1245679);";
SQLite SQL:
SELECT #value0=ID FROM VS_Groups WHERE (Name = 'Ato_h');
INSERT INTO VS_Types(Name, Group_id, Color) VALUES('20', #value0, 65536);
The Code inside the C#
using (SQLiteConnection conn = new SQLiteConnection(cs))
{
try
{
conn.Open();
SQLiteCommand cmd = new SQLiteCommand(conn);
cmd.CommandText = "Select #groudId = ID From VS_Groups Where(Name = 'Ato_h'); "
+ "INSERT INTO VS_Types(Name, Group_id, Color) Values('20', #groudId, 1245679);";
cmd.ExecuteNonQuery();
conn.Close();
testOutput.WriteLine("Insert Successful");
}
catch (Exception ex)
{
this.testOutput.WriteLine("Failed to open connection: {0}", ex.Message);
}
}
Please give me some suggestions about how to use the parameter inside C# Sqlite command in this situation.
Update: the VS_Groups and VS_Types table and its content
CREATE TABLE "VS_Groups" (
`ID` INTEGER PRIMARY KEY AUTOINCREMENT,
`Name` TEXT,
`Width` INTEGER,
`Height` INTEGER,
`Flags` INTEGER,
`Limi_recognition` INTEGER,
`Base` TEXT,
`Flags1` INTEGER,
`Limit_recognition` INTEGER,
`Flags2` INTEGER,
`Limit_recognition2` INTEGER,
`Distance_threshold` INTEGER
)
CREATE TABLE `VS_Types` (
`ID` INTEGER PRIMARY KEY AUTOINCREMENT,
`Name` TEXT,
`Group_id` INTEGER,
`Color` INTEGER
)
The existing record is:9,Ato_h,160,140,65536,,,,400,,,100
Sqlite SQL does not work like that. You cannot declare and store a value in a variable, then reuse that variable later. Terms like #groudId are only placeholders for parameters passed to the query. That means that the expression #groudId = ID is NOT an assignment, rather it is a comparison. Since you are not binding the parameter #groudId to anything, the parameter value is null, so the expression is a comparison like null = ID which will result in false which numerically is 0 (zero). The select statement returns 0 and is not used in the INSERT statement.
If the INSERT is working at all, it is probably resulting in something like INSERT INTO VS_Types(Name, Group_id, Color) Values('20', null, 1245679);
At the end of the question, you also say "The existing record is ..." and you only show a single record for VS_Groups, although the insert statement is for the table VS_Types. But you don't show output for the VS_Types table! You are inspecting the wrong table for the inserted data. If you query the table VS_Types, you will likely find many records with Name == '20', GroupID == null and Color == 123456789... exactly as the INSERT statement says.
In summary, you are not using parameters correctly, but you really don't even need a parameter in the code you show, so it is difficult to know how to answer properly. An answer showing proper use of parameters would be wasted, but a replacement SQL may not be want you want in the end either. I suggest researching parameters separately to learn how to use them properly. For now, use this nested statement:
INSERT INTO VS_Types(Name, Group_id, Color)
VALUES ('20', (Select ID From VS_Groups Where Name = 'Ato_h'), 1245679);
Regrettably that's not all. The table definition does not show that VS_Groups.Name is unique, so technically there could be multiple rows that match the nested query, so the INSERT statement could still fail. I suggest adding a UNIQUE constraint to the VS_Groups.Name column.
How to set Default Value as Value of SqlCommand SqlParameter?
SqlCommand is the class contained in System.Data.SqlClient
My Schema does not accept DBNull.Value as value
SqlCommand command = new SqlCommand();
command.Parameters.Add(new SqlParameter("column_1", SqlDbType.VarChar, 1) { Value = DBNull.Value });
As lboshuizen points out, if your "schema" isn't taking null, or the parameter of the stored procedure or query cannot be null, trying to give it a null value will likely fail. In this case, you need to see why you are trying to set it to null if you know it doesn't accept it. I would surmise an empty string as opposed to null would work, or something else that is sensible.
The SqlParameterCollection property Parameters has an AddWithValue method:
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlparametercollection.addwithvalue(v=vs.110).aspx
You can simply insert null and that will be handled for you:
command.Parameters.AddWithValue("#parameter", null);
If you cannot provide a null, you can provide something like an empty string:
command.Parameters.AddWithvalue("#parameter", "");
You also very rarely need to specify the data type using this mechanism.
If the schema doesn't accept null it indicates that the column is mandatory and requires a sensible value.
Using a default value for a column is a property of the schema.
So either alter the schema to provide a default.
ALTER TABLE {TABLENAME}
ADD {COLUMNNAME} {TYPE} {NULL|NOT NULL}
CONSTRAINT {CONSTRAINT_NAME} DEFAULT {DEFAULT_VALUE}
Choose a valid (not null) default value in your application code and use it as a value in the parameter.
const string default = "unknown";
...
SqlCommand command = new SqlCommand();
command.Parameters.Add(new SqlParameter("column_1", SqlDbType.VarChar, 1)
{ Value = default });
Note: Changing the schema to accept NULL is considered cheating :-)
Using SQL Server 2008, WinForms C# .NET 4.5, Visual Studio 2012.
I have a query that currently updates a table with some information from a GridView.
Below is the code that calls the stored procedure:
public void UpdateMain(string part, int? pareto)
{
try
{
using (SqlConnection AutoConn = new SqlConnection(conn32))
{
AutoConn.Open();
using (SqlCommand InfoCommand = new SqlCommand())
{
using (SqlDataAdapter infoAdapter = new SqlDataAdapter(InfoCommand))
{
InfoCommand.Connection = AutoConn;
InfoCommand.CommandType = CommandType.StoredProcedure;
InfoCommand.CommandText = "dbo.updateMain";
InfoCommand.Parameters.AddWithValue("#part", part);
InfoCommand.Parameters.AddWithValue("#pareto", pareto);
InfoCommand.CommandTimeout = 180;
InfoCommand.ExecuteNonQuery();
}
}
}
}
catch (Exception e)
{
//MessageBox.Show("Error in connection :: " + e);
}
}
And here's the SQL:
ALTER PROCEDURE [dbo].[updateMain]
#part varchar(255),
#Pareto int
as
UPDATE dbo.ParetoMain
SET NewPareto = #Pareto
WHERE Part = #part
Nothing fancy as you can see. The problem I have is the Newpareto doesn't have to have a value, so I need it to allow nulls. I made sure the table allows nulls. And in my C# code I made sure to use nullable int, but when I run the code I get the error:
Exception:Thrown: "Procedure or function 'updateMain' expects parameter '#Pareto', which was not supplied." (System.Data.SqlClient.SqlException)
A System.Data.SqlClient.SqlException was thrown: "Procedure or function 'updateMain' expects parameter '#Pareto', which was not supplied."
So how do I stop this error and get the null into the table?
The problem is that the parameter is expected, but not added if the nullable value is null. You need to address this by either:
Manually setting it do DBNull.Value as in: InfoCommand.Parameters.AddWithValue("#Pareto", (object)pareto ?? DbNull.Value);
Or by making the parameter optional as in: #Pareto int = null
Your stored procedure could look like this if you want to make the parameter optional:
ALTER PROCEDURE [dbo].[updateMain]
#part varchar(255),
#Pareto int = null
as
UPDATE dbo.ParetoMain SET NewPareto =#Pareto WHERE Part = #part
EDIT
I take it from the accepted answer that you need to cast to object due to type mismatch problems. I'm fixing my answer for the sake of completeness.
use
InfoCommand.Parameters.AddWithValue("#Pareto", (Object)pareto ?? DBNull.Value);
Try this:
if (pareto != null)
{
InfoCommand.Parameters.AddWithValue("#pareto", pareto);
}
else
{
InfoCommand.Parameters.AddWithValue("#pareto", DBNull);
}
How can I INSERT values into SQL Server that are stored in a string[] such that some of the values should be disregarded in favor of the values stored in SQL Server as default constraints on the table? What do I need to pass(e.g. NULL or something else) to use those defaults?
Currently, I add all the defaults in my code, and it is getting bulky.
Below is my code:
if (value == "") value = "0";
string insert = "INSERT INTO " + table + " (" + columns + ") VALUES (" + atColumns + ")";
using (SqlConnection connect = new SqlConnection(connection))
{
using (SqlCommand command = new SqlCommand(insert, connect))
{
//adds values to corresponding parameters
for (int i = 0; i < table_cols.Length; i++)
{
command.Parameters.AddWithValue("#" + table_cols[i], table_vals[i]);
}
foreach (SqlParameter Parameter in command.Parameters)
{
if (Convert.ToString(Parameter.Value) == "")
{
Parameter.Value = DBNull.Value;
}
}
connect.Open();
command.ExecuteNonQuery();
response = "Success";
return response;
If a specific Parameter.Value is not-null and has a default set by SQL Server, this code will not work with null.
In SQL Server, this gets handled by omitting the value in your insert statement (this omission triggers inserting the default value for the table, whereas providing null produces errors).
If you want SQL Server to use the default value constraint for the column then don't include the column as part of the insert parameters.
Example:
--From SQL Server
CREATE TABLE Orders
(
Id INT IDENTITY PRIMARY KEY
,Amount INT NOT NULL
,Cost MONEY NOT NULL
,SaleDate DATE NOT NULL DEFAULT GETUTCDATE()
);
//From C#
public int Insert(decimal cost, int amount)
{
using (var connection = new SqlConnection(connectionString))
{
var command = connection.CreateCommand();
//Don't specify the SaleDate and it will insert the current time
command.CommandText = "INSERT INTO Orders(Amount, Cost) VALUES(#Amount, #Cost); SELECT SCOPE_IDENTITY();";
command.Parameters.AddWithValue("#Amount", amount);
command.Parameters.AddWithValue("#Cost", cost);
using(var reader = command.ExecuteReader())
{
if(reader.Read())
return Convert.ToInt32(reader[0]);
}
}
return 0;
}
If you want to use a parameters list in your C# code then just keep the parameter names grouped with their values and if the value is null and it has a default value then just skip it.
Passing in a NULL tells SQL that you want a NULL in that column overriding the default. If you want to pass something in pass in the keyword DEFAULT. I wrote an article, "keyword DEFAULT", about the usage:
The DEFAULT keyword causes the default value (from the constraint) to be inserted into the column.
Just remember that when you pass in DEFAULT don't put quotes around it. That makes it the string DEFAULT rather than the keyword DEFAULT.
The only other way of doing it I can think of would be triggers based your approach (and you're better off coding it at that point).
However, if you alter your approach to use stored procedures, you can do your value handling natively in SQL, otherwise you're stuck coding it into your app... might i recommend Ternary statements for your example: http://msdn.microsoft.com/en-us/library/ty67wk28%28v=vs.80%29.aspx .
If you include a column in the column list, it will try and insert the value you give, it. It will not assume that NULL means "just insert the default value".
If you don't want to insert a value into that column, don't include it in your column list (or value list, obviously).
While it may seem more efficient to loop through the table columns and be agnostic of the column name, type, etc. In the long run you may be better off handling each column explicitly so you can choose whether or not to use a default, verify the value, etc.
I actually used the INFORMATION_SCHEMA.COLUMNS table to pull back from SQL Server all of the Column Defaults. Then I just organized the defaults into a string[] and looped through it to insert defaults rather than nulls (some defaults are null).