简体   繁体   中英

What's the best way to store a computed column that maintains a sorting index in SQL Server?

So let's say I've got a table called [transactions] with an identity column as the primary key, a date field, and some other columns. I want to include a persistent column that is computed or somehow calculated which will effectively store the "sort order." This cannot simply be the ID column, however, because I'm sorting by date, and sometimes you might add a value retroactively.

So for example, if the table started out looking like this:

+-----+------------+---------+--------+--------+
| id  |    date    | account | amount | (sort) |
+-----+------------+---------+--------+--------+
|   1 | 2014-05-22 |      7  | 100.00 |    1   |
|   2 | 2014-05-29 |      7  |  45.25 |    2   |
|   3 | 2014-06-03 |      8  |  99.00 |    3   |
+-----+------------+---------+--------+--------+

Then, if I ran this statement:

INSERT INTO [transactions] ([date], [account], [amount]) 
VALUES ('2014-05-27', 8, 88.50);

I would want the sort column to be smart enough so that the table would then look like this:

+-----+------------+---------+--------+--------+
| id  |    date    | account | amount | (sort) |
+-----+------------+---------+--------+--------+
|   1 | 2014-05-22 |      7  | 100.00 |    1   |
|   2 | 2014-05-29 |      7  |  45.25 |    3   |
|   3 | 2014-06-03 |      8  |  99.00 |    4   |
|   4 | 2014-05-27 |      8  |  88.50 |    2   |
+-----+------------+---------+--------+--------+

Ideally, I'd like this column to persist as an actual column. What's the best way to accomplish this?

You can just calculate the value when you need it:

select t.*, row_number() over (order by [date]) as [sort]
from transactions t;

Alternatively, just use [date] for order by . I don't see why another column is necessary.

EDIT:

If you want to keep the column sort in order, then you are going to need a trigger. And, the trigger will not be cheap. The logic in the trigger would be essentially:

update transactions
    set sort = sort + 1
    where [date] > NEWDATE;

insert into transactions( . . . , [sort])
    select . . . , coalesce(max([sort])) + 1
    from transactions
    where [date] < NEWDATE;

(I'm leaving out all the stuff involved with defining a trigger.)

Although the insert can be made quite efficient with an index, this does affect the performance of the update , which has to affect every row with a larger date. If you are almost always inserting rows with a newer date, this might be a reasonable trade-off.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM