I am developing a simple savings account application where I am able to simulate deposit, withdrawal and transfer of money. I have a button called "Deposit" that I can click and data will be recorded in my database.
To make that insert statement I am using SQL parameters and this is the code:
SqlCon = New SqlConnection
SqlCon.ConnectionString = "............"
Try
Query = "INSERT INTO Transacoes(tpAccount, dateTransaction, descrTransaction, amoutTransaction, balanceTransaction)
VALUES(#tpAccount, #dateTransaction, #ddescrTransaction, #amoutTransaction, #balanceTransaction)"
SqlCon.Open()
SqlCmd = New SqlCommand(Query, SqlCon)
With SqlCmd.Parameters
.Add("#tpAccount", SqlDbType.Char).Value = cbTipoConta.Text
.Add("#dateTransaction", SqlDbType.DateTime).Value = txtDate.Text
.Add("#descrTransaction", SqlDbType.Char).Value = cmdDepositar.Text
.Add("#amoutTransaction", SqlDbType.Int).Value = txtDeposito.Text
.Add("#balanceTransaction", SqlDbType.Int).Value = txtBalance.Text
End With
SqlCmd.ExecuteNonQuery()
SqlCon.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
In this table I have an "ID" column but I don't want it to display on SQL parameters and shows me an error:
Cannot insert the value NULL into column 'Id'`.
I should autoincrement the Id and then this will work fine? Or what is the best way to solve this?
You should autoincrement the ID, I always use ID column with Identity(1,1) even though it is not needed at the moment. It is always nice to select specific row fast and when the ID is autoincremented, then you have only one where condition.
In order to be able to omit the ID field in your insert statement you need to set an auto increment (identity) on that field.
REF: https://technet.microsoft.com/en-gb/library/ms188263(v=sql.105).aspx
Identity is not the only solution in this case. The other one is named sequence.
In your case you can simply create a new sequence like in this example
create sequence dbo.id_sequence as int
start with 0
increment by 1;
More information about create of sequence you can find here
If you have a sequence you can use it as a defalut value for any column in table what you can see in example on point D here. You can even use more sequences to work with more than one column in a table if you want.
Difference between identinty and sequence is that you can use an identity only for one column (with sequence or even sequences you can do it with many columns in one table) and for set identity you need to recreate table (the alter is not allowed in this case) or remove column with identity and create a new one with it (and you need to be aware about constraints and relations with deleted column). With sequences you can simply alter the table in any moment with any column you need.
With sequences you can update or insert a value to a column (with identity you can't) so if you use this part of your work to simulate something it colud be a good idea to make a possibility of using original ids (if you need it of course) instead of that created by identity.
Related
Which is the better way to check if the primary key is already in use?
Dim sql As String = "Insert into Z_SKm_Funktion_Mapping (Funktion_CSV ,Funktion_Property) values('" + MappingTextbox.Text + "','" + PropertyBox.SelectedItem + "') "
Console.WriteLine(sql)
Dim connectionString As String = My.Settings.SLXADRIUMDEVConnectionString
Dim connection As New SqlConnection(connectionString)
Dim dataadapter As New SqlDataAdapter(Sql, connection)
Try
connection.Open()
dataadapter.InsertCommand = New SqlCommand(sql, connection)
dataadapter.InsertCommand.ExecuteNonQuery()
connection.Close()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
I have two solutions in mind, but I don't know if anyone of them is best.
First one: I could just delete the MsgBox statement in the Catch block.
Then it just runs through the code normally and does not insert the Statement.
Second one: I Create a Select Statement which checks if the Primary Key is already in use.
By the way: In this case Funktion_CSV is the PK
The best efficient way is that your primary key should be Auto-increment (with increment and seed value), and let SQL decide what will be the next value of insert records. To do this you can use IDENTITY column with Auto-increment PK in your table
If your code decides the PK values then there is the chance that multiple people doing the insert then conflict occurs and that's result in failure of insertion of records.
If you are very specific that your codes needs to decide PK(not recommended) value then better to Check first before insert and do this in Transaction So when multiple user try to insert a single time, then first records insert successfully but other records handled in catch block
Im writing a VB app that is scrubbing some data inside a DB2 database. In a few tables i want to update entire columns. For example an account number column. I am changing all account numbers to start at 1, and increment as I go down the list. Id like to be able to return both the old account number, and the new one so I can generate some kind of report I can reference so I dont lose the original values. Im updating columns as so:
DECLARE #accntnum INT
SET #accntnum = 0
UPDATE accounts
SET #accntnum = accntnum = #accntnum + 1
GO
Is there a way for me to return both the original accntnum and the new one in one table?
DB2 has a really nifty feature where you can select data from a "data change statement". This was tested on DB2 for Linux/Unix/Windows, but I think that it should also work on at least DB2 for z/OS.
For your numbering, you might considering creating a sequence, as well. Then your update would be something like:
CREATE SEQUENCE acct_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
CACHE 24
;
SELECT accntnum AS new_acct, old_acct
FROM FINAL TABLE (
UPDATE accounts INCLUDE(old_acct INT)
SET accntnum = NEXT VALUE FOR acct_seq, old_acct = accntnum
)
ORDER BY old_acct;
The INCLUDE part creates a new column in the resulting table with the name and the data type specified, and then you can set the value in the update statement as you would any other field.
A possible solution is to add an additional column (let's call it oldaccntnum) and assign old values to that column as you do your update.
Then drop it when you no longer need it.
Here's what I'd do:
-- create a new table to track the changes.
- with columns identifying a unique key, old-vale, new-value, timestamp
-- create a trigger on the accounts table
to write the old and new values to the new table.
But, not knowing all the conditions, it may not be worth the trouble.
I am inserting data from my vb.net application to msaccess db.
I am confused in way of getting the last inserted record added to a table. IN MS-SQL we get ##IDENTITY for that but it didn't worked for me in MSAccess.
so what should be do for getting the last inserted record added to a table?
Example:
Dim db As Database
Set db = CurrentDb
db.Execute "INSERT INTO Table1 (atext) Values('abc')", dbFailOnError
Dim rs As dao.Recordset
Set rs = db.OpenRecordset("select ##identity")
Debug.Print rs(0)
It does require that there is an autoincrement key on the table.
Here is a short example using OleDb. Notice that I create a command from the connection and then reuse that object to make my select identity call. This ensures we are in the same scope and get the identity of the record we just inserted. This has the same effect of chaining the commands together with ";", like you would want to do in other DB SQL calls to return the identity with the insert command. ExecuteScalarAsync returns the response object which we can cast to our ID type.
Dim Identity As Integer
Dim recordsAffected As Integer
Using connection As New OleDbConnection(ConnectionString)
Await connection.OpenAsync()
Using command = connection.CreateCommand()
command.CommandText = "INSERT INTO table (field) VALUES (?)"
recordsAffected = Await command.ExecuteNonQueryAsync()
' Get the ID of last inserted record
command.CommandText = "SELECT ##IDENTITY"
Identity = CInt(Await command.ExecuteScalarAsync())
End Using
connection.Close()
End Using
It's always a good practice to have a numeric (even auto-increment) primary key. Then you can always select the MAX and that's the latest inserted record.
It's more complicated in Access than SQL Server because access doesn't support the execution of multiple statements in a batch or output parameters.
According to the MSDN documentation, you need to add a handler for the RowUpdated event.
Before resorting to this, however, I would try wrapping your insert code in a transaction and then executing the select ##identity method within the transaction. Might not work, but worth a shot.
As far as I know, MS Access does not have the functionality to get the last added row.
In practice, I create an autoincrement column (which is usually the Primary Key anyway). Then I run this query when I desire to get the last row in the table:
SELECT TOP 1 * FROM [Table] ORDER BY [IdColumn] DESC
It simply sorts the the rows in the table by the ID column in reverse order and takes the first one (which is really the last row in the table).
I have a datatable comimg from code that contain set of columns (ID- primary key, and name varchar). I have my sql table that also contain same (ID- primary key, and name varchar) type of data. table has 200000+ rows. I want to compare that if sqltable id column contain same id in datatable means (datatable id column value matches with sqltable id field). If the both id is same thn it will overwrite recoed in sqltable.
Vivek Jagga
Chandigarh
My assumption is that the datatable rows all have a state of "Added", so will result in the InsertCommand being executed.
Option 1
- create a stored proc that checks whether a record with the ID already exists first. If it exists, do an UPDATE, else do an INSERT. Assign this sproc as the InsertCommand
Option 2 (assumes SQL 2005+)
- create a stored proc that tries an INSERT within a TRY block. In the CATCH block, if the error is a PK constraint error (ERROR_NUMBER() = 2627, then it means the record with that ID already exists so do an UPDATE on it. Assign this sproc as the InsertCommand
Option 3
- load all the data in the datatable in to a new table (use the SqlBulkCopy class for this). Then UPDATE records in the real table from this table where the ID already exists. Then INSERT records into the real table where they don't already exist.
Option 1 has the overhead of checking each time whether a record exists before doing anything and this could be relatively expensive over the whole activity.
Option 2 is more optimal if the majority of the time, you know that most of the records are NEW (i.e. if there's quite a few updates, then you'll have the hit of the PK errors ).
Option 3 can work and perform really well. The SqlBulkCopy class is a fast way to bulk load data into the database.
I want to duplicate a row, not the keys of course, without explicity using the field names.
Is there a SQL way or do I have to enumerate the field names through code?
I don't want to explicity use field names because I want to minimize code and db dependencies.
I am going to use it in the Ms Access 2003. I mention it in case that no standard way exists.
INSERT INTO `<table>` (column1, column2, ...) -- Not IDENTITY columns
SELECT column1, column2, ... FROM ...
This will also allow you to insert replacement values for the primary key columns, etc. I've used this, along with a common table expression, to take a set of test data from the month of February, and to pretend they're really from June.
I know you said you want to do it without the field names, but I don't think you can. It's also not a good idea, as it would tie you to the order of the columns.
If you don't have any uniques to worry about:
INSERT INTO <table> (SELECT * FROM <table> WHERE <condition>)
Otherwise, John Saunders' answer is probably your best bet.
If your primary key fields have automatic identifiers then you might well be able to script to interogate the system for fields which are not in the PK, and use the existing values for those that are not and only insert those ones (or to insert null for the PK fields).
Consequently I don't think there is going to be a "standard" way.
I'm not an Access person, but in SQL Server you can choose "Script table as --> Insert into" in SQL Server Management Studio. You can easily modify this to filter the rows you want into an INSERT INTO SELECT statement.
Perhaps something like this exists in Access?
Like folks have stated before me, you can do "INSERT INTO TBL SELECT * FROM TBL WHERE X=Y" and you will get one row. And this will fail if you have a primary key.
If you do not have a PK then you probably have bigger problems.
Is this a linked table? If so, there are no database dependencies, because you are dealing with an ODBC link. In that case, you can easily use this to get a list of columns for the table:
SELECT TOP 0 * FROM TBL (on linked tbl will need a round trip to server)
You get a blank recordset, and you just iterate through the columns.
Ms Access 2003 oriented solution
I have a form where the user can press a button to create a new version of the current record.
That part in Ms Access is easy:
DoCmd.GoToRecord , , acNewRec
Now I need to update all the fields on the form (controls are bind with table fields) except the key, ie "id" field, with data from some other record.
I came up with the below routine, which worked good for me:
Private Sub UpdateRow(tblname As String, key_name As String, key_value As String)
Dim Rst As Recordset
Dim field As field
Set DB = CurrentDb
Set Rst = DB.OpenRecordset("select * from " & tblname & " where " & _
key_name & "=" & key_value, dbOpenDynaset)
For Each field In Rst.Fields
If field.Name <> key_name Then
Form(field.Name) = field
End If
Next field
Rst.Close
Set Rst = Nothing
Set DB = Nothing
End Sub
And I use it like this:
DoCmd.GoToRecord , , acNewRec
UpdateRow "TableName", "KeyName", "some_previous_key_value"
Form.Refresh
You would need to explicitly supply the field names for the keys when you supply replacement values, therefore a 'standard' way is simply not possible.
...unless all you tables have a single key, all with the same name (ID is popular), and each key consists of a single column that has the IDENTITY (autonumber) property, in which case you would in fact have no keys at all, merely a way of using the IDENTITY value to uniquely identify your duplicate rows!