Re-structure sequence in existing SQL Server table - sql

I have a SQL Server 2016 table and it has than 10,000 rows. The Id column is a sequential id incremented by 1. But that Id is not in the correct order as shown in the screenshot below where 330 is missing. Is there any way to correct this sequence in an existing table?
I've tried like below but it's not working.
CREATE SEQUENCE contacts_seq
AS BIGINT
START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 99999
NO CYCLE
CACHE 10;

There is no point of fixing this - you are going to perform a operation which will block the access to your table and may affect your application performance.
And then, someone can delete the record X and you will be at the same position again.
Generally, the perpouse of id is to uniquely identify a row. If for some visualization reasons you do not want to have gaps you can use RANKING functions to fix this.
For example:
SELECT ROW_NUMBER () OVER (ORDER BY id) AS [ID]

Related

Using identity column gaps in SQL Server 2017

I have a few 1000 jumps in my table. I've figured out the reason, rather late I would say, which is frequent server failure and restarts and executed
set identity cache=off.
Hopefully, these large jumps will not occur. Now I want to reuse these numbers in the gaps for the new entries, what is the best way to do this? is changing the seed value is possible? Please note that I can not alter any existing data.
Also, note the rate at which new entries are added is slow (less than 10 entries daily) and I can keep an eye on this database and change the seed value again manually when necessary.
Thank you very much.
You can write a script for each instance using SET IDENTITY INSERT table_name ON and SET IDENTITY INSERT table_name OFF at the start and end of your script. The full documentation is here. You can only use it on one table at a time.
Changing the seed will have no effect as the next highest value will always be used.
The following script will help with identifying gaps.
SELECT TOP 1
id + 1
FROM mytable mo
WHERE NOT EXISTS
(
SELECT NULL
FROM mytable mi
WHERE mi.id = mo.id + 1
)
ORDER BY
id
Which is from the this question/answer
UPDATE
A possible strategy would be to take the database offline, use SET IDENTITY INSERT to fill the gaps/jumps with the required ID but otherwise minimum/empty data and then make live again. Then use the empty records until all are used and then revert to the previous method.
I don't think these numbers are important for users. but you can consider to make bulk operation for once to fix them. Don't try to insert in between them
setting identity insert on and of for table level changes structure of your table and it is not transaction safe.
you need to write TSQL script to alter your base table and dependent table at the same time

How to change db sequence start value

My requirement is as follows.
(a) I have already sequence created and one table is (lets assume employee having id,name..etc).
(b) Some how my sequence get corrupted and currently current value of sequence is not sync with the max value of id column of employee table.
now i want to reset my sequence to the max value of the id column of employee table. i know we can do it easily by using PL/SQL,Stored procedure. but i want to write plain query which will do following tasks.
1- Fetch max value of id and current value of my sequence .Take a difference and add that difference to the sequence by using increment by.( here my current value of sequence is lesser than max id value of id column)
You change the values of a sequence with the 'ALTER SEQUENCE' command.
To restart the sequence with a new base value, you need to drop and recreate it.
I do not think you can do this with a straightforward SELECT query.
Here is the Oracle 10g documentation for ALTER SEQUENCE.
You can't change the increment from plain SQL as alter sequence is DDL, so you need to increment it multiple times, one by one. This would increment the sequence as many times as the highest ID you currently have:
select your_sequence.nextval
from (
select max(id) as max_id
from your_table
) t
connect by level < t.max_id;
SQL Fiddle demo (fudged a bit as the sequence isn't reset if the schema is cached).
If you have a high value though that might be inefficient, though as a one-off adjustment that probably doesn't matter. You can't refer to the current sequence value in a subquery or CTE, but you could look at the USER_SEQUNECES view to get a rough guide of how far out you are to begin with, and reduce the number of calls to within double the case size (depending on how many waiting values the cache holds):
select your_sequence.nextval
from (
select max(id) as max_id
from your_table
) t
connect by level <= (
select t.max_id + us.cache_size + 1 - us.last_number
from user_sequences us
where sequence_name = 'YOUR_SEQUENCE'
);
SQL Fiddle.
With low existing ID values the second one might do more work, but with higher values you can see the second comes into its own a bit.

Implement a ring buffer

We have a table logging data. It is logging at say 15K rows per second.
Question: How would we limit the table size to the 1bn newest rows?
i.e. once 1bn rows is reached, it becomes a ring buffer, deleting the oldest row when adding the newest.
Triggers might load the system too much. Here's a trigger example on SO.
We are already using a bunch of tweaks to keep the speed up (such as stored procedures, Table Parameters etc).
Edit (8 years on) :
My recent question/answer here addresses a similar issue using a time series database.
Unless there is something magic about 1 billion, I think you should consider other approaches.
The first that comes to mind is partitioning the data. Say, put one hour's worth of data into each partition. This will result in about 15,000*60*60 = 54 million records in a partition. About every 20 hours, you can remove a partition.
One big advantage of partitioning is that the insert performance should work well and you don't have to delete individual records. There can be additional overheads depending on the query load, indexes, and other factors. But, with no additional indexes and a query load that is primarily inserts, it should solve your problem better than trying to delete 15,000 records each second along with the inserts.
I don't have a complete answer but hopefully some ideas to help you get started.
I would add some sort of numeric column to the table. This value would increment by 1 until it reached the number of rows you wanted to keep. At that point the procedure would switch to update statements, overwriting the previous row instead of inserting new ones. You obviously won't be able to use this column to determine the order of the rows, so if you don't already I would also add a timestamp column so you can order them chronologically later.
In order to coordinate the counter value across transactions you could use a sequence, then perform a modulo division to get the counter value.
In order to handle any gaps in the table (e.g. someone deleted some of the rows) you may want to use a merge statement. This should perform an insert if the row is missing or an update if it exists.
Hope this helps.
Here's my suggestion:
Pre-populate the table with 1,000,000,000 rows, including a row number as the primary key.
Instead of inserting new rows, have the logger keep a counter variable that increments each time, and update the appropriate row according to the row number.
This is actually what you would do with a ring buffer in other contexts. You wouldn't keep allocating memory and deleting; you'd just overwrite the same array over and over.
Update: the update doesn't actually change the data in place, as I thought it did. So this may not be efficient.
Just an idea that is to complicated to write in a comment.
Create a few log tables, 3 as an example, Log1, Log2, Log3
CREATE TABLE Log1 (
Id int NOT NULL
CHECK (Id BETWEEN 0 AND 9)
,Message varchar(10) NOT NULL
,CONSTRAINT [PK_Log1] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)
CREATE TABLE Log2 (
Id int NOT NULL
CHECK (Id BETWEEN 10 AND 19)
,Message varchar(10) NOT NULL
,CONSTRAINT [PK_Log2] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)
CREATE TABLE Log3 (
Id int NOT NULL
CHECK (Id BETWEEN 20 AND 29)
,Message varchar(10) NOT NULL
,CONSTRAINT [PK_Log3] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
)
Then create a partitioned view
CREATE VIEW LogView AS (
SELECT * FROM Log1
UNION ALL
SELECT * FROM Log2
UNION ALL
SELECT * FROM Log3
)
If you are on SQL2012 you can use a sequence
CREATE SEQUENCE LogSequence AS int
START WITH 0
INCREMENT BY 1
MINVALUE 0
MAXVALUE 29
CYCLE
;
And then start to insert values
INSERT INTO LogView (Id, Message)
SELECT NEXT VALUE FOR LogSequence
,'SomeMessage'
Now you just have to truncate the logtables on some kind of schedule
If you don't have sql2012 you need to create the sequence some other way
I'm looking for something similar myself (using a table as a circular buffer) but it seems like a simpler approach (for me) will be just to periodically delete old entries (e.g. the lowest IDs or lowest create/lastmodified datetimes or entries over a certain age). It's not a circular buffer but perhaps it is a close enough approximation for some. ;)

