Delete the last insert record with the same values - sql

I have the following records inside a table:
User Product Quantity
A Test 1 5
A Test 1 3
B Test 1 4
B Test 2 1
When I run 'DELETE FROM Sample WHERE User='A' AND Product='Test 1', I want to delete the last inserted record:
User Product Quantity
A Test 1 5
B Test 1 4
B Test 2 1
Is this possible? Please advise.

Here's a working sql fiddle based on my comments.
Note that in the fiddle example I added an id and last_edited columns. I use GetDate() to fill the date time but add successive days( getdate() + 1..n ) to force unique date times...
The answer isn't the smoothest but demonstrates what I was talking about in the comments, and is correct. By the way, you didn't specify the version of SQL Server but if it's 2012 you should use the new, higher-precision date time type and also add a unique index on the column since your date times need to be unique identifiers in this scenario. Do you use the surrogate id though!
Repeating comments here:
What does "last" mean in your table? Without a date time column you cannot deterministically calculate which record was temporally placed last in the table. There is no internal metadata, in SQL Server at least, that would give you such info... I would also suggest using a surrogate primary key since none of your values are unique.

Related

Oracle Enforce Uniqueness

I need to enforce uniqueness on specific data in a table (~10 million rows). This example data illustrates the rule -
For code=X the part# cannot be duplicate. For any other code there can be duplicate part#. e.g ID 8 row can't be there but ID 6 row is fine. There are several different codes in the table and part# but uniqueness is desired only for one code=X.
ID CODE PART#
1 A R0P98
2 X R9P01
3 A R0P98
4 A R0P44
5 X R0P44
6 A R0P98
7 X T0P66
8 X T0P66
The only way I see is to create a trigger on the table and check for PART# for code=X before insert or update. However, I fear this solution may slow down inserts and updates on this table.
Appreciate your help!
In Oracle, you can create a unique index on an expression for this:
create unique index myidx
on mytable (case when code = 'X' then part# end);

SQL Query to add timestamp

I have a Table in our ERP system that tracks the status of shop orders. It has the open date (column name ORGDUE_10) and Status column (STATUS_10) which has codes 1-6, and status 3 is an open order, status 4 is closed (the rest of the codes do not matter for this application). Unfortunately, this table does not have a timestamp column where I can get the date when the order is closed. I need to determine if multiple Shop Orders were closed (STATUS_10 changed from 3 to 4) on time or if they went past the due date (ORGDUE_10).
Any ideas how I could do a query that will accomplish this? I assume I need a another table – write the data to it and then some kind of trigger?
I am using VS2015. The Table Name that I cannot edit is Order_Master
STATUS_10 ORDNUM_10 PRTNUM_10 CURDUE_10
4 | 50015246 |ASY5670 | 9/4/2017
3 | 50016983 |ASY5699 | 5/15/2017
I figured it out (I think). Here is the code I used which seems to do the trick. this code will update, insert, and conditionally timestamp (datestamp) two different tables on two different servers. I hope this makes sense and helps someone else. I appreciate the help given #Jonathan Leffler, sorry I didn't make it easy on you.
MERGE server2.dbo.table2 AS target /* the added server.dbo is in the event the two tables are
on different sql servers*/
USING server1.dbo.table1 AS source ON (target.column-t = source.column-s) /*
column-t is the target column and column-s is the matching source column */
WHEN MATCHED AND (conditional column) AND (antoher conditional column) THEN
UPDATE SET
column-t = source.column-s, column-t (for datestamp) = (GETDATE())
WHEN NOT MATCHED AND (conditional column) AND (antoher conditional
column)THEN /* you cannot use a WHERE clause in a MERGE but you can set
up similar conditions in the WHEN statements */
INSERT (target columns)
VALUES (source columns in same order as target columns);

Return rows in the exact order they were inserted

I have a simple join table with two id columns in SQL Server.
Is there any way to select all rows in the exact order they were inserted?
If I try to make a SELECT *, even if I don't specify an ORDER BY clause, the rows are not being returned in the order they were inserted, but ordered by the first key column.
I know it's a weird question, but this table is very big and I need to check exactly when a strange behavior has begun, and unfortunately I don't have a timestamp column in my table.
UPDATE #1
I'll try to explain why I'm saying that the rows are not returned in 'natural' order when I SELECT * FROM table without an ORDER BY clause.
My table was something like this:
id1 id2
---------------
1 1
2 2
3 3
4 4
5 5
5 6
... and so on, with about 90.000+ rows
Now, I don't know why (probably a software bug inserted these rows), but my table have 4.5 million rows and looks like this:
id1 id2
---------------
1 1
1 35986
1 44775
1 60816
1 62998
1 67514
1 67517
1 67701
1 67837
...
1 75657 (100+ "strange" rows)
2 2
2 35986
2 44775
2 60816
2 62998
2 67514
2 67517
2 67701
2 67837
...
2 75657 (100+ "strange" rows)
Crazy, my table have now millions of rows. I have to take a look when this happened (when the rows where inserted) because I have to delete them, but I can't just delete using *WHERE id2 IN (strange_ids)* because there are "right" id1 columns that belongs to these id2 columns, and I can't delete them, so I'm trying to see when exactly these rows were inserted to delete them.
When I SELECT * FROM table, it returns me ordered by id1, like the above table, and
the rows were not inserted in this order in my table. I think my table is not corrupted because is the second time that this strange behavior happens the same way, but now I have so many rows that I can delete manually like it was on 1st time. Why the rows are not being returned in the order they were inserted? These "strange rows" were definetely inserted yesterday and should be returned near the end of my table if I do a SELECT * without an ORDER BY, isn't it?
A select query with no order by does not retrieve the rows in any particular order. You have to have an order by to get an order.
SQL Server does not have any default method for retrieving by insert order. You can do it, if you have the information in the row. The best way is a primary key identity column:
TableId int identity(1, 1) not null primary key
Such a column is incremented as each row is inserted.
You can also have a CreatedAt column:
CreatedAt datetime default getdate()
However, this could have duplicates for simultaneous inserts.
The key point, though, is that a select with no order by clause returns an unordered set of rows.
As others have already written, you will not be able to get the rows out of the link table in the order they were inserted.
If there is some sort of internal ordering of the rows in one or both of the tables that this link table is joining, then you can use that to try to figure out when the link table rows have been created. Basically, they cannot have been created BEFORE both of the rows containing the PK:s have been created.
But on the other hand you will not be able to find out how long after they have been created.
If you have decent backups, you could try to restore one or a few backups of varying age and then try to see if those backups also contains this strange behaviour. It could give you at least some clue about when the strangeness has started.
But the bottom line is that using just a select, there is now way to get the row out of a table like this in the order they were inserted.
If SELECT * doesn't return them in 'natural' order and you didn't insert them with a timestamp or auto-incrementing ID then I believe you're sunk. If you've got an IDENTITY field, order by that.
But the question I have is, how can you tell that SELECT * isn't returning them in the order they were inserted?
Update:
Based on your update, it looks like there is no method by which to return records as you wish, I'd guess you've got a clustered index on ID1?
Select *, %%physloc%% as pl from table
order by pl desc

T-SQL(MSSQL 2005)Reorder Scope_identity

Have a small table of 2 columns on MSSQL Server 2005 which contains a lot of information let's say about 1 billion records and it is constantly being written into.
Definition of the table is :
Create table Test(
id int identity(1,1) primary key ,
name varchar(30) )
Te PK is int which I choose it over uniqueidentifier for a number of reasons. The problem comes with the auto increment I want to reorganize the 'id' every time a row is deleted. The objective to this is leaving no gaps. The table is active and a lot of rows are written into it, so dropping a column is not an option also locking the table for a long time.
Quick example of what I want to accomplish:
I have this :
id | name
----+-------
1 | Roy
2 | Boss
5 | Jane
7 | Janet
I want to reorganize it so it will look like this :
id | name
----+-------
1 | Roy
2 | Boss
3 | Jane
4 | Janet
I am aware of DBCC CHECKIDENT (TableName, RESEED, position) but I am not sure it will benefit my case, because my table is big and it will take a lot of time to reposition also if I am not mistaken it will lock the table for a very long time. This table is not used by any other table. But if you like you can submit a suggestion to the same problem having in mind that the table is used by other tables.
EDIT 1 :
The objective is to prove that the rows follow each other in case a row is deleted so I can see it is deleted and reinstate it.I was thinking of adding a third column that will contain a hash value from the row above , and if the row above is deleted I would know that I have a gap and need to restore it ,in that case the order will not matter because I can compare the has codes and see if they match , so I can see which row follows which.But still I wonder is there a more clever and safer way of doing this ?Maybe involve something else rather then hash codes , some other way of proving that the rows follow each other , or that the new row contains parts of the previous row?
EDIT 2 :
I'll try to explain it one more time if I can't well then I don't want to waste anyone's time.
In the perfect case scenario there will be nothing missing from this table , but due to
server errors some data maybe deleted or some of my associates might be wasteful and delete it by fault.
I have logs and can recover that data, but I want to prove that the records are sequenced , that they follow
each other even if there is a server error and some of them are deleted but later on reinstated.
Is there a way to do this ?
Example:
well let's say that 7 is deleted and after that reinstated as 23 , how would you prove that 23 is 7, meaning that 23 came after 6 and before 8 ?
I would suggest not worrying about trying to reseed your Identity column -- let SQL Server maintain it's uniqueness for each row.
Generally this is wanted for presentation logic instead, in which case, you could use the ROW_NUMBER() analytic function:
SELECT Row_Number() Over (Order By Id) NewId,
Id, Name
FROM YourTable
I agree with others that this shouldn't typically be done, but if you absolutely want to do it you can utilize the quirky update to get it done quickly, should be something like this:
DECLARE #prev_id INT = 0
UPDATE Test
SELECT id = CASE WHEN id - #prev_id = 1 THEN id
ELSE #prev_id + 1
END
,#prev_id = id
FROM test
You should read about the limitations of quirky update, primarily the conditions that must be met to ensure consistent output. This is a good article but they annoyingly have you sign in, but you can find other resources: http://www.sqlservercentral.com/articles/T-SQL/68467/
Edit: Actually, in this case I think you could just use:
DECLARE #prev_id INT = 0
UPDATE Test
SELECT id = #prev_id + 1
,#prev_id = id
FROM Test
The way to do it is to not implement your proposed fix.
Leave the identity alone.
If identity 7 is deleted you know it is just after 6 and and just before 8.
If you need them to stay in the same order then simple.
Place unique constraint on name.
Don't delete the record.
Just add a bool column for active.

Copy data from one field to another on every row

So I've got:
id number
1 0
2 0
3 0
Is there a sql statement to copy everything from id into number?
I'm about to write a php scrip to select, then update every row. My SQL knowledge is pretty basic, but I'm sure there's a smart guy way to to do this:
Background: The id used to be a number that was displayed in the app and was unique. That number is no longer unique with some new features I'm adding--so I need to move it to a field that isn't unique while maintaining the integrity of the old.
You can use an update statement and reference the columns. Just do the following:
update mytable set number = id
That sets number equal to id on each row. Enjoy!