I am trying to add a new row in oracle and get the ID of the newly inserted row, here is what my code looks like
cmd.CommandText = "insert into table1 (id,col2) values (id_seq.NEXTVAL,'abc') returning id into :new_id";
OracleParameter objParameter = new OracleParameter("new_id", OracleDbType.Varchar2);
objParameter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(objParameter);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
newID = objParameter.Value;
What am I doing wrong?
Try by changing the insert query to:
insert into table1 (id,col2) values (id_seq.NEXTVAL,'abc') returning id into new_id
Related
I have a .Net application that loads a datatable from an oracle Database. The table contains a virtual column.
When I'm inserting a new row in datatable, it says :
Insert INSERT operation disallowed on virtual columns
I do understand this error but I don't know how to skip the virtual columns when saving data back to the database.
Here is my code :
Dim Command As OracleCommand
Dim TempDataAdapter As OracleDataAdapter
Dim DataSet = new DataSet
Dim Name = "MyTable"
Dim TempDataAdapter As OracleDataAdapter
Dim DataTable as DataTable
'The connection is defined somewhere else...
Command = New OracleCommand("MyTable", Me.Connection)
Command.CommandType = CommandType.Text
TempDataAdapter = New OracleDataAdapter(Command)
'Fill the table from the database
TempDataAdapter.FillSchema(DataSet, SchemaType.Source, Name)
DataTable = DataTable = DataSet.Tables(0)
And the code for saving data back to database :
TempDataAdapter.Update(DataTable)
After the creation of the datatable, I tried deleting the virtual column from the datatable :
DataTable.Columns.Remove(DataTable.Columns("MyVirtualColumn"))
But when saving data back to the database, it returns the same error.
Can anyone help please ?
Cheers,
If you are not trying to populate or query the virtual column, can you create a view on that table that excludes the virtual column and work with that view.
When you insert data into table with virtual columns then you must list columns, i. e. you must not use
Insert into table_x values (x, y, z)
but
Insert into table_x (col1, col2, col3) values (x, y, z)
Write your .net statements accordingly. If you try to update with DataTable then you can use a view which excludes the virtual columns:
CREATE OR REPLACE VIEW V_MyTable AS
SELECT col1, col2 -- skip virtual_col3
FROM MyTable;
In case you like to select virtual columns but skip them for INSERT (or UPDATE) you can create a view with a INSTEAD OF Trigger. Would be like this:
CREATE OR REPLACE VIEW V_MyTable AS
SELECT col1, col2, virtual_col3
FROM MyTable;
CREATE OR REPLACE TRIGGER IO_MyTable
INSTEAD OF INSERT OR UPDATE ON V_MyTable
FOR EACH ROW
BEGIN
IF UPDATING THEN
UPDATE MyTable SET
col1 = :NEW.col1,
col2 = :NEW.col2
WHERE primary_key_col = :OLD.primary_key_col;
ELSIF INSERTING THEN
INSERT INTO MyTable (col1, col2) VALUES (:NEW.col1, :NEW.col2);
END IF;
END;
I want to insert a record to a table called Payment which has column ID as the primary key(Auto Increment) and then I want to get that ID to use in a WHERE clause of another update statement.
var insertSatement = #"BEGIN INSERT INTO Payment (payment_type, reference, payment_date, total_records, total_amount) VALUES(#type, #reference, #date, #totalRecords, #totalAmount ) ";
var updateStatement = #"UPDATE SalaryTrans SET payment_id = (SELECT TOP 1 id FROM Payment ORDER BY Payment.id) WHERE SalaryTrans.id = #paramID ";
These two statements could not be merged as the update is going to update multiple rows. It will update all matching rows of the SalaryTrans table. So I'm using a foreach loop.
//open connection, add parameters
sqlCommand.CommandText = insertStatement;
sqlCommand.ExecuteNonQuery(); // This inserts...
foreach(PaymentInfo p in paymentList)
{
paramID.value = p.id;
sqlCommand.CommandText = updateStatement;
sqlCommand.ExecuteNonQuery();
}
In the loop each time "SELECT TOP 1 id..." is also executed. To avoid it, is there a way to use SCOPE_IDENTITY() to get the last updated ID from Payment table and use it in the loop?
Would there be a difference if I change update statement as follows in this context (performance wise) ?
DECLARE #ID INT = (SELECT TOP 1 id FROM Payment ORDER BY Payment.id)
UPDATE SalaryTrans SET payment_id = #ID WHERE SalaryTrans.id = 1
Or else should I separate this SELECT from the UPDATE to keep it outside the loop?
NOTE : My main concentration here is the performance factor.
What you can also try is, change your statement like below
var insertSatement = #"BEGIN INSERT INTO Payment (payment_type, reference, payment_date, total_records, total_amount) VALUES(#type, #reference, #date, #totalRecords, #totalAmount ); SELECT CAST(scope_identity() AS int) ";
Then in your excecute non query get the return value
sqlCommand.CommandText = insertStatement;
int id = (int) sqlCommand.ExecuteScalar(); // This inserts...
You can use the id in the loop
You can use SCOPE_IDENTITY
It will contain the latest value of the identity column from the newly inserted row
http://msdn.microsoft.com/en-us/library/ms190315.aspx
If I have the following list in C# that was loaded from the database
List<User> user = GetUsers(foo);
and it was updated and I want to store those changes in the database what's the best way of doing it using SQL? It should insert the records added to that list, updated the modified records and delete the ones that are not present in the collection.
I'm no using the EntityFramework so I need to do this using SQL.
Copy this list to datatable and set datatable RowStat as (modified,deleted,new)
and update datatable using sqldataadapter
Here's an example that adds or inserts a row. It searches for a row with a specific UserID. If the row exists, it uses update to grant the user a point. If the row does not exist, a new row is created with insert.
var connectionString = "Data Source=myServerAddress;" +
"Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;"
using (var con = new SqlConnection(connectionString))
{
con.Open();
var com = con.CreateCommand();
com.Parameters.AddWithValue("#UserId", userId);
com.CommandText = #"
if exists (select * from YourTable where UserId = #UserId)
update YourTable set TrollPoints = TrollPoints + 1 where UserId = #UserId
else
insert YourTable (UserId, TrollPoints) values (#UserId, 1)
";
com.ExecuteNonQuery();
}
The use of parameters allows the server to chache the execution plan, and also helps against SQL injection.
I'm using vb.net 2008 and ADO.NET. When using the ADO CommandBuilder and the Insert Command how can I get the newly created Key? (my Table as an Identity column and this is the key.)
Try your insert command somethign like this
insert into table_name values('first value','second value') set #id = SCOPE_IDENTITY()
And then you can set #id Parameter as below
SqlParameter IDParameter =
new SqlParameter("#id",
SqlDbType.Int);
IDParameter.Direction = ParameterDirection.Output;
insertCommand.Parameters.Add(IDParameter);
Finally you can get the value of id parameter in an int variable
int id = (int)IDParameter.Value;
Is there a way to determine whether a record was matched or not (whether the record was inserted or updated) after calling MERGE?
Ideally I'd like to output it to a parameter.
Edit:
I've got the merge statement outputting what happened in my management studio using the following statement:
Say I had the following merge statement:
MERGE INTO TestTable as target
USING ( select '00D81CB4EA0842EF9E158BB8FEC48A1E' )
AS source (Guid)
ON ( target.Guid = source.Guid )
WHEN MATCHED THEN
UPDATE SET Test_Column = NULL
WHEN NOT MATCHED THEN
INSERT (Guid, Test_Column) VALUES ('00D81CB4EA0842EF9E158BB8FEC48A1E', NULL)
OUTPUT $action;
I'm trying to use a parameter to get the '$action' output.
What you could do is create a temporary table (or a table variable) and send your output there - add some meaningful fields to your OUTPUT clause to make it clear what row was
affected by what action:
DECLARE #OutputTable TABLE (Guid UNIQUEIDENTIFIER, Action VARCHAR(100))
MERGE INTO TestTable as target
USING ( select '00D81CB4EA0842EF9E158BB8FEC48A1E' )
AS source (Guid)
ON ( target.Guid = source.Guid )
WHEN MATCHED THEN
UPDATE SET Test_Column = NULL
WHEN NOT MATCHED THEN
INSERT (Guid, Test_Column) VALUES ('00D81CB4EA0842EF9E158BB8FEC48A1E', NULL)
OUTPUT INSERTED.Guid, $action INTO #OutputTable
SELECT
Guid, Action
FROM
#OutputTable
UPDATE: ah, okay, so you want to call this from .NET ! Well, in that case, just call it using the .ExecuteReader() method on your SqlCommand object - the stuff you're outputting using OUTPUT... will be returned to the .NET caller as a result set - you can loop through that:
using(SqlCommand cmd = new SqlCommand(mergeStmt, connection))
{
connection.Open();
using(SqlDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
var outputAction = rdr.GetValue(0);
}
rdr.Close();
}
connection.Close();
}
You should get back the resulting "$action" from that data reader.