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.
Related
I have a C# front-end to SQL Server back-end using Visual Studios 2017. When I initially created my table in the database, it was:
CREATE TABLE [dbo].[tblHazard_Reports]
(
[Id] INT PRIMARY KEY,
[Badge] INT NOT NULL,
[Full Name] VARCHAR NOT NULL
)
I have since changed it to
CREATE TABLE [dbo].[tblHazard_Reports]
(
[Id] INT IDENTITY(1, 1) PRIMARY KEY,
[Badge] INT,
[Full Name] VARCHAR(MAX)
)
However, when I run my SQLcmd.ExecuteNonQuery() statement, I'll either get the error that a column does not allow NULL or that a string or binary data will be truncated. Although everything in my project seems to show that my changes to the columns have been made, I get errors as if I never touched it.
I've looked online for a place to put a proper ALTER statement in Visual Studio, but I can't find anything. How can I rebuild my table to reflect the changes I've made?
Here is my C# code in case it is relevant.
private void InsertHazardItem(E3_Project.HazardItem currHaz)
{
using(SqlConnection cnn = new SqlConnection("connectionString"))
{
string commandString = "INSERT INTO tblHazard_Reports([ID], [Badge],
[Full Name]) VALUES(#ID, #Badge, #Name)";
using(SqlCommand command = new SqlCommand(commandString, cnn))
{
var parameterID = new SqlParameter("#ID", System.Data.SqlDbType.Int);
var parameterBadge = new SqlParameter("#Badge", System.Data.SqlDbType.Int);
var parameterName = new SqlParameter("#Name", System.Data.SqlDbType.VarChar);
parameterID.Value = currHaz.ID;
parameterBadge.Value = currHaz.Badge;
parameterName.Value = currHaz.Name;
command.Parameters.Add(parameterID);
command.Parameters.Add(parameterBadge);
command.Parameters.Add(parameterName);
cnn.Open()
command.ExecuteNonQuery(); //The error is always on this line
}
}
}
Note that the ID should be auto-incrementing, but I have it included here because, again, it doesn't seem that my change to the table has been built.
Since you defined the ID column as an IDENTITY column, the database takes care of setting that value when you INSERT a row. Try removing the ID column from your INSERT statement and it should work.
Unrequested Hint: You and everyone who ever uses your database will be much happier if you do not include spaces in your column names. [Full Name] would be better as FullName.
Alterations to a table must be done in code. In my case, I ended up using C# and ExecuteNonQuery to do so, as shown here.
Even new tables must be created with code and executed directly with code. Adding a new table to my database using the Visual Studio tools did not seem to actually show up and be used.
I'm developing a WinForm desktop application for users to input employees retirement data, using SQL Server 2008 as DB.
One of the tables that gets part of the user data has a reference to another table whose records were defined at design time, adding a Foreign Key constraint for consistency.
CREATE TABLE tbCongedo (
ID int IDENTITY(0,1) PRIMARY KEY,
ID_ANAGRAFICA int NOT NULL,
ID_TIPOLOGIA int NOT NULL,
DECORRENZA datetime NOT NULL,
PROT_NUM nvarchar(7) NOT NULL,
PROT_DATA datetime NOT NULL
);
CREATE TABLE tbTipologia (
ID int IDENTITY(0,1) PRIMARY KEY,
TIPOLOGIA nvarchar(20)
);
INSERT INTO tbTipologia VALUES ('CONGEDO'), ('POSTICIPO'), ('ANTICIPO'), ('REVOCA'), ('DECESSO')
ALTER TABLE tbCongedo
ADD CONSTRAINT FK_tbCongedo_tbTipologia
FOREIGN KEY (ID_TIPOLOGIA) REFERENCES tbTipologia(ID)
Then, I have this code that should execute the INSERT statement
public int Insert(SqlConnection Connessione)
{
using (SqlCommand Comando = new SqlCommand("INSERT INTO tbCongedo VALUES (#ID_ANAGRAFICA, #PROT_NUM, #PROT_DATA, #DECORRENZA, #ID_TIPOLOGIA); SELECT SCOPE_IDENTITY()", Connessione))
{
Comando.Parameters.AddWithValue("#ID_ANAGRAFICA", ID_ANAGRAFICA);
Comando.Parameters.AddWithValue("#PROT_NUM", PROT_NUM);
Comando.Parameters.AddWithValue("#PROT_DATA", PROT_DATA);
Comando.Parameters.AddWithValue("#DECORRENZA", DECORRENZA);
Comando.Parameters.AddWithValue("#ID_TIPOLOGIA", ID_TIPOLOGIA);
ID = Int32.Parse(Comando.ExecuteScalar().ToString());
}
return ID;
}
but I'm given this SqlException:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_tbCongedo_tbTipologia". The conflict occurred in database "Scadenziario_ver4_TEST", table "dbo.tbTipologia", column 'ID'
These are the data that I was trying to get inserted in the table:
ID_ANAGRAFICA = 2
ID_TIPOLOGIA = 0
PROT_DATA = {16/03/2018 00:00:00}
DECORRENZA = {16/03/2018 00:00:00}
PROT_NUM = 123456
Funny thing is that when I try to insert those same data manually through SQL Server Management Studio, I'm given no error at all.
Thanks.-
Try specifying fields: (col_name1, col_name2, ...).
Without that the VALUES may not be applied as how you might hope. Variable names are NOT automagically matched with similarly-named columns.
So like this:
... new SqlCommand
(
"INSERT INTO tbCongedo " +
" (ID_ANAGRAFICA, PROT_NUM, PROT_DATA, DECORRENZA, ID_TIPOLOGIA) "
"VALUES (#ID_ANAGRAFICA, #PROT_NUM, #PROT_DATA, #DECORRENZA, #ID_TIPOLOGIA); " +
"SELECT SCOPE_IDENTITY()", Connessione
)
...
I think the problem isn't in the data but in the INSERT statement itself. You are trying to insert the values to the wrong columns using the wrong order. To solve the issue you should either specify the columns in the INSERT statement or correct the order of the values. In your case the query will try to insert the value of #PROT_NUM in the ID_TIPOLOGIA instead.
I have a table SupplierMaster in a SQL Server database with a column SUPPLIERNAME.
I want to edit saved supplier name using stored procedure with below query
ALTER PROCEDURE [dbo].[usp_SupplierMasterUpdateDetails]
(
#SUPPLIERNAME NVARCHAR(50)
)
AS
BEGIN
UPDATE [dbo].[SupplierMaster]
SET [SUPPLIERNAME] = #SUPPLIERNAME
WHERE [SUPPLIERNAME] = #SUPPLIERNAME
END
and I run the BELOW code through "UPDATE BUTTON" to update the data.
string connString = ConfigurationManager.ConnectionStrings["dbx"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand("usp_SupplierMasterUpdateDetails", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// Parameter
cmd.Parameters.AddWithValue("SUPPLIERNAME", AddSupplierTextBox.Text);
// Open Connection
conn.Open();
// ExecuteReader (Select Statement)
// ExecuteScalar (Select Statement)
// ExecuteNonQuery (Insert, Update or Delete)
cmd.ExecuteNonQuery();
MessageBox.Show("SUCCESSFULLY UPDATED", "Successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
But its not updating the selected data.
Please advice and assist me to correct the code for proper work.
You have multiple issues there.
First you need to fix your update query just as Thomas Levesque suggested.
a SQL Server table needs a primary key to be able to uniquely identify a record, for updates for example.
The easiest thing you could do is set that primary key to be identity of type int and make it self generating. Your supplier table could look like this :
SupplierID int, Primary Key, identity
SupplierName nvarchar(100)
Now, when you do an update, you would do it like this:
Update SupplierMaster
Set SupplierName = #supplierName
Where SupplierID = #suplierID
Such a SQL statement will return an int value. This return value will tell you how many SQL rows this update statement has changed. If it says 0 then it means that the SQL statement could not find that id you passed through and nothing changed. If it says 1, then the record was found and updated, if you get more than 1 you have an issue with the SQL statement and multiple rows were updated.
In your code check for this return value and that's how you determine if your update statement was successful or not.
I have a method to insert user information into the SQL Server database. I have my combobox populate on pageload event. The user selects the input they want and hit update if they are updating a old record or insert if creating a new record. When they do so my database is not storing the right value if they select 4 it stores 3. Here is my insert method and populate method.
Insert method: I have to join the StockID because it is a primary key.
using (dbConn2 = new SqlConnection(Properties.Settings.Default["tville"].ToString()))
{
SqlCommand addNewFormat = new SqlCommand(#"INSERT INTO PackLabelFormat ( PackFormatID, Description, PrintWeight, PrintPlantCode, PrintPrice, StockID) VALUES (#PackFormatID, #Description, #PrintWeight, #PrintPlantCode, #PrintPrice, (SELECT #StockID from LabelStockReference LSR WHERE LSR.StockID = #StockID))", dbConn2);
addNewFormat.Parameters.AddWithValue("#PackFormatID", Convert.ToInt32(IDselect));
addNewFormat.Parameters.AddWithValue("#Description", rTxtBoxDescription.Text);
addNewFormat.Parameters.AddWithValue("#PrintPrice", rChkBoxPrintPrice.Checked);
addNewFormat.Parameters.AddWithValue("#PrintWeight", rChkBoxWeight.Checked);
addNewFormat.Parameters.AddWithValue("#PrintPlantCode", rChkBoxPlantCode.Checked);
addNewFormat.Parameters.AddWithValue("#StockID", Convert.ToInt32(cmboBoxStock.SelectedIndex));
dbConn2.Open();
addNewFormat.ExecuteNonQuery();
Populate method:
if (labelList != null)
{
foreach (LabelData l in labelList)
{
cmboBoxStock.Items.Add(string.Format("{0} - {1}", l.PackFormatID, l.Description));
}
}
If there is anything else I'm leaving out just let me know. Thanks.
There are two options for your INSERT statement:
(1) you can use INSERT ... VALUES .... and in this case, you must supply as many values as you have columns to insert data into, and you have to supply literal values or SQL Server variables only - you cannot use a SELECT to provide a value:
DECLARE #ASqlServerVariable VARCHAR(100)
SET #ASqlServerVariable = 'any possible value that's legal for this datatype'
INSERT INTO dbo.YourTable(ID, Col1, Col2, Col3)
VALUES (42, 'Some fixed value', #ASqlServerVariable, 'Another literal value')
What you could do is use a SELECT to store the value you're interested in into a SQL Server variable:
DECLARe #StockID INT
SELECT #StockID = ID
FROM dbo.LabelStockReference LSR
WHERE LSR.StockID = 4711
(2) if you can't provide all literal values or variables, then you must use the INSERT .... SELECT ... option, which requires you to provide as many columns in your SELECT as the INSERT expects to insert a row into the target table:
DECLARE #ASqlServerVariable VARCHAR(100)
SET #ASqlServerVariable = 'any possible value that's legal for this datatype'
INSERT INTO dbo.YourTable(ID, Col1, Col2, Col3)
SELECT
42, 'Some fixed value', #ASqlServerVariable, aTableColumn
FROM
dbo.SomeOtherTable
See the official TechNet documentation for INSERT for all the details and exact syntax of all possible options etc.
The first SelectedIndex is 0, and your first ID is 1 ,so just make this change:
addNewFormat.Parameters.AddWithValue("#StockID", Convert.ToInt32(cmboBoxStock.SelectedIndex)+1);
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).