how to insert or update if there is already a record? - sql

My table has two columns: Amount and Date
When I am adding new values, I want to update the amount if there is already a record with that date. If there is not, I want to just insert my new values.

something like:
if exists(select * from table where date = #date)
update table set amount = #amount where date = #date
else
insert table (amount, date) select #amount, date

Assuming you have at least SQL Server 2008, you could use the MERGE keyword. This keyword was added specifically for cases like yours. You specify a MERGE clause (basically a join) and then statements telling it how to handle when it does or doesn't find a match.
There's a decent example at the bottom that shows merging between a target table and a source "table" created out of a single row of parameters. To boil it down a bit, you could use something like:
MERGE [TargetTable] AS target -- This is the table we'll be updating
USING (SELECT #Date) AS source (Date) -- These are the new values
ON (target.Date = source.Date) -- Here we define how we find a "match"
WHEN MATCHED THEN -- If the date already exists:
UPDATE SET Amount = #Amount
WHEN NOT MATCHED THEN -- If the date does not already exist:
INSERT (Date, Amount) VALUES (#Date, Amount)
Note that the nested UPDATE and INSERT clauses do not specify a table. That is because we already told SQL Server which table to perform those actions on when we defined our target table (the table specified right after the MERGE keyword).
Update: This functionality is apparently not supported by SQL Server CE, so it will not work in your specific case. I am leaving this answer here as it may help others attempting to do something similar in the full version of SQL Server. For the SQL Server CE solution, check out BJury's answer.

As an alternative to IF .. NOT EXISTS, you could assert an UPDATE, and fall back on an insert. This is usually quite a performant UPSERT pattern if data generally does exist already.
UPDATE MyTable
SET Amount = #NewAmount
WHERE Date = #Date;
IF ##ROWCOUNT = 0
INSERT INTO MyTable(Amount, Date) VALUES (#NewAmount, #Date);

If you are using nhibernate ORM, then you can use SaveOrUpdate session method.

Related

Delete new record if same data exists

I want to delete new record if the same record created before.
My columns are date, time and MsgLog. If date and time are same, I want to delete new one.
I need help .
You can check in the table whether that value exists or not in the column using a query. If it exists, you can show message that a record already exists.
To prevent such kind of erroneous additions you can add restriction to your table to ensure unique #Date #Time pairs; if you don't want to change data structure (e.g. you want to add records with such restrictions once or twice) you can exploit insert select counstruction.
-- MS SQL version, check your DBMS
insert into MyTable(
Date,
Time,
MsgLog)
select #Date,
#Time,
#MsgLog
where not exists(
select 1
from MyTable
where (#Date = Date) and
(#Time = Time)
)
P.S. want to delete new one equals to do not insert new one
You should create a unique constraint in the DB level to avoid invalid data no matter who writes to your DB.
It's always important to have your schema well defined. That way you're safe that no matter how many apps are using your DB or even in case someone just writes some inserts manually.
I don't know which DB are you using but in MySQL can use to following DDL
alter table MY_TABLE add unique index(date, time);
And in Oracle you can :
alter table MY_TABLE ADD CONSTRAINT constaint_name UNIQUE (date, time);
That said, you can also (not instead of) do some checks before inserting new values to avoid dealing with exceptions or to improve performance by avoiding making unnecessary access to your DB (length \ nulls for example could easily be dealt with in the application level).
You can avoid deleting by checking for duplicate while inserting.
Just modify your insert procedure like this, so no duplicates will entered.
declare #intCount as int;
select #intCount =count(MsgLog) where (date=#date) and (time =#time )
if #intCount=0
begin
'insert procedure
end
> Edited
since what you wanted is you need to delete the duplicate entries after your bulk insert. Think about this logic,
create a temporary table
Insert LogId,date,time from your table to the temp table order by date,time
now declare four variables, #preTime,#PreDate,#CurrTime,#CurrDate
Loop for each items in temp table, like this
while
begin
#pkLogID= ' Get LogID for the current row
select #currTime=time,#currDate=date from tblTemp where pkLogId=#pkLogID 'Assign Current values
'Delete condition check
if (#currDate=#preDate) and (#currTime=#preTime)
begin
delete from MAINTABLE where pkLogId=#pkLogID
end
select #preDate=#currDate,#preTime=#currTime 'Assign current values as preValues for next entries
end
The above strategy is we sorted all entries according to date and time, so duplicates will come closer, and we started to compare each entry with its previous, when match found we deleting the duplicate entry.

SQL SELECT or INSERT INTO query

I'm working with SQL Server 2000. I need to take the results from one column (VALIMIT) and insert them into another column (VALIMIT2012) in the same table (lending_limits).
My question is do I need to do a SELECT query first, or do I just start with an INSERT INTO query and what the proper syntax would be for the INSERT INTO query.
You can do this with an UPDATE statement:
update lending_limits
set VALIMIT2012 = VALIMIT
Neither. You don't insert columns, you insert rows, so what you want is an update:
update SomeTable
set VALIMIT2012 = VALIMIT
Note: It looks like you have one column per year, which is bad database design. If you have different data for each year, you should put that in a separate table, so that you get the year as data, not part of the column name.
UPDATE TableName SET VALIMIT2012 = VALIMIT

Delete and Insert or Select and Update

We have a status table. When the status changes we currently delete the old record and insert a new.
We are wondering if it would be faster to do a select to check if it exists followed by an insert or update.
Although similar to the following question, it is not the same, since we are changing individual records and the other question was doing a total table refresh.
DELETE, INSERT vs UPDATE || INSERT
Since you're talking SQL Server 2008, have you considered MERGE? It's a single statement that allows you to do an update or insert:
create table T1 (
ID int not null,
Val1 varchar(10) not null
)
go
insert into T1 (ID,Val1)
select 1,'abc'
go
merge into T1
using (select 1 as ID,'def' as Val1) upd on T1.ID = upd.ID --<-- These identify the row you want to update/insert and the new value you want to set. They could be #parameters
when matched then update set Val1 = upd.Val1
when not matched then insert (ID,Val1) values (upd.ID,upd.Val1);
What about INSERT ... ON DUPLICATE KEY? First doing a select to check if a record exists and checking in your program the result of that creates a race condition. That might not be important in your case if there is only a single instance of the program however.
INSERT INTO users (username, email) VALUES ('Jo', 'jo#email.com')
ON DUPLICATE KEY UPDATE email = 'jo#email.com'
You can use ##ROWCOUNT and perform UPDATE. If it was 0 rows affected - then perform INSERT after, nothing otherwise.
Your suggestion would mean always two instructions for each status change. The usual way is to do an UPDATE and then check if the operation changed any rows (Most databases have a variable like ROWCOUNT which should be greater than 0 if something changed). If it didn't, do an INSERT.
Search for UPSERT for find patterns for your specific DBMS
Personally, I think the UPDATE method is the best. Instead of doing a SELECT first to check if a record already exists, you can first attempt an UPDATE but if no rows are affected (using ##ROWCOUNT) you can do an INSERT.
The reason for this is that sooner or later you might want to track status changes, and the best way to do this would be to keep an audit trail of all changes using a trigger on the status table.

Prevent inserting overlapping date ranges using a SQL trigger

I have a table that simplified looks like this:
create table Test
(
ValidFrom date not null,
ValidTo date not null,
check (ValidTo > ValidFrom)
)
I would like to write a trigger that prevents inserting values that overlap an existing date range. I've written a trigger that looks like this:
create trigger Trigger_Test
on Test
for insert
as
begin
if exists(
select *
from Test t
join inserted i
on ((i.ValidTo >= t.ValidFrom) and (i.ValidFrom <= t.ValidTo))
)
begin
raiserror (N'Overlapping range.', 16, 1);
rollback transaction;
return
end;
end
But it doesn't work, since my newly inserted record is part of both tables Test and inserted while inside a trigger. So the new record in inserted table is always joined to itself in the Test table. Trigger will always revert transation.
I can't distinguish new records from existing ones. So if I'd exclude same date ranges I would be able to insert multiple exactly-same ranges in the table.
The main question is
Is it possible to write a trigger that would work as expected without adding an additional identity column to my Test table that I could use to exclude newly inserted records from my exists() statement like:
create trigger Trigger_Test
on Test
for insert
as
begin
if exists(
select *
from Test t
join inserted i
on (
i.ID <> t.ID and /* exclude myself out */
i.ValidTo >= t.ValidFrom and i.ValidFrom <=t.ValidTo
)
)
begin
raiserror (N'Overlapping range.', 16, 1);
rollback transaction;
return
end;
end
Important: If impossible without identity is the only answer, I welcome you to present it along with a reasonable explanation why.
I know this is already answered, but I tackled this problem recently and came up with something that works (and performs well doing a singleton seek for each inserted row). See the example in this article:
http://michaeljswart.com/2011/06/enforcing-business-rules-vs-avoiding-triggers-which-is-better/
(and it doesn't make use of an identity column)
Two minor changes and everything should work just fine.
First, add a where clause to your trigger to exclude the duplicate records from the join. Then you won't be comparing the inserted records to themselves:
select *
from testdatetrigger t
join inserted i
on ((i.ValidTo >= t.ValidFrom) and (i.ValidFrom <= t.ValidTo))
Where not (i.ValidTo=t.Validto and i.ValidFrom=t.ValidFrom)
Except, this would allow for exact duplicate ranges, so you will have to add a unique constraint across the two columns. Actually, you may want a unique constraint on each column, since any two ranges that start (or finish) on the same day are by default overlapping.

SQL Server 2000 Function for record created datetime

I was given a task to display when a record in the database was added, however the previous developers never made a field for this, and I can't go back and make up dates for all the existing records. Is there an easy way to extract out a record Creation date from a SQL server 2000 query.
SELECT RECORD_CREATED_DATE FROM tblSomething WHERE idField = 1
The RECORD_CREATED_DATE isn't a field in the existing table. Is there some sort of SQL Function to get this information ?
If it's not stored as a field, the info is lost after the transaction log recycles (typically daily), and maybe even sooner.
No, unfortunately date of insert or last update are not automatically stored with each record.
To do that, you need to create two datetime columns in your table (e.g. CreatedOn, UpdatedOn) and then in an INSERT trigger set the CreatedOn = getdate() and in the UPDATE trigger set the UpdatedOn = getdate().
CREATE TRIGGER tgr_tblMain_Insert
ON dbo.tblMain
AFTER INSERT
AS
BEGIN
set nocount on
update dbo.tblMain
set CreatedOn = getdate(),
CreatedBy = session_user
where tblMain.ID = INSERTED.ID
END
I also like to create CreatedBy and UpdatedBy varchar(20) columns which I set to session_user or update through other methods.
I would start with putting this information in from now on. Create two columns, InsertedDate, LastUpdatedDate. Use a default value of getdate() on the first and an update trigger to populate the second (might want to consider UpdatedBy as well). Then I would write a query to display the information using the CASE Statement to display the date if there is one and to display "Unknown" is the field is null. This gets more complicated if you need to store a record of all the updates. Then you need to use audit tables.
I'm not aware of a way you can get this information for existing records. However, going forward you can create an audit table that stores the TableName and RecordCreateDate (or something similar.
Then, for the relevant tables you can make an insert trigger:
CREATE TRIGGER trigger_RecordInsertDate
ON YourTableName
AFTER INSERT
AS
BEGIN
-- T-SQL code for inserting a record and timestamp
-- to the audit table goes here
END
create another column and give it a default of getdate() that will take care of inserted date, for updated date you will need to write an update trigger