The Overview: I've got a dropdown with a list of reports the user can run. In the table that holds this list, I have ReportID, ReportName, SProc and SQLView fields. The idea here is, the user selects a report name, and based on that a specific Stored Procedure will run, and then a specific view will be bound to a datagrid to display the report. For some reports you need to enter a date, for others you don't.
The Code: Here is what I have written;
protected void btnSubmit_OnClick(object sender, EventArgs e)
{
List<ReportData> myReportData = new List<ReportData>();
using (SqlConnection connection1 = new SqlConnection(str2))
{
//Query the Reports table to find the record associated with the selected report
using (SqlCommand cmd = new SqlCommand("SELECT * from tblManagerReports WHERE ReportID = " + cboFilterOption.SelectedValue + "", connection1))
{
connection1.Open();
using (SqlDataReader DT1 = cmd.ExecuteReader())
{
while (DT1.Read())
{
//Read the record into an "array", so you can find the SProc and View names
int MyRptID = Convert.ToInt32(DT1[0]);
string MyRptName = DT1[1].ToString();
string MyRptSproc = DT1[2].ToString();
string MySQLView = DT1[3].ToString();
//Run the Stored Procedure first
SqlConnection connection2 = new SqlConnection(str2);
SqlCommand cmd2 = new SqlCommand("" + MyRptSproc + "", connection2);
//Set up the parameters, if they exist
if (string.IsNullOrEmpty(this.txtStartDate.Text))
{
}
else
{
cmd2.Parameters.Add("#StDate", SqlDbType.Date).Value = txtStartDate.Text;
}
if (string.IsNullOrEmpty(this.txtEndDate.Text))
{
}
else
{
cmd2.Parameters.Add("#EnDate", SqlDbType.Date).Value = txtEndDate.Text;
}
if (MyRptSproc != "")
{
connection2.Open();
cmd2.ExecuteNonQuery();
}
try
{
//Now open the View and bind it to the GridView
string SelectView = "SELECT * FROM " + MySQLView + "";
SqlConnection con = new SqlConnection(str2);
SqlCommand SelectCmd = new SqlCommand(SelectView, con);
SqlDataAdapter SelectAdapter = new SqlDataAdapter(SelectCmd);
//Fill the dataset
DataSet RunReport = new DataSet();
SelectAdapter.Fill(RunReport);
GridView_Reports.DataSource = RunReport;
GridView_Reports.DataBind();
}
catch
{
ScriptManager.RegisterStartupScript(btnSubmit, typeof(Button), "Report Menu", "alert('There is no View associated with this report.\\nPlease contact the developers and let them know of this issue.')", true);
return;
}
}
}
}
}
The Problem: When the code hits the line
cmd2.ExecuteNonQuery();
and there is a start and end date entered, it's telling me "Procedure or function expects parameter '#StDate', which is not supplied." I've stepped through the code and see that cmd2 has 2 parameters, so why isn't the function seeing them?
Additionally, here's the specific stored procedure which is causing the snafu (I've got 2 others that run fine, but neither of them are trying to pass parameters to a stored procedure:
ALTER procedure [dbo].[usp_DailyProc]
#StDate smalldatetime,
#EnDate smalldatetime
AS
BEGIN
IF OBJECT_ID('Temp_DailyProduction') IS NOT NULL
drop table Temp_DailyProduction;
IF OBJECT_ID('Temp_AuditorDailyProduction') IS NOT NULL
drop table Temp_AuditorDailyProduction;
SELECT
[Audit Date],
Auditor,
Count([Doc #]) AS [Claim Count],
Count([Primary Error Code]) AS [Final Error],
SUM(case when [Status]='removed' then 1 else 0 end) as Removed,
SOCNUM
INTO Temp_DailyProc
FROM PreClosed
WHERE (((Get_Next_Status)='Closed' Or (Get_Next_Status)='Panel' Or (Get_Next_Status)='HPanel'))
GROUP BY [Audit Date], Auditor, SOCNUM
HAVING ((([Audit Date]) Between #StDate And #EnDate));
SELECT
TDP.[Audit Date],
TDP.Auditor,
EID.EMPLOYEE AS [Auditor Name],
TDP.[Claim Count],
TDP.[Final Error],
TDP.Removed,
TDP.[Removed]/TDP.[Final Error] AS [Error Removal Ratio],
TDP.SOCNUM
INTO Temp_AuditorDailyProc
FROM Temp_DailyProc TDP
LEFT JOIN PreLookup EID
ON TDP.Auditor = EID.ID_Trim;
drop table Temp_DailyProduction;
END
I think you need to use the AddWithValue method instead of the Add method.
AddWithValue replaces the SqlParameterCollection.Add method that takes
a String and an Object. The overload of Add that takes a string and an
object was deprecated because of possible ambiguity with the
SqlParameterCollection.Add overload that takes a String and a
SqlDbType enumeration value where passing an integer with the string
could be interpreted as being either the parameter value or the
corresponding SqlDbType value. Use AddWithValue whenever you want to
add a parameter by specifying its name and value.
Had another thought, you are passing a string (Text) value as Date parameter. I think you should convert this to a date type. e.g.
cmd2.Parameters.Add("#StDate", SqlDbType.Date).Value = DateTime.Parse(txtStartDate.Text);
A more robust way of doing this would be to use DateTime.TryParseExact.
Related
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 need to know, if I am writing the stored procedure correctly and If the C# code for executing is correct. for some reason the error being returned as is Incorrect syntax near 'c16b'. Old Error
The new error now is: Procedure or function 'sptimeupdate' expects parameter '#date', which was not supplied.
the nvarchar string for validating and updating in the column by ClientID is 3fc8ffa1-c16b-4d7b-9e55-1e88dfe15277, but the part in bold is only showing in the debug test intel sense in error handling
ALTER PROCEDURE sptimeupdate
#id nvarchar(50),
#date datetime
AS
BEGIN
SET NOCOUNT ON;
UPDATE ClientTable
SET Today_Date=(#date)
WHERE ClientID=(#id)
END
//--------------above stored procedure--------------------------------
//--------------Executing the stored procedure in C#
IEnumerable<XElement> searchClientID =
from clientid in main.XPathSelectElements("Network/ClientID")
where (string)clientid.Attribute("id") == IntializedPorts[i].ToString()
select clientid;
foreach (string clientid in searchClientID)
{
for (int up = 0; up < IntializedPorts.Count(); up++)
{
//Update the current time in the clientid tble.
//Renames the table copy for groups
try
{
string[] Clientid; //client id array
Clientid = new string[IntializedPorts.Count()]; //Intialization of the array
Clientid[up] = clientid.ToString();
DateTime td = Convert.ToDateTime(toolDate.Text); //Just added a datetime object withdate
SqlConnection sqlConnectionCmdString = new SqlConnection(#"Data=.\SQLEXPRESS;AttachDbFilename=C:\Users\Shawn\Documents\Visual Studio 2010\Projects\Server\database\ClientRegit.mdf;Integrated Security=True;User Instance=True");
//EXECUTE THE STORED PROCEDURE sptimedate
// string UpdateCommand = "sptimeupdate" + Clientid[up].ToString() + toolDate.Text;
string UpdateCommand = "sptimeupdate" + "'" + Clientid[up].ToString() + "'" + "'" +td.ToString()+ "'"; //this is the new UpdateCommand string as to pass parameters to stored procedure
SqlCommand sqlRenameCommand = new SqlCommand(UpdateCommand, sqlConnectionCmdString);
sqlConnectionCmdString.Open();
sqlRenameCommand.ExecuteNonQuery();
sqlConnectionCmdString.Close();
}
catch(DataException ex)
{ MessageBox.Show("Failed to UpdateCurrentTime","DataError",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
}
When you call a stored procedure from code you need to create a command with its command type set to StoredProcedure, otherwise the engine tries to use your command text as it was an sql text like SELECT INSERT etc... But the mose important thing is that you need to pass the parameters required by the stored procedure in the Parameters collection of the command
So this could be the code to replace the actual one
string UpdateCommand = "sptimeupdate";
using(SqlConnection sqlConnectionCmdString = new SqlConnection(......))
using(SqlCommand sqlRenameCommand = new SqlCommand(UpdateCommand, sqlConnectionCmdString))
{
DateTime td = Convert.ToDateTime(toolDate.Text);
sqlRenameCommand.CommandType = CommandType.StoredProcedure;
sqlRenameCommand.Parameters.Add("#id", SqlDbType.NVarChar).Value = Clientid[up].ToString();
sqlRenameCommand.Parameters.Add("#date", SqlDbType.DateTime).Value = td;
sqlConnectionCmdString.Open();
sqlRenameCommand.ExecuteNonQuery();
}
Notice two things. The using statement is the best practice to follow when you create a connection to ensure the correct closing and disposing of the connection, second, the parameter for the DateTime expected by the sp should be passed as a DateTime not as a string- Of course this means that you should be certain that the content of toolDate is convertible to a DateTime value.
Your error is originating from this line of code:
string UpdateCommand = "sptimeupdate" + Clientid[up].ToString() + toolDate.Text;
There you are just concatenating the Clientid[up].ToString() as a string into the other string, same with the toolDate.Text, both without and sql markup.
Your resulting SQL query would look like this (assuming toolDate.Text is '2014-10-23'):
sptimeupdate3fc8ffa1-c16b-4d7b-9e55-1e88dfe152772014-10-23
which as you can see is not a proper SQL command.
You should always use parametrized command statements when calling simple SQL commands.
However in your case, you are actually calling a stored procedure.
So change your code to handle it like a stored procedure, example below.
// Create the connection object once
using (SqlConnection sqlConnectionCmdString = new SqlConnection(#"Data=.\SQLEXPRESS;AttachDbFilename=C:\Users\Shawn\Documents\Visual Studio 2010\Projects\Server\database\ClientRegit.mdf;Integrated Security=True;User Instance=True"))
{
// Same with the SqlCommand object and adding the parameters once also
SqlCommand sqlRenameCommand = new SqlCommand("sptimeupdate", sqlConnectionCmdString);
sqlRenameCommand.CommandType = CommandType.StoredProcedure;
sqlRenameCommand.Parameters.Add("#id", SqlDbType.NVarChar);
sqlRenameCommand.Parameters.Add("#datetime", SqlDbType.DateTime);
// Open the connection once only
sqlConnectionCmdString.Open();
foreach (string clientid in searchClientID)
{
for (int up = 0; up < IntializedPorts.Count; up++)
{
try
{
// The below three lines seem redundant.
// Clientid[up] will be equal to clientid after it all, so just use clientid
//string[] Clientid;
//Clientid = new string[IntializedPorts.Count];
//Clientid[up] = clientid.ToString();
sqlRenameCommand.Parameters["#id"].Value = clientid;
sqlRenameCommand.Parameters["#datetime"].Value = toolDate.Text;
sqlRenameCommand.ExecuteNonQuery();
}
// Might want to move this try..catch outside the two loops,
// otherwise you will get this message each time an error happens
// which might be alot, depending on the side of searchClientID
catch (SqlException)
{
MessageBox.Show("Failed to UpdateCurrentTime", "DataError", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
NOTE:
Please read the comments inside the code above for additional advice and suggestions.
Recreating a SqlConnection and SqlCommand for each iteration will have a performance impact on your application. So rather create them once and reuse them until you are done.
Further reading can be done here:
SqlCommand (There are nice examples at the bottom of that page)
dotnetperls version of SqlCommand
P.S. your sql procedure's code looks fine, you could remove the SET NOTCOUNT ON since that does not really do much in this scenario
I'm running a query from a web form to update records. Since I'm just learning about C#, I'm using a command string as opposed to a stored procedure.
My update method is as follows:
public void updateOne()
{
string commandText = "update INVOICE SET <Redacted> = #<Redacted>,
Supplier = #Sup, SupplierName = #SupN, NetTotal = #Net,
VATTotal = #VAT, InvoiceDate = #InvDt "
<needed a line break here, which is why I split the string again>
+ "WHERE K_INVOICE = #K_INV";
using (SqlConnection dbConnection = new SqlConnection
(conParams.connectionString))
{
SqlCommand cmd = new SqlCommand(commandText, dbConnection);
cmd.Parameters.Add("#K_INV", SqlDbType.Int);
cmd.Parameters["#K_INV"].Value = #K_INV;
cmd.Parameters.AddWithValue("#<Redacted>", #<Redacted>.ToString());
cmd.Parameters.AddWithValue("#Sup", #Sup.ToString());
cmd.Parameters.AddWithValue("#SupN", #SupN.ToString());
cmd.Parameters.AddWithValue("#Net", #Net.ToString());
cmd.Parameters.AddWithValue("VAT", #VAT.ToString());
cmd.Parameters.AddWithValue("#InvDt", #InvDt.ToString());
try
{
dbConnection.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
errorString = e.Message.ToString();
}
}
}
Catch stalls on an SQL error (Incorrect syntax near SET), and I have an idea that the issue occurs because I convert the parameters to strings. The first parameter is an Int, which should be OK.
If this is the case, what should I convert the parameters to? If not, what on earth is wrong?
Try to add a # before the string to escape the breaklines, for sample:
string commandText = #"update INVOICE SET [Redacted] = #Redacted,
Supplier = #Sup, SupplierName = #SupN, NetTotal = #Net,
VATTotal = #VAT, InvoiceDate = #InvDt "
+ "WHERE K_INVOICE = #K_INV";
In parameterName argument you can add the # but the value not, just the variable, for sample
cmd.Parameters.AddWithValue("#Redacted", redacted.ToString());
Try to execute this query in the databse with some values to check if everything is correct. You could use [brackets] in the table name and column names if you have a reserved word.
I would recommend you read this blog article on the dangers of .AddWithValue():
Can we stop using AddWithValue already?
Instead of
cmd.Parameters.AddWithValue("#Sup", #Sup.ToString());
you should use
cmd.Parameters.Add("#Sup", SqlDbType.VarChar, 50).Value = ...(provide value here)..;
(is your variable in C# really called #SupN ?? Rather unusual and confusing....)
I would recommend to always define an explicit length for any string parameters you define
I want to check to see if some of the fields have some unique values - for instance, I want to check if field1, field2 in my table have a value of "YES". If both of them have "Yes" then I want to call some function, but if one of them has "No" value then I want to call some other function. Note in my select statement, I am passing an ID from the query-string. How can I do this?
protected void Check_ItemUpdated(object sender, DetailsViewUpdatedEventArgs e) {
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
SqlDataAdapter da = new SqlDataAdapter("SELECT ID, Field1, Field2 from MyTabel WHERE ID = '" + Request.QueryString["ID"] + "'", con);
DataTable dt = new DataTable();
da.Fill(dt);
}
If figuring out whether a specific set of criteria exists or not in a given record is all you need, then I can suggest you doing this check on Database side and then using ExecuteScalar to get the result:
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString))
{
using(SqlCommand cmd = new SqlCommand("SELECT count(*) from MyTabel WHERE ID =#ID And (Field1='Yes' And Field2='Yes')" , con))
{
cmd.parameters.Add("#ID",Request.QueryString["ID"]);
con.open();
int result = cmd.ExecuteScalar();
con.close();
if(result == 1)
// condition exists
// so call success function
else
// call failure function
}
}
Update:
This may not be directly related to the question but to get record Id from detailsView, you need to go through 2 steps:
Set the datakeynames property for the detailsView to the name of your table's primary key name – in this case, ID.
<asp:detailsview datakeynames="ID"
Now you can access the selected Id by
int id = (int)detailsView.SelectedValue;
Check here for more information.
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