MS SQL查找上一条记录的值

时间:2014-08-04 14:44:38

标签: sql sql-server

仍然让我的头脑加入这样的事情。

这是我的问题......

我们有一个表格,其中包含有关特定"昵称"的大量信息,这是在我们销售产品时输入的。遗憾的是,除了昵称之外,没有办法将记录与相同的昵称绑在一起。

每行中的一个值是产品售出时的货架编号。

我们之前没有使用过这些信息,但现在我们想要添加一个新行,其中还包括产品上次售出时的货架编号。

这对于新记录来说不是一个大问题,因为我使用ASP来添加记录,并且可以轻松地进行最后一次记录更新以获取值。

问题是我们想要超过220,000条记录并执行相同的操作,虽然我已经在ASP中编写了一个脚本来执行此操作...即使我已经将脚本分解为运行,它也会永远运行一次销售一天(ASP Classic)。

所以我很想知道在Microsoft SQL Server 12上是否存在SQL等价物。

新纪录|昵称|架子|最后一个架子

2152 | '老橘子' | 10 | 9

您知道每条记录都有唯一的ID和日期戳。

问题进一步复杂化,因为有时产品不会在销售期间出售,因此最后一条记录可能包含空值而非数字。在这种情况下,我想忽略这个记录,如果有一个记录,那就转到那个记录。

如果你能提供帮助,谢谢你。

MALC

1 个答案:

答案 0 :(得分:0)

修改

更改此答案以提供触发器和示例更新,以设置现有数据的最后一个数据库。已修改SQL以添加此内容。


我能想到的最简单的解决方案是使用插入触发器。这是一个可以在非生产SQL服务器上运行的测试脚本。我在触发器中使用了一些代码,这些代码适用于MS SQL Server 2005或更高版本(用于分区的' over'子句)。我在SQL 2008上测试过它,但没有在任何其他版本或SQLexpress上测试过。

我在datestamp列中添加了,因为需要知道哪条记录是最新的。

触发器中的逻辑是排除新记录,并查找具有最新日期戳和最高ID的项目。如果同一昵称的两个项目存在于同一日期,则它使用id最高的值。它排除任何货架为空的项目。

在表格中,我还添加了一个名为' expected'存储我期望LastShelf列包含该行的内容。在我的测试中,他们都匹配。

可能出现的问题

如果在具有相同昵称的多个项目的单个SQL语句中进行批量插入,则LastShelf将来自现有数据,并且不会获取插入数据中的任何Shelf值。也许某种SQL专家可以建议重写我的insert语句来解决这个问题吗?

希望这会有所帮助..

-- Create a demo database (
use master;
go

create database [Demo_Trigger];
go

use Demo_Trigger;

-- Create the table we want to test
create table Items 
    (ID int not null identity primary key,  -- primary key
     datestamp datetime not null,           -- timestamp of record (to find last entry)
     nickname nvarchar(64) not null,        -- nickname
     shelf int null,                        -- shelf (can be null)
     lastShelf int null,                    -- last shelf
     expected int null);                    -- for testing/demo - what we expect result to be!

GO

-- Create an insert trigger 
create trigger Items_InsertSetLastShelf
on Items after Insert as
BEGIN
  SET NOCOUNT ON;

  -- determine unique list of nicknames being inserted 
  update Items
  Set LastShelf = tmp.Shelf
  from Items, 
  (
    select nickname, shelf from 
    (
        select id, nickname, datestamp, shelf,
            MAX(datestamp) over (partition by nickname) maxDate, -- get latest by date
            MAX(id) over (partition by nickname) maxID           -- get highest id
        from items
        where shelf is not null -- ignore null shelf
        and nickname in (select distinct nickname from inserted) -- only search for inserted nicknames
        and items.id not in (select id from inserted) -- exclude new records
    ) tmp2
    where datestamp = maxdate and id = maxID
  ) tmp
  where Items.nickname = tmp.Nickname and items.ID IN (SELECT ID from inserted)

END;

GO


-- create some items to test functionality
insert items (datestamp, nickname, shelf, expected) values ('2014-01-01','aaa',1, null); -- aaa on shelf 1
insert items (datestamp, nickname, shelf, expected) values ('2014-01-01','aaa',2, 1); -- aaa on shelf 2 but same date as previous
insert items (datestamp, nickname, shelf, expected) values ('2014-01-02','bbb',2, null); -- bbb on shelf 2, no prev record
insert items (datestamp, nickname, shelf, expected) values ('2014-01-03','aaa',3, 2); -- aaa - should have lastShelf=2, as that was the last record, not 1 
insert items (datestamp, nickname, shelf, expected) values ('2014-01-04','aaa',null, 3); -- aaa again, but null shelf, lastShelf=3
insert items (datestamp, nickname, shelf, expected) values ('2014-01-06','aaa',4, 3); -- aaa last shelf should ignore null, still 3
insert items (datestamp, nickname, shelf, expected) values ('2014-01-08','bbb',1, 2); -- bbb lastShelf=2
insert items (datestamp, nickname, shelf, expected) values ('2014-01-06','aaa',5, 4); -- aaa lastShelf should be 4

-- show results
select * from Items;

此时,项目是正确的,所以现在删除LastShelf以模拟现有记录:

update Items set LastShelf =null;

此查询将为现有记录设置LastShelf值:工具架不能为空,具有相同的昵称以及更早的日期和更低的ID。对于具有相同日期的条目,使用来自较高ID的货架。您可以通过比较"预期"来检查结果。最后一个架子。

update Items
set lastShelf = tmp.computed
from (
select i1.ID, i1.Nickname, i1.shelf, i1.expected,
(select top 1 i3.shelf from 
    (
    select id, nickname, datestamp, shelf,
        MAX(datestamp) over (partition by nickname) maxDate, -- get latest by date
        MAX(id) over (partition by nickname) maxID           -- get highest id
    from items i2
    where i2.shelf is not null -- ignore null shelf
    and i2.nickname = i1.nickname -- same nickname
    and i2.datestamp <= i1.datestamp -- date is earlier than this record
    and i2.ID < i1.ID -- ID is lower than this record
    ) i3 where i3.maxDate = i3.datestamp and i3.ID = i3.maxID
) computed
from Items i1
) tmp where Items.ID = tmp.ID;