Can you specify a sub-sequence for a table? - sql-server

I've created an item history table for which I'd like to automatically increment VersionId partitioned by ItemId.
ID ItemId VersionId ItemContent Created
1 1 1 fooo 2015-02-24 12:54:00.11
2 2 1 barr 2015-02-24 12:54:15.35
3 1 2 foo 2015-02-24 12:55:00.61
4 1 3 baz 2015-02-24 12:55:45.23
5 2 2 bar 2015-02-24 12:56:00.03
Currently, that VersionId is set in a trigger. What I would like to find is something like this (I know this doesn't actually work):
create table ItemHistory
(
Id int identity(1,1) not null primary key
,ItemId int not null references Item(Id)
,VersionId int not null default row_number() over (partition by ItemId order by Id)
,ItemContent varchar(max)
,Created datetime not null default getdate()
)
While I have a working solution, I'd like to know if I'm missing some built-in functionality for handling this case.

In case you want to use my comment as the answer
Why not just do it with a view? You can have row_number() in a view.
With an index on ItemId, Id it should be very fast.
Probably less overhead than trigger.
I see you added a comment read only. Even more reason for view.

Related

Multiple OrderID for a single SQL table

Let's imagine a table below, where;
ID is the primary key and it is auto incremental column
ItemType is a foreign key
OrderID is the order number for each ItemType value
ID ItemType OrderID Col1
== ======== ======= ====
1 1 1 ABCD
2 1 2 XYZT
3 2 1 BDKL
4 1 3 XXXX
5 1 4 TYTY
6 2 2 ABCD
7 1 5 XYZZ
8 3 1 ABCD
9 3 2 ABCD
10 1 6 XYZT
11 2 3 ABCD
as you see there might be more than one ItemType that comes from another table, and each ItemType has a sequential OrderID that starts from 1 and increases by 1 for every record.
My Question is;
what is the best practice to have a column that keeps the OrderID information correctly?
Assuming that the ID values would always be increasing, such that a subsequent order's ID value would always be greater than an an earlier order's ID value, we could just use ROW_NUMBER here and not even use a column:
SELECT
ID,
ItemType,
ROW_NUMBER() OVER (PARTITION BY ItemType ORDER BY ID) OrderID,
Col1
FROM yourTable
ORDER BY
ID;
Demo
If my assumption of the ID column might not be correct always, then I suggest adding a new timestamp column which records when each order actually happened. Then, use something similar to the above approach, but order based on the order timestamp.
You do not need to do this - it will be difficult to implement and you can face some performance issues if batches of orders are created at the same time. As there is no built -in group by identity or identity over (partition by) you need to get the maximum value for each inserted type - and this should be in transaction and will be blocking others inserted.
So, just have a normal identity column to guarantee uniqueness of each order and use ROW_NUMBER to get the OrderID in incremented way by type in the presentation lair.

Create 2 table ids, the second restarts when the first increments

I have the following table:
CREATE TABLE [dbo].[CASES]
(
[CASE_ID] INT NOT NULL,
[CASE_SECTION] INT NOT NULL,
[CASE_DATA] NVARCHAR(MAX) NOT NULL,
)
I want CASE_SECTION to increment based on whether the CASE_ID has changed.
Example:
CASE_ID CASE_SECTION CASE_DATA
---------------------------------------------
1 1 'FROG ATE THE FLY'
1 2 'FROG SAT ON LOG'
2 1 'CHEETAH CHEATAXED'
3 1 'BLUE CHEESE STINKS'
Basically, I want to do something similar to using ROW_NUMBER() OVER(PARTITION BY CASE_ID) as the CASE_DATA is inserted into the table.
Is there a way I can set the table up so that CASE_SECTION increments like this by default when data is inserted?
you can use rownumber:
Select row_number() over(partition by case_id order by case_data) as case_section, * from yourtable
If you can add either an IDENTITY or InsertedDateTime column to the table, you can use that to make Case_Section a computed column that uses row_number() partitioned by case_id.
Another poster suggested this, but if you order by case_data or any other column that isn't guaranteed to be ordinal, you run the risk that the value will move around as data is inserted and changes the order of the rows.
If your computation does row_number() over(partition by case_id order by [ColumnThatIncreasesWithEachInsert]) then the values will be stable over time.

Getting only new data from SQL Server

I've run my application which is getting data from SQL Server periodically. The problem here is that I want to get the records created since the last read.
Let me show an example.
At first, (at 12:00:00)
Table
---------
orderId orderName
1 name1
2 name2
3 name3
4 name3
I'm going to select all data here.
SELECT *
FROM TABLE
After one minute, some data was added into TABLE like below,
Table
---------
orderId orderName
1 name1
2 name2
3 name3
4 name3
5 name4
6 name5
At this point, when I select the data like below,
select *
from TABLE
what I want to get is row no. 5 and row no.6, which is added after I selected before.
My idea is I need to keep an identifier which indicates the transaction of id or something like that but I still don't catch any idea... Can you help me? Any keyword or links helping me?
It would be helpful for me to implement the refresh event to get only new data with the idea I'm expecting.
Thank you guys, here's the more specific table I have.
Table
---------
orderId orderTime
1 2017-9-4 8:00:00.000
1 2017-9-4 8:00:10.000
1 2017-9-4 8:00:20.000
1 2017-9-4 8:00:30.000
1 2017-9-4 8:00:40.000
1 2017-9-4 8:00:50.000
2 2017-9-4 8:00:11.000
2 2017-9-4 8:00:20.000
2 2017-9-4 8:00:32.000
2 2017-9-4 8:00:40.000
And the time records will be added continuously based on the orderId, respectively. Most idea that I keep the last orderId may not work for my case. How do I handle it in the specific this case?
There not any keyword to identify latest entry of last execution. Because, your query run both the time on different session. So, you can't identify it.
But Basically, we have other option to do this task.
Do it with Maintaining Max value of identifier. Maintain it into the variable, Session, Parameter, etc...
select *
from table
where orderId > yourvariableValue
You need to always save somewhere the largest orderId you've got at your last select and then, knowing that orderId, use it in your select, like this:
select ...
from ...
where orderId > 4
I see a lot of vague suggestions for saving in sessions, variables etc. I suggest you just use the table itself:
Find the last key in the local table:
SELECT ISNULL(MAX(OrderID),0) FROM TABLE
Use that to decide what to select out from your remote table
DECLARE #MaxID INT
SELECT #MaxID = ISNULL(MAX(OrderID),0) FROM TABLE
INSERT INTO TABLE (OrderID, Col1, Col2)
SELECT OrderID, Col1, Col2
FROM REMOTETABLE
WHERE OrderID > #MaxID
I see you have a recent edit saying this may not work. You need to explain why otherwise no one has any chance of helping. Is it because the OrderID might not always increment? Can it go backwards? You need to explain.
Store the last orderId and the associated last orderTime in a variable.
This should work as you want.
DECLARE #lastOrderId int = 2
DECLARE #lastOrderTime datetime = '2017-9-4 8:00:40.000'
SELECT * FROM Table
WHERE (orderId = #lastOrderId AND orderTime > #lastOrderTime) OR orderId > #lastOrderId
ORDER BY orderId, orderTime;

SQL Server : recreate table in appropriate order

I've deleted some records (more precisely row 4) from a table in a SQL Server database. Now the first column goes like this (1,2,3,5) without row 4:
ID Name
------------
1 Luk
2 Sky
3 Philips
5 Andrey
How can I recreate this table and insert all data again in appropriate order?
Like this:
ID Name
--------
1 Luk
2 Sky
3 Philips
4 Andrey
EDIT:
But if i have another column (number) that is not a key, like this:
ID Number Name
------------
1 1 Luk
2 2 Sky
3 3 Philips
5 5 Andrey
Then can i recreate column Number and Name,
ID Number Name
------------
1 1 Luk
2 2 Sky
3 3 Philips
5 4 Andrey 'Can i do this, and if can HOW?
I would make a pretty strong case for never storing this number, since it is calculated, instead you could just create a view:
CREATE VIEW dbo.YourView
AS
SELECT ID,
Number = ROW_NUMBER() OVER(ORDER BY ID),
Name
FROM dbo.YourTable;
GO
This way after you have deleted rows, your view will already be in sync without having to perform any updates.
If you need to store the value, then almost the same query applies, but just placed inside a common table expression, which is then updated:
WITH CTE AS
( SELECT ID,
Number,
NewNumber = ROW_NUMBER() OVER(ORDER BY ID)
FROM dbo.YourTable
)
UPDATE CTE
SET Number = NewNumber;
You can use dbcc command
DBCC CHECKIDENT('tableName', RESEED, 0)
It would reset identity to 0.
Note it would require to truncate table first.
You can make the ID to auto increment which by default, the starting value for AUTO_INCREMENT is 1, and it will increment by 1 for each new record.
E.g MSSQL uses IDENTITY keyword to auto increment whereas MySQL uses the AUTO_INCREMENT keyword to perform an auto-increment feature.
MSSQL
ID int IDENTITY(1,1) PRIMARY KEY
MySQL
ID int NOT NULL AUTO_INCREMENT

how can i convert one row of a database to two

i have a table with the column id, itemID and locationId.
i have now split one locationId into multiple ones so i want to:
Update all records where locationId is 10 and have two rows where locationId is set to 11 and 12 (ItemId would be the same for both rows)
So to start i have:
Id ItemID LocationID
1 1 10
and i want to end up with
Id ItemID LocationID
1 1 11
1 1 12
is there any convenient way of doing this given its an update and an insert at once
Possibly there's a single statement that can do it but why wouldn't you just use transactions, a vendor-agnostic way:
begin transaction;
insert into TBL (id,itemid,locationid)
select id, itemid, 11
from TBL
where locationid = 10;
update TBL
set locationid = 12
where locationid = 10;
commit transaction;
I always tend to use standard SQL where possible so as to be able to switch between vendors easily, never mind the fact I haven't switched vendors for over a decade now :-)
Still, it's nice to have the ability even if I never use it (though sometimes I'll go vendor-specific for performance reasons if required - I don't think that'll be necessary for this particular use case since it's probably not something you'll be doing a lot of).

Resources