oracle sql query requirements

I have some data in oracle table abot 10,000 rows i want to genrate column which return 1 for ist row and 2 for second and so on 1 for 3rd and 2 for 4th and 1 for 5th and 2 for 6th and so on..Is there any way that i can do it using sql query or any script which can update my column like this.that it will generate 1,2 as i mentioned above i have thought much but i didn't got to do this using sql or any other scencrio for my requirements.plz help if any possibility for doing this with my table data
You can use the combination of the ROWNUM and MOD functions.
Your query would look something like this:
SELECT ROWNUM, 2 - MOD(ROWNUM, 2) FROM ...
The MOD function will return 0 for even rows and 1 for odd rows.
select mod(rownum,5)+1,fld1, fld2, fld3 from mytable;
Edit:
I did not misunderstand requirements, I worked around them. Adding a column and then updating a table that way is a bad design idea. Tables are seldom completely static, even rule and validation tables. The only time this might make any sense is if the table is locked against delete, insert, and update. Any change to any existing row can alter the logical order. Which was never specified. Delete means the entire sequence has to be rewritten. Update and insert can have the same effect.
And if you wanted to do this you can use a sequence to insert a bogus counter. A sequence that cycles over and over, assuming you know the order and can control inserts and updates in terms of that order.

SQL Lite blank row id even after deleting the row

I have a SQLite DB file lets say a.db. And I have 100 rows in table a. When I give
SELECT * FROM a WHERE rowid BETWEEN 1 AND 100
it gives me the first 100 results. Now if I delete the first 2 rows from the table and run the
SELECT * FROM a WHERE rowid BETWEEN 1 AND 100
it gives me only 98 rows. And when I give the query
SELECT * FROM a WHERE rowid = 1
it gives me an empty row. The database doesn't seem to rearrange the rowid.
Please help.. Is there any way to force the SQLite to rearrange the row ids ?
In SQLite, rowid is just an int column with autoincremented values. The only thing you're guaranteed is that each rowid will be unique to that table -- nothing more. You aren't guaranteed that rowids will be sequential, and you aren't even guaranteed that every number will be used! For example, if an INSERT fails, the rowid used in that failed insert will probably be skipped and never used again (if the autoincrement keyword is explicitly used -- otherwise, if a row is deleted, its rowid is free to be reused by any newly inserted data.)
If you want rowids to be sequential and autoupdated, you'll have to create your own version of the rowid column and keep it updated with triggers.
I found out the answer. We need to run the Vacuum query after every delete. This will rearrange all the rowindex and remove the dead rows.
http://sqlite.org/lang_vacuum.html