I am using a trigger in SQL Server that works as required when executing a query in the query window in SQL Server Management Studio. The objective of the trigger is to take the latest value from one table (where an id corresponds to the inserted id) and add this value to the inserted row.
I am also using a DataAdapter in C# to interact with the same database that has the trigger. When I use MyAdapter.update(MyDataTable) to insert new values into the table that the trigger is assigned to, the trigger does not execute.
I have done a lot of googling but nobody else seems to have that problem so I am thinking I am missing something fundamental. I am also new to database interaction with .Net. The data adapter works properly (i.e. inserts and updates as needed) except for not firing the trigger.
Below are some excerpts from my C# code and the trigger.
CREATE TRIGGER getLatestCap
ON TestIDTable
AFTER insert
AS
BEGIN
SET NOCOUNT ON;
DECLARE #BID INT;
DECLARE #Date Date;
SET #BID = (SELECT BattID FROM inserted);
SET #Date = (SELECT Test_Date FROM inserted);
SELECT M_Cap, Cap_Date
INTO #tempTable
FROM CapDataTable
WHERE BattID = #BID;
-- Set the Test_Cap entry in TestIDTable to that capacity.
UPDATE TestIDTable
SET Test_Cap = (SELECT M_Cap
FROM #tempTable
WHERE Cap_Date = (SELECT max(Cap_Date)
FROM #tempTable))
WHERE BattID = #BID AND Test_Date = #Date;
END
GO
private void Setup()
{
try
{
string BattSelect = "SELECT * FROM " + tbl;
dt = new DataTable();
Adpt = new SqlDataAdapter(BattSelect, ConnectionStr);
builder = new SqlCommandBuilder(Adpt);
Adpt.Fill(dt);
}
catch (Exception e)
{
MessageBox.Show("While Connecting to "+tbl+": " + e.ToString());
}
}
private void UpdateDB()
{
try
{
Adpt.InsertCommand = builder.GetInsertCommand();
Adpt.UpdateCommand = builder.GetUpdateCommand();
Adpt.Update(dt);
}
catch (Exception e)
{
MessageBox.Show("While Updating " + tbl + ": " + e.ToString());
}
}
Question summary: the trigger works in SQL Server, but does fire (nor complains) when using a data adapter.
Thanks for your time and help!
Marvin
Following HABO's Tip (below original post) I modified my trigger to work for multiple inserted rows. This has solved my problem. New trigger code below:
CREATE TRIGGER getLatestCap
ON TestIDTable
AFTER insert
AS
BEGIN
SET NOCOUNT ON;
UPDATE TestIDTable
set Test_Cap = M_Cap
FROM
(SELECT C.BattID, Test_Date, M_Cap
FROM
(SELECT t.BattID, t.M_Cap, t.Cap_Date
FROM CapDataTable t
INNER JOIN(
SELECT BattID, max(Cap_Date) as Latest
FROM CapDataTable
GROUP BY BattID
) tm on t.BattID = tm.BattID and t.Cap_Date = tm.Latest)
C INNER JOIN inserted I
on C.BattID = I.BattID) as t1
INNER JOIN TestIDTable as t2
on t1.BattID = t2.BattID AND t1.Test_Date = t2.Test_Date
END
GO
Thanks for your help!
Your firing the trigger after INSERT. With the SQLDataAdapter you're performing an UPDATE. Those are two very different types of transactions.
Try setting your trigger to ON UPDATE. That should do the trick.
Related
I am trying to carry out an 'insert if not exists' statement, i am not receiving any errors and the row does not exist in the db, however it still will not add it. Executing a normal 'insert' works but not when the 'if not exists' is added.
I have also tried including BEGIN & END and it doesnt work.
Where am i going wrong??
string getStudentModuleId = "SELECT ModuleId FROM StudentModuleMarks WHERE Mark < 40";
SqlCommand myCommand = new SqlCommand(getStudentModuleId, MyConnection3);
try
{
moduleid = (int)myCommand.ExecuteScalar();
string addRepeat = "IF NOT EXISTS (SELECT * FROM StudentModules WHERE ModuleId = #moduleid AND SchoolYear = '2018') INSERT INTO StudentModules(StudentDegreeId, ModuleId, Repeat, SchoolYear, EnrolledStatus) VALUES (1,#moduleid,1,'2018','Active')";
SqlCommand command = new SqlCommand(addRepeat, MyConnection3);
command.Parameters.AddWithValue("#moduleid", moduleid);
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
It seems you are using sql server, For MySQL, you can follow this technique to insert record if it doesn't exist :
INSERT INTO StudentModules(StudentDegreeId, ModuleId, Repeat, SchoolYear, EnrolledStatus)
select 1,#moduleid, 1, '2018', 'Active' from dual
where NOT EXISTS (SELECT * FROM StudentModules WHERE ModuleId = #moduleid AND SchoolYear = '2018')
Please note that, in MySQL, you don't really need to have a table called dual to exist: it is a special table-name that can be used to select anything from it. And it will output a single record always with a SELECT query like above.
I have this code:
string insertSql =
"INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)";
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("#UserId", newUserId);
myCommand.Parameters.AddWithValue("#GameId", newGameId);
myCommand.ExecuteNonQuery();
myConnection.Close();
}
When I insert into this table, I have an auto_increment int primary key column called GamesProfileId, how can i get the last inserted one after this so I can use that id to insert into another table?
For SQL Server 2005+, if there is no insert trigger, then change the insert statement (all one line, split for clarity here) to this
INSERT INTO aspnet_GameProfiles(UserId,GameId)
OUTPUT INSERTED.ID
VALUES(#UserId, #GameId)
For SQL Server 2000, or if there is an insert trigger:
INSERT INTO aspnet_GameProfiles(UserId,GameId)
VALUES(#UserId, #GameId);
SELECT SCOPE_IDENTITY()
And then
Int32 newId = (Int32) myCommand.ExecuteScalar();
You can create a SqlCommand with CommandText equal to
INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(#UserId, #GameId)
and execute int id = (int)command.ExecuteScalar.
This MSDN article will give you some additional techniques.
string insertSql =
"INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)SELECT SCOPE_IDENTITY()";
int primaryKey;
using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
myConnection.Open();
SqlCommand myCommand = new SqlCommand(insertSql, myConnection);
myCommand.Parameters.AddWithValue("#UserId", newUserId);
myCommand.Parameters.AddWithValue("#GameId", newGameId);
primaryKey = Convert.ToInt32(myCommand.ExecuteScalar());
myConnection.Close();
}
This will work.
I had the same need and found this answer ..
This creates a record in the company table (comp), it the grabs the auto ID created on the company table and drops that into a Staff table (staff) so the 2 tables can be linked, MANY staff to ONE company. It works on my SQL 2008 DB, should work on SQL 2005 and above.
===========================
CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]
#comp_name varchar(55) = 'Big Company',
#comp_regno nchar(8) = '12345678',
#comp_email nvarchar(50) = 'no1#home.com',
#recID INT OUTPUT
-- The '#recID' is used to hold the Company auto generated ID number that we are about to grab
AS
Begin
SET NOCOUNT ON
DECLARE #tableVar TABLE (tempID INT)
-- The line above is used to create a tempory table to hold the auto generated ID number for later use. It has only one field 'tempID' and its type INT is the same as the '#recID'.
INSERT INTO comp(comp_name, comp_regno, comp_email)
OUTPUT inserted.comp_id INTO #tableVar
-- The 'OUTPUT inserted.' line above is used to grab data out of any field in the record it is creating right now. This data we want is the ID autonumber. So make sure it says the correct field name for your table, mine is 'comp_id'. This is then dropped into the tempory table we created earlier.
VALUES (#comp_name, #comp_regno, #comp_email)
SET #recID = (SELECT tempID FROM #tableVar)
-- The line above is used to search the tempory table we created earlier where the ID we need is saved. Since there is only one record in this tempory table, and only one field, it will only select the ID number you need and drop it into '#recID'. '#recID' now has the ID number you want and you can use it how you want like i have used it below.
INSERT INTO staff(Staff_comp_id)
VALUES (#recID)
End
-- So there you go. You can actually grab what ever you want in the 'OUTPUT inserted.WhatEverFieldNameYouWant' line and create what fields you want in your tempory table and access it to use how ever you want.
I was looking for something like this for ages, with this detailed break down, I hope this helps.
In pure SQL the main statement kools like:
INSERT INTO [simbs] ([En]) OUTPUT INSERTED.[ID] VALUES ('en')
Square brackets defines the table simbs and then the columns En and ID, round brackets defines the enumeration of columns to be initiated and then the values for the columns, in my case one column and one value. The apostrophes enclose a string
I will explain you my approach:
It might be not easy to understand but i hope useful to get the big picture around using the last inserted id. Of course there are alternative easier approaches. But I have reasons to keep mine. Associated functions are not included, just their names and parameter names.
I use this method for medical artificial intelligence
The method check if the wanted string exist in the central table (1). If the wanted string is not in the central table "simbs", or if duplicates are allowed, the wanted string is added to the central table "simbs" (2). The last inseerted id is used to create associated table (3).
public List<int[]> CreateSymbolByName(string SymbolName, bool AcceptDuplicates)
{
if (! AcceptDuplicates) // check if "AcceptDuplicates" flag is set
{
List<int[]> ExistentSymbols = GetSymbolsByName(SymbolName, 0, 10); // create a list of int arrays with existent records
if (ExistentSymbols.Count > 0) return ExistentSymbols; //(1) return existent records because creation of duplicates is not allowed
}
List<int[]> ResultedSymbols = new List<int[]>(); // prepare a empty list
int[] symbolPosition = { 0, 0, 0, 0 }; // prepare a neutral position for the new symbol
try // If SQL will fail, the code will continue with catch statement
{
//DEFAULT und NULL sind nicht als explizite Identitätswerte zulässig
string commandString = "INSERT INTO [simbs] ([En]) OUTPUT INSERTED.ID VALUES ('" + SymbolName + "') "; // Insert in table "simbs" on column "En" the value stored by variable "SymbolName"
SqlCommand mySqlCommand = new SqlCommand(commandString, SqlServerConnection); // initialize the query environment
SqlDataReader myReader = mySqlCommand.ExecuteReader(); // last inserted ID is recieved as any resultset on the first column of the first row
int LastInsertedId = 0; // this value will be changed if insertion suceede
while (myReader.Read()) // read from resultset
{
if (myReader.GetInt32(0) > -1)
{
int[] symbolID = new int[] { 0, 0, 0, 0 };
LastInsertedId = myReader.GetInt32(0); // (2) GET LAST INSERTED ID
symbolID[0] = LastInsertedId ; // Use of last inserted id
if (symbolID[0] != 0 || symbolID[1] != 0) // if last inserted id succeded
{
ResultedSymbols.Add(symbolID);
}
}
}
myReader.Close();
if (SqlTrace) SQLView.Log(mySqlCommand.CommandText); // Log the text of the command
if (LastInsertedId > 0) // if insertion of the new row in the table was successful
{
string commandString2 = "UPDATE [simbs] SET [IR] = [ID] WHERE [ID] = " + LastInsertedId + " ;"; // update the table by giving to another row the value of the last inserted id
SqlCommand mySqlCommand2 = new SqlCommand(commandString2, SqlServerConnection);
mySqlCommand2.ExecuteNonQuery();
symbolPosition[0] = LastInsertedId; // mark the position of the new inserted symbol
ResultedSymbols.Add(symbolPosition); // add the new record to the results collection
}
}
catch (SqlException retrieveSymbolIndexException) // this is executed only if there were errors in the try block
{
Console.WriteLine("Error: {0}", retrieveSymbolIndexException.ToString()); // user is informed about the error
}
CreateSymbolTable(LastInsertedId); //(3) // Create new table based on the last inserted id
if (MyResultsTrace) SQLView.LogResult(LastInsertedId); // log the action
return ResultedSymbols; // return the list containing this new record
}
I tried the above but they didn't work, i found this thought, that works a just fine for me.
var ContactID = db.GetLastInsertId();
Its less code and i easy to put in.
Hope this helps someone.
You can also use a call to SCOPE_IDENTITY in SQL Server.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace DBDemo2
{
public partial class Form1 : Form
{
string connectionString = "Database=company;Uid=sa;Pwd=mypassword";
System.Data.SqlClient.SqlConnection connection;
System.Data.SqlClient.SqlCommand command;
SqlParameter idparam = new SqlParameter("#eid", SqlDbType.Int, 0);
SqlParameter nameparam = new SqlParameter("#name", SqlDbType.NChar, 20);
SqlParameter addrparam = new SqlParameter("#addr", SqlDbType.NChar, 10);
public Form1()
{
InitializeComponent();
connection = new System.Data.SqlClient.SqlConnection(connectionString);
connection.Open();
command = new System.Data.SqlClient.SqlCommand(null, connection);
command.CommandText = "insert into employee(ename, city) values(#name, #addr);select SCOPE_IDENTITY();";
command.Parameters.Add(nameparam);
command.Parameters.Add(addrparam);
command.Prepare();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void buttonSave_Click(object sender, EventArgs e)
{
try
{
int id = Int32.Parse(textBoxID.Text);
String name = textBoxName.Text;
String address = textBoxAddress.Text;
command.Parameters[0].Value = name;
command.Parameters[1].Value = address;
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
reader.Read();
int nid = Convert.ToInt32(reader[0]);
MessageBox.Show("ID : " + nid);
}
/*int af = command.ExecuteNonQuery();
MessageBox.Show(command.Parameters["ID"].Value.ToString());
*/
}
catch (NullReferenceException ne)
{
MessageBox.Show("Error is : " + ne.StackTrace);
}
catch (Exception ee)
{
MessageBox.Show("Error is : " + ee.StackTrace);
}
}
private void buttonSave_Leave(object sender, EventArgs e)
{
}
private void Form1_Leave(object sender, EventArgs e)
{
connection.Close();
}
}
}
There are all sorts of ways to get the Last Inserted ID but the easiest way I have found is by simply retrieving it from the TableAdapter in the DataSet like so:
<Your DataTable Class> tblData = new <Your DataTable Class>();
<Your Table Adapter Class> tblAdpt = new <Your Table Adapter Class>();
/*** Initialize and update Table Data Here ***/
/*** Make sure to call the EndEdit() method ***/
/*** of any Binding Sources before update ***/
<YourBindingSource>.EndEdit();
//Update the Dataset
tblAdpt.Update(tblData);
//Get the New ID from the Table Adapter
long newID = tblAdpt.Adapter.InsertCommand.LastInsertedId;
Hope this Helps ...
After inserting any row you can get last inserted id by below line of query.
INSERT INTO aspnet_GameProfiles(UserId,GameId)
VALUES(#UserId, #GameId);
SELECT ##IDENTITY
If you're using executeScalar:
cmd.ExecuteScalar();
result_id=cmd.LastInsertedId.ToString();
Maybe this answer helps as well as my database seems to have no column specified as "IDENTITY" (which is needed for "SELECT SCOPE_IDENTITY()" or "##IDENTITY" calls). Also my "ID" column was of type "binary(16)" so I needed to convert the output like stated below:
string returnId = BitConverter.ToString((byte[])cmd.ExecuteScalar()).Replace("-", "");
// skip the replace if you handle the hyphen otherwise
Use SELECT SCOPE_IDENTITY() in query
After this:
INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(#UserId, #GameId)
Execute this
int id = (int)command.ExecuteScalar;
It will work
INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(#UserId, #GameId)";
then you can just access to the last id by ordering the table in desc way.
SELECT TOP 1 UserId FROM aspnet_GameProfiles ORDER BY UserId DESC.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[spCountNewLastIDAnyTableRows]
(
#PassedTableName as NVarchar(255),
#PassedColumnName as NVarchar(225)
)
AS
BEGIN
DECLARE #ActualTableName AS NVarchar(255)
DECLARE #ActualColumnName as NVarchar(225)
SELECT #ActualTableName = QUOTENAME( TABLE_NAME )
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #PassedTableName
SELECT #ActualColumnName = QUOTENAME( COLUMN_NAME )
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = #PassedColumnName
DECLARE #sql AS NVARCHAR(MAX)
SELECT #sql = 'select MAX('+ #ActualColumnName + ') + 1 as LASTID' + ' FROM ' + #ActualTableName
EXEC(#SQL)
END
i want fetch a huge data on site (about 19000 record) and show that on datalist control.
my data list have a paging feature and on the first time i show only 6 record on datalist.
then he user can go to page 2 and 3 and ...
fetch all record to data table get more time.
Please help me in details what should i use in sql server.
private void FetchDataToDataList()
{
DataTable dt = new DataTable();
if (Cache["DataTable-cach"] == null)
{
String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand("SELECT dbo.table_name.field_name, FROM dbo.table_name ", con);
con.Open();
dt = new DataTable("T");
string startime = System.DateTime.Now.ToLongTimeString();
dt.Load(cmd.ExecuteReader());
string endtime = System.DateTime.Now.ToLongTimeString();
Cache.Insert("DataTable-cach", dt, null, DateTime.Now.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration);
con.Close();
}
else
{
dt = ((DataTable)Cache["DataTable-cach"]);
}
// pagedDS is data list control
PagedDataSource pagedDS = new PagedDataSource();
pagedDS.DataSource = dt.DefaultView;
pagedDS.AllowPaging = true;
pagedDS.PageSize = 6;
pagedDS.CurrentPageIndex = CurrentPage;
dlPaging.DataSource = pagedDS;
dlPaging.DataBind();
lblCurrentPage.Text = pagedDS.PageCount.ToString() +" صفحه " + (CurrentPage + 1).ToString()+ " از " ;
// Disable Prev or Next buttons if necessary
cmdPrev.Enabled = !pagedDS.IsFirstPage;
cmdNext.Enabled = !pagedDS.IsLastPage;
}
Depending on the SQL Server version, you should request only as many records from the database as you need.
In SQL Server 2012 you can use the OFFSET and FETCH NEXT keywords. In earlier versions, use ROW_NUMBER.
Laoding 19,000 records at a time is not a good option beacuse it would take time to build all the html at the same time.
And most importantly you are not going to display all the records at a time.
So, you need to load only those records that are currently being displayed to user.
This tremendously boosts your performance / page load speed.
Write your stored procedure in such a way that you are fetching only required records and not records all at a time.
Example:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
CREATE PROCEDURE GetDataPageWise // Name of the stored procedure
#PageIndex INT = 1
,#PageSize INT = 10
,#RecordCount INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT ROW_NUMBER() OVER
(
ORDER BY [ColumnName] ASC
)AS RowNumber
,[ColumnName]
,[ColumnName]
,[ColumnName]
INTO #Results // #Results is the temporary table that we are creating
FROM [TableName]
SELECT #RecordCount = COUNT(*)
FROM #Results
SELECT * FROM #Results
WHERE RowNumber BETWEEN(#PageIndex -1) * #PageSize + 1 AND(((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results // Dropping the temporary table results as it is not required furthur
END
GO
Hope this helps..
You can try paging like below
http://www.codeproject.com/Articles/192408/SQL-Pager-Control-for-GridView-DataList-Repeater-D
Can you use a WHERE statement within an INSERT INTO statement in SQL?
here is what i am currently trying to do.
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
VALUES (#ComponentType, #CompDescr)
WHERE (AssetTagNumber = #TagNo)
But the compiler is having an issue with the WHERE statement.
thanks
***UPDATE****
This is the full code that i am using so far with amendments
protected void AddBut_Click(object sender, EventArgs e)
{
//still passing the Asset tag number forward here
var ID = Request.QueryString["Id"];
string sql = "";
using (SqlConnection con = new SqlConnection("Data Source: *******************)
{
sql = "IF (AssetTagNumber = #TagNo) " +
"BEGIN " +
"INSERT INTO AssetComponents(ComponentID, ComponentDescription) " +
"VALUES (#ComponentType, #CompDescr) " +
"END ";
using (SqlCommand cmd = new SqlCommand(sql, con))
{
// try
// {
cmd.Parameters.AddWithValue("#TagNo", ID);
cmd.Parameters.AddWithValue("#ComponentType", TypeDDL.Text.Trim());
cmd.Parameters.AddWithValue("#CompDescr", DescrTB.Text.Trim());
con.Open();
cmd.ExecuteNonQuery();
con.Close();
Response.Redirect("ComponentDetails.aspx");
// }
// catch (SqlException ex) { MessageBox.Show(" "); }
// catch (Exception ex) { MessageBox.Show(" "); }
}
}
}
Im sorry i was not clear enough first time around.
What i want to do is insert a new record with a clause that says if this record has an existing PK then use this key to insert another entry for that record
Apologies once again
Why don't you just use IF-clause?
IF (AssetTagNumber = #TagNo)
BEGIN
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
VALUES (#ComponentType, #CompDescr)
END
For statements with WHERE script should look similar to:
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
SELECT #ComponentType, #CompDescr
FROM <table>
WHERE (AssetTagNumber = #TagNo)
You can not "conditionally insert" like that. The WHERE clause is only available for SELECT, UPDATE or DELETE.
To check whether you need to INSERT a new record, you need to use IF, as in:
IF NOT EXISTS (SELECT ...)
INSERT INTO ...
if EXISTS (select * from AssetComponents where AssetTagNumber = #TagNo)
Begin
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
(#ComponentType, #CompDescr)
End
Use this:
UPDATE AssetComponents
Set ComponentID=#ComponentType, ComponentDescription=#CompDesc
Where AssetTagNumber = #TagNo
WHERE clause is something that helps to filter record, so it preferably uses with either SELECT or UPDATE. For INSERT we normally use IF NOT EXISTS clause.
See Examples:
http://social.msdn.microsoft.com/Forums/sqlserver/en-US/724ab6f3-413f-4c59-9b68-776f3ecfa899/insert-if-not-exists-into
http://msdn.microsoft.com/en-us/library/ms174335.aspx
Also, after looking at documentation, we can see that INSERT statement has NO support for WHERE clause.
If records already exists you can perform eith UPDATE or DELETE with INSERT operations.
You can try like:
IF NOT EXISTS (SELECT * FROM AssetComponents WHERE (AssetTagNumber = #TagNo))
INSERT INTO AssetComponents(ComponentID, ComponentDescription) VALUES (#ComponentType, #CompDescr)
ELSE
--UPDATE fields
Consider INSERT SELECT:
INSERT INTO AssetComponents(ComponentID, ComponentDescription)
SELECT [fill out here] AS ComponentID,
[fill out here] AS ComponentDescription
FROM somesource
WHERE [condition]
This is a specialty of MS SQL Server so will not work in other databases. It sort of requires that your data are already in another table or other source that you can query.
I have a stored procedure that contains like 10 different INSERTS, is it possible to return the COUNT of the rows affected on each INSERT to ASP.NET c# page so i can display Stored Procedure process for the client viewing that ASP.NET page?
You need to use following command in the start of your stored procedure:
SET NOCOUNT OFF
In this case SQL server will send text messages ("X rows affected" ) to client in real time after each INSERT/UPDATE. So all you need is to read these messages in your software.
Here is my answer how to do it in Delphi for BACKUP MS SQL command. Sorry I've not enough knowledge in C# but I guess you can do it in C# with SqlCommand class.
On the server side send the message to the client using RAISERROR function with severity 10 (severity higher than 10 causes exception that breaks procedure execution, i.e. transfers execution to the CATCH block, if there is one). In the following example I haven't added error number, so the default error number of 50000 will be used by RAISERROR function. Here is the example:
DECLARE #count INT = 0
DECLARE #infoMessage VARCHAR(1000) = ''
-- INSERT
SET #count = ##ROWCOUNT
SET #infoMessage = 'Number of rows affected ' + CAST(#count AS VARCHAR(10))
RAISERROR(#infoMessage, 10, 0) WITH NOWAIT
-- another INSERT
SET #count = ##ROWCOUNT
SET #infoMessage = 'Number of rows affected ' + CAST(#count AS VARCHAR(10))
RAISERROR(#infoMessage, 10, 0) WITH NOWAIT
On the client side, set the appropriate event handlers, here is an example:
using (SqlConnection conn = new SqlConnection(...))
{
conn.FireInfoMessageEventOnUserErrors = true;
conn.InfoMessage += new SqlInfoMessageEventHandler(conn_InfoMessage);
using (SqlCommand comm = new SqlCommand("dbo.sp1", conn)
{ CommandType = CommandType.StoredProcedure })
{
conn.Open();
comm.ExecuteNonQuery();
}
}
static void conn_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
// Process received message
}
After every Inserts, use ##ROWCOUNT, then get the value by query.
Returns the number of rows affected by the last statement. If the
number of rows is more than 2 billion, use ROWCOUNT_BIG.
Sample:
USE AdventureWorks2012;
GO
UPDATE HumanResources.Employee
SET JobTitle = N'Executive'
WHERE NationalIDNumber = 123456789
IF ##ROWCOUNT = 0
PRINT 'Warning: No rows were updated';
GO
Edit: How you can get ##rowcount with multiple query? Here's an example:
DECLARE #t int
DECLARE #t2 int
SELECT * from table1
SELECT #t=##ROWCOUNT
SELECT * from table2
SELECT #t2=##ROWCOUNT
SELECT #t,#t2'