Table for the inserts:
CREATE TABLE [dbo].[CcureMessage]
(
[CcureMessageId] [UNIQUEIDENTIFIER] NOT NULL,
[Event] [VARCHAR](20) NULL,
[Type] [VARCHAR](20) NULL,
[Message] [VARCHAR](MAX) NOT NULL,
[Xml] [VARCHAR](4000) NOT NULL,
CONSTRAINT [PK_CcureMessage]
PRIMARY KEY CLUSTERED ([CcureMessageId] ASC)
WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[CcureMessage]
ADD CONSTRAINT [DF_CcureMessage_CcureMessageId]
DEFAULT (NEWID()) FOR [CcureMessageId]
GO
I made the PK table have a default value so that I'm not passing a GUID at all, yet it seems I'm still getting an error related to the guid.
Insert command that works fine through SSMS:
INSERT INTO CcureMessage (Event, Type, Message, Xml)
VALUES ('event 3', 'type 3', 'big json 3', 'xml-ish');
C# Code:
public void DoInsert(Message msg)
{
// hard-coding this to set test values
TopicMessage tm = new TopicMessage();
tm.Event = "event 1";
tm.Type = "Type 1";
tm.Message = "json data message";
tm.Xml = "xml data goes here";
string connString = set to correct value;
string sql = "INSERT INTO CcureMessage (Event, Type, Message, Xml) VALUES (#Event, #Type, #Message, #Xml)";
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandType = System.Data.CommandType.Text;
SqlParameter eventParm = new SqlParameter("#Event", tm.CcureMessageId);
SqlParameter typeParm = new SqlParameter("#Type", tm.Type);
SqlParameter msgParm = new SqlParameter("#Message", tm.Message);
SqlParameter xmlParm = new SqlParameter("#Xml", tm.Xml);
cmd.Parameters.Add(eventParm);
cmd.Parameters.Add(typeParm);
cmd.Parameters.Add(msgParm);
cmd.Parameters.Add(xmlParm);
cmd.ExecuteNonQuery();
}
}
Running this results in the error
Insufficient result space to convert uniqueidentifier value to char
The problem seems that you are passing guid to a varchar column in your code
SqlParameter eventParm = new SqlParameter("#Event", tm.CcureMessageId);
Should be:
SqlParameter eventParm = new SqlParameter("#Event", tm.Event);
In my case, I wasn't working with guids in the C# code and received this error. So tracing this back to the stored proc, I found that the error came directly from there.
I traced it down to a conversion I was running on a GUID field as follows:
CONVERT(varchar(13), guid)
I assumed it would simply truncate the field value. So I had to do the following:
CONVERT(varchar(13), CONVERT(varchar(36), guid))
Related
According to my question with weird problem specified here how to fix
System.Data.SqlClient.SqlException: String or binary data would be truncated in table
My problem is, that if I am saving new problem into the database, its ID is always set to 0 (I checked this out in debugging), which then throws
System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Alert__Problem_I__17F790F9". The conflict occurred in database "SmartOne", table "dbo.Problem", column 'id'
But in SQL Server Management Studio, the ID is set correctly (ID is defined as an Identity column).
Where both I am using is in my question mentioned below. Thanks for any ideas or advice.
Method that saves Problem:
public void Save(Problem element)
{
using (SqlConnection conn = new SqlConnection(DatabaseSingleton.connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand("INSERT INTO Problem VALUES " +
"(#nameOfAlert, #value, #result, #message_ID) ", conn))
{
command.Parameters.Add(new SqlParameter("#nameOfAlert", element.NameOfAlert));
command.Parameters.Add(new SqlParameter("#value", (int)element.Value));
command.Parameters.Add(new SqlParameter("#result", (int)element.Result));
command.Parameters.Add(new SqlParameter("#message_ID", element.Message_Id));
command.ExecuteNonQuery();
command.CommandText = "Select ##Identity";
}
conn.Close();
}
}
Method that saves an Alert:
public void Save(Alert element)
{
using (SqlConnection conn = new SqlConnection(DatabaseSingleton.connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand("INSERT INTO [Alert] VALUES (#message_ID, #date, #email, #AMUser_ID, #Problem_ID) ", conn))
{
command.Parameters.Add(new SqlParameter("#message_ID", element.Id_MimeMessage));
command.Parameters.Add(new SqlParameter("#date", element.Date));
command.Parameters.Add(new SqlParameter("#email", element.Email));
command.Parameters.Add(new SqlParameter("#AMUser_ID", element.User_ID));
command.Parameters.Add(new SqlParameter("#Problem_ID", element.Problem_ID));
command.ExecuteNonQuery();
command.CommandText = "Select ##Identity";
}
conn.Close();
}
}
SQL Scheme
CREATE TABLE [dbo].[Alert](
[id] [int] IDENTITY(1,1) NOT NULL,
[message_ID] [varchar](100) NOT NULL,
[date] [datetime] NOT NULL,
[email] [varchar](50) NOT NULL,
[AMUser_ID] [int] NOT NULL,
[Problem_ID] [int] NOT NULL);
//Where is ID, it means FK ID
CREATE TABLE [dbo].[Problem](
[id] [int] IDENTITY(1,1) NOT NULL,
[nameOfAlert] [varchar](50) NOT NULL,
[Value_ID] [int] NOT NULL,
[Result_ID] [int] NOT NULL,
[message_ID] [varchar](100) NOT NULL);
One problem might be that you're never actually getting back the inserted IDENTITY value from your first insert - thus you aren't using any valid ProblemId value for your second insert.
Try something like this:
public void Save(Problem element)
{
using (SqlConnection conn = new SqlConnection(DatabaseSingleton.connString))
{
conn.Open();
// define INSERT query - I'd *strongly* recommend specifying all
// columns you're inserting into!
// Also: run the "SELECT SCOPE_IDENTITY()" right after the INSERT
string insertQry = "INSERT INTO dbo.Problem(NameOfAlert, Value, Result, MessageId) " +
"VALUES (#nameOfAlert, #value, #result, #message_ID); " +
"SELECT SCOPE_IDENTITY();";
using (SqlCommand command = new SqlCommand(insertQry, conn))
{
// also here: define the *datatype* of the parameter, and use
// .Value = to set the value.
// Since you haven't shown what the table looks like, I'm just
// **guessing** the datatype and max length for the string parameters - adapt as needed!
command.Parameters.Add("#nameOfAlert", SqlDbType.VarChar, 100).Value = element.NameOfAlert;
command.Parameters.Add("#value", SqlDbType.Int).Value = (int)element.Value;
command.Parameters.Add("#result", SqlDbType.Int).Value = (int)element.Result;
command.Parameters.Add("#message_ID", SqlDbType.VarChar, 100).Value = element.Message_Id;
// since your statement now returns the ID value - use "ExecuteScalar"
var returnedValue = command.ExecuteScalar();
if (returnedValue != null)
{
// if a value was returned - convert to INT
int problemId = Convert.ToInt32(returnedValue);
}
}
conn.Close();
}
}
Now, in case the INSERT works, you get back the ProblemId value from the identity column, and you can now use this in your second insert as value for the #ProblemId parameter.
For saving the id into other table, you have to complete the insertion first. if the insertion is not completed then you can not get the problem id (if it is the primary key, which is supposed to be returned by saving the datas). Only after saving the data to the table, you are going to have the problem id then you can use it as FK in the same method.
if i say, there is two table and you are going to use the first table primary key in the second table as FK. Then you need to complete the first table row insertion. after excuting the query for the first table, you will get the primary key of that row and you can use easily in the second table as FK.
protected void searchupdate_Click(object sender, EventArgs e)
{
SqlConnection con = Connection.DBconnection();
{
SqlCommand com = new SqlCommand("sp_searchupdate", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#id", txtid.Text.Trim());
com.Parameters.AddWithValue("#id_student", textstudentid.Text.Trim());
com.Parameters.AddWithValue("#tamil", txttamil.Text.Trim());
com.Parameters.AddWithValue("#english", txtenglish.Text.Trim());
com.Parameters.AddWithValue("#maths", txtmaths.Text.Trim());
com.Parameters.AddWithValue("#science", txtscience.Text.Trim());
com.Parameters.AddWithValue("#socialScience", txtsocialscience.Text.Trim());
SqlParameter retval = new SqlParameter("#output", SqlDbType.VarChar, 50);
retval.Direction = ParameterDirection.Output;
com.Parameters.Add(retval);
com.ExecuteNonQuery();
string Output = retval.Value.ToString();
output.Text = Output;
textstudentid.Text = string.Empty;
txttamil.Text = string.Empty;
txtenglish.Text = string.Empty;
txtmaths.Text = string.Empty;
txtscience.Text = string.Empty;
txtsocialscience.Text = string.Empty;
}
stored procedure:
ALTER PROCEDURE sp_searchupdate
(
#id int,
#id_student int,
#output varchar(50) output,
#Tamil Varchar (100),
#English varchar (50),
#Maths Varchar (50),
#Science Varchar (50),
#SocialScience Varchar (50)
)
AS
IF EXISTS (SELECT * FROM studentresult WHERE id=#id)
BEGIN
UPDATE studentresult SET Tamil = #Tamil,English = #English, Maths = #Maths,Science = #Science,SocialScience = #SocialScience WHERE id = #id
SET #output='Updated'
END
ELSE
BEGIN
INSERT INTO studentresult (id_student,Tamil,English,Maths,Science,SocialScience) values (#id_student,#Tamil,#English,#Maths,#Science,#SocialScience)
SET #output='Inserted'
END
when i enter input value and click update.. it shows the following error:
Insert statement conflict with foreign key fk_student.
The statement terminated
I'm new to .net, can anyone help me what my mistake.. or what should i do?
Any help would be highly appreciated..
Thanks,
Most probably, you are trying to insert an ID that is not present in the primary key of the referencing table.
This kind of issue happens when bad data is passed into tables and two tables have foreign key constraint defined between them which wont allow such data to be inserted.
The rule is like this, a FK (Foreign key) cannot have a value in that column that is not also in the primary key column of the referenced table. So you might have to check on the values that you are passing through your queries.
Hope this helps.
I'm new here and I'm facing a trouble currently, my scenario is that I wanted to insert and update data from Excel into a SQL Server table.
For the insert part it works perfectly but when it comes to update I have no idea how should I do that. I have search for few methods and I found this is the most comfortable for me by using stored procedure.
Here is my code that I'm using now. When I try it gave me this error:
Operand type clash: nvarchar is incompatible with user-defined table type
--- Stored procedure ---
CREATE PROCEDURE [dbo].[chkUpdate]
#Operator IC_CHK READONLY
AS
BEGIN
set nocount on;
MERGE INTO tb_Operator c1
USING #Operator c2 ON c1.IC = c2.IC
WHEN MATCHED THEN
UPDATE SET
c1.Name = c2.Name,
--c1.IC = c2.IC,
c1.Email = c2.Email,
c1.Status = c2.Status,
c1.Datetime = c2.Datetime
WHEN NOT MATCHED THEN
INSERT VALUES(c2.Name, c2.IC, c2.Email, c2.[Status], c2.[Datetime]);
end
--- User-defined table type ---
CREATE TYPE [dbo].[IC_CHK] as table
(
[Id] [int] NULL,
[Name] [nvarchar](50) NULL,
[IC] [bigint] NULL,
[Email] [nvarchar](MAX) NULL,
[Status] [nvarchar](50) NULL,
[Datetime] [datetime] NULL
)
VS 2010 code:
protected void btnImport_Click1(object sender, EventArgs e)
{
int i = 0;
try
{
string path = string.Concat(Server.MapPath("~/Excel/" + UploadExcel.FileName));
UploadExcel.SaveAs(path);
String strCon = string.Format("Provider=Microsoft.Ace.OLEDB.12.0;Data Source={0}; Extended Properties=Excel 12.0;",path);
OleDbDataAdapter myda = new OleDbDataAdapter("SELECT * FROM [sheet1$]", strCon);
DataTable myds = new DataTable();
myda.Fill(myds);
for (i = 0; i <= myds.Rows.Count - 1; i++)
{
String constr = ConfigurationManager.ConnectionStrings["conn"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
using (SqlCommand cmd = new SqlCommand("chkUpdate"))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.AddWithValue("#Operator", path);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
MsgBox1.alert("Import success");
View.Visible = true;
vBinds();
}
catch (Exception ex)
{
MsgBox1.alert(ex.Message);
}
}
Do check for me and I'm appreciate it. Thank you
P/S: I double confirm that my user-defined table type has the same data type with my table.
In the INSERT in your MERGE statement, I would recommend to explicitly define the columns you're inserting into. Most likely, that's the cause of the error - you're inserting your columns - but you're not specifying which target columns those should be inserted into.
Since you're not specifying that, you must supply values for each column in the table, in the exact order in which they are defined - is that really the case?? E.g. what do you insert into your ID column in the table??
Assuming the ID column on your actual database table is an IDENTITY column, I would use (otherwise, you'd have to list ID in the list of columns to insert into as well and provide a value in the VALUES list of values):
WHEN NOT MATCHED THEN
INSERT(Name, IC, Email, [Status], [DateTime])
VALUES(c2.Name, c2.IC, c2.Email, c2.[Status], c2.[Datetime]);
and I would also recommend not to use T-SQL reserved keywords like status or datetime as your column names - you're just asking for trouble doing so. Use more expressive names - something that really relates to your business domain - not just datetime.....
I have created User-Defined Table Types and have written stored procedure as below:
//Create the data type
CREATE TYPE [dbo].tbl_admintype AS TABLE
(
[code] [varchar](50) NULL,
[name] [varchar](100) NULL,
[branch] [varchar](100) NULL default '',
[location] [varchar](100) NULL default '',
[usertype] [varchar](50) NULL,
[password] [varchar](max) NULL,
[saltkey] [varchar](100) NULL
)
GO
//Stored Procedure
create PROCEDURE [dbo].[proc_tbl_admin_InsertItem]
#tbl_admintype tbl_admintype READONLY
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
MERGE INTO tbl_admin a
USING #tbl_admintype at
ON a.code=at.code and a.usertype=at.usertype
--WHEN MATCHED THEN
--UPDATE SET a.Name = at.Name,a.Country = at.Country
WHEN NOT MATCHED THEN
INSERT VALUES(at.name, at.code, at.password, at.saltkey,at.branch,at.location,at.usertype,1,getdate(),getdate());
select ''
END
The following piece of code works fine:
using (SqlConnection con1 = new SqlConnection(connectionstring))
{
using (SqlCommand cmd1 = new SqlCommand("proc_tbl_admin_InsertItem"))
{
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Connection = con1;
cmd1.Parameters.AddWithValue("#tbl_admintype", dt);
con1.Open();
cmd1.ExecuteNonQuery();
con1.Close();
}
}
But when I used the following function:
public int ExecuteNonQuery(string spName, params object[] parameterValues)
{
try
{
return db.ExecuteNonQuery(spName, parameterValues);
}
catch (DALException ex)
{
throw ex;
}
}
it gives the error:
"The incoming tabular data stream (TDS) remote procedure call (RPC)
protocol stream is incorrect. Table-valued parameter 1
("#tbl_admintype"), row 0, column 0: Data type 0xF3 (user-defined
table type) has a non-zero length database name specified. Database
name is not allowed with a table-valued parameter, only schema name
and type name are valid.".
Don't use AddWithValue. Instead, do this:
cmd1.Parameters.Add("#tbl_admintype", SqlDbType.Structured).Value = dt;
If you insist on using AddWithValue you can do it this way:
SqlParameter tvpParam = cmb1.Parameters.AddWithValue(
"#tbl_admintype", dt);
tvpParam.SqlDbType = SqlDbType.Structured;
This can be done since both the Add method and the AddWithValue method returns a reference to the parameter.
For more information, read this MSDN page.
You should create User Defined Table Type at SQL Server to send DataTable from C# to stored procedure.
Just open in SSMS:
Programmability -> Types -> UserDefined Table Types and right click New -> UserDefinedTableType
Then:
USE [YourDatabase]
GO
/****** Object: UserDefinedTableType [dbo].[tp_ParameterList]
Script Date: 18.10.2017 10:36:40 ******/
CREATE TYPE [dbo].[tp_ParameterList] AS TABLE(
[Name] [VARCHAR](255) NULL,
[Val] [VARCHAR](255) NULL
)
GO
Now you can execute your stored procedure with parameter which can accept DataTable:
ALTER PROCEDURE [dbo].[YourSPWithDataTable](
#AdditionalParams dbo.tp_ParameterList READONLY
)
AS
and you can call stored procedure from C# like that:
var cmd = new SqlCommand("YourSPWithDataTable", db.Database.Connection as SqlConnection,
db.Database.CurrentTransaction.UnderlyingTransaction as SqlTransaction);
cmd.CommandType = CommandType.StoredProcedure;
DataTable dt = new DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Val");
dt.Rows.Add("id_Person", 1);
dt.Rows.Add("id_Dep", 1);
cmd.Parameters.Add(new SqlParameter("#AdditionalParams", dt));
cmd.ExecuteNonQuery();
I am trying to update a column in a SQL Server DB from C# that is defined as nVarChar(max). The update works as long as the text length is 4000 characters or less. As soon as the length is 4001 I get the infamous error:
String or binary data would be truncated.
The statement has been terminated.
The update will work if it is run manually from within SQL Server Management Studio.
The C# code calls a SP to perform the update. I listed all the relevant code below:
CREATE TABLE [dbo].[UpdateTable]
(
[PK_ID] [int] IDENTITY(1,1) NOT NULL,
[NEWTEXT] [nvarchar](max) NULL,
CONSTRAINT [PK_UpdateTable]
PRIMARY KEY CLUSTERED ([PK_ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
--DATABASE STORED PROCEDURE
CREATE Procedure [dbo].[usp_UpdateText]
#ID int,
#NEWTEXT nvarchar (max)
AS
SET NOCOUNT ON
UPDATE [UpdateTable]
SET [NEWTEXT] = #NEWTEXT
WHERE PK_ID = #ID;
RETURN
C# DB code:
using System.Data;
using System.Data.SqlClient;
public static void UpdateText(AjaxObjects.TextObject obj)
{
SqlConnection connection = DataBase.GetConnection();
using (connection)
{
connection.Open();
using (SqlCommand cmd = new SqlCommand("usp_UpdateText", connection))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Int).Value = obj.Id;
cmd.Parameters.Add("#NEWTEXT", SqlDbType.NVarChar, -1).Value = obj.Text;
cmd.ExecuteNonQuery();
}
connection.Close();
}
}