SQL 将不好的 table 设计迁移到好的 table 设计?

SQL to migrate bad table design to good table design?

我正在努力将旧的 Access 数据库转换为 SQL 服务器。在规范化数据库方面一切都相当简单,但我遇到了一个我似乎无法跨越的障碍。

旧数据库使用 table 来保存框之间对象的移动。问题是旧的 table 不保存对象移动到的新框,只是所有旧框的日志。当前框保存在 Obj table 中。检查此 fiddle、http://sqlfiddle.com/#!6/382bb/7/0

有没有优雅的解决方案?

TL:DR;

旧的 table 是这样 returning 数据,

MoveID ObjectID   OldBoxID DTMoved
1      27         22       2009-09-11
2      27         16       2008-01-19
3      27         29       2004-10-31

我想要 return,

MoveID ObjectID   OldBoxID NewBoxID   DTMoved
1      27         22       24**      2009-09-11
2      27         16       22        2008-01-19
3      27         29       16        2004-10-31

**This value will be from the Obj table that shows the current BoxID for the object.

以防 fiddle 消失,这是我的架构,

CREATE TABLE Box (
[BoxID] int IDENTITY(1,1) NOT NULL,
[BoxName] varchar(20) NULL,
CONSTRAINT [PK_Box] PRIMARY KEY CLUSTERED 
(
    [BoxID] ASC
))
GO

INSERT INTO Box (BoxName) VALUES ('Box1')
INSERT INTO Box (BoxName) VALUES ('Box2')
INSERT INTO Box (BoxName) VALUES ('Box3')
INSERT INTO Box (BoxName) VALUES ('Box4')
INSERT INTO Box (BoxName) VALUES ('Box5')
INSERT INTO Box (BoxName) VALUES ('Box6')
INSERT INTO Box (BoxName) VALUES ('Box7')
INSERT INTO Box (BoxName) VALUES ('Box8')
INSERT INTO Box (BoxName) VALUES ('Box9')
INSERT INTO Box (BoxName) VALUES ('Box10')

CREATE TABLE Obj (
    [ObjectID] int IDENTITY(1,1) NOT NULL,
    [ObjectName] varchar(20) NULL,
    [CurrentBoxID] int NULL
CONSTRAINT [PK_Obj] PRIMARY KEY CLUSTERED 
(
[ObjectID] ASC
))
GO

INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('tiger',3)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('file',8)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('press',9)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('heap',4)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('careful',6)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('fairies',5)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('uneven',7)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('fertile',5)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('brass',9)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('hospitable',8)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('stem',1)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('pastoral',9)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('strip',10)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('spiteful',9)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('scribble',6)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('vest',1)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('soothe',5)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('sin',4)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('fanatical',10)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('scissors',7)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('rat',3)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('plastic',5)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('store',6)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('mighty',1)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('juice',6)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('angry',8)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('zephyr',2)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('decorous',1)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('stretch',4)
INSERT INTO Obj (ObjectName,CurrentBoxID) VALUES ('complete',9)

CREATE TABLE Move (
    [MoveID] int IDENTITY(1,1) NOT NULL,
    [ObjectID] int NULL,
    [OldBoxID] int NULL,
    [DTMoved] datetime NULL
 CONSTRAINT [PK_Move] PRIMARY KEY CLUSTERED 
(
    [MoveID] ASC
))
GO

INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (5,10,'01/15/2006')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (30,6,'05/21/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (27,10,'06/12/2010')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (25,6,'10/30/2006')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (19,10,'08/30/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (19,2,'05/01/2006')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (29,4,'01/24/2013')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (16,10,'04/08/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (17,3,'03/11/2014')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (3,4,'02/25/2006')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (17,9,'06/05/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (27,5,'12/31/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (11,8,'01/08/2012')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (27,1,'09/21/2012')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (21,7,'07/22/2017')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (16,1,'02/19/2005')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (12,3,'09/12/2012')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (3,3,'05/08/2016')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (6,1,'09/12/2006')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (20,1,'12/13/2015')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (13,4,'10/20/2017')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (2,5,'06/21/2015')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (6,5,'11/21/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (15,5,'09/10/2005')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (15,10,'10/20/2006')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (10,10,'06/07/2008')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (9,2,'10/19/2012')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (3,1,'10/27/2011')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (27,1,'03/03/2010')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (2,8,'12/06/2013')
INSERT INTO Move (ObjectID,OldBoxID,DTMoved) VALUES (2,4,'03/29/2017')

我正在寻找 return 以下结构的查询,

MoveID,ObjectID,DTMoved,OldBox,NewBox
12,27,'2008-12-31',Box5,Box1
29,27,'2010-03-03',Box1,Box10
3,27,'2010-06-12',Box10,Box1
14,27,'2012-09-21',Box1,Box2

这是我用来显示 fiddle、

中示例的查询
--Move joins
SELECT MoveID, M.ObjectID, DTMoved, BB.BoxName AS OldBox, B.BoxName AS CurrentBox
FROM Move M
   INNER JOIN Obj O ON M.ObjectID = O.ObjectID
   INNER JOIN Box B ON O.CurrentBoxID = B.BoxID
   INNER JOIN Box BB ON M.OldBoxID = BB.BoxID
ORDER BY O.ObjectID, DTMoved

--How many moves per box
SELECT ObjectID, COUNT(ObjectID)
FROM Move
GROUP BY ObjectID
ORDER BY COUNT(ObjectID) DESC

--Look at Object ID 27
SELECT MoveID, M.ObjectID, DTMoved, BB.BoxName AS OldBox, '' AS NewBox, B.BoxName AS CurrentBox
FROM Move M
   INNER JOIN Obj O ON M.ObjectID = O.ObjectID
   INNER JOIN Box B ON O.CurrentBoxID = B.BoxID
   INNER JOIN Box BB ON M.OldBoxID = BB.BoxID
WHERE M.ObjectID = 27
ORDER BY DTMoved DESC

试试这个:-

SELECT MoveID, M.ObjectID, DTMoved, BB.BoxName AS OldBox 
,isnull(lead(oldboxid) OVER (ORDER BY DTMoved), O.CurrentBoxID) As newBoxId
FROM Move M
   INNER JOIN Obj O ON M.ObjectID = O.ObjectID
   INNER JOIN Box BB ON M.OldBoxId = BB.BoxID
WHERE M.ObjectID = 27
ORDER BY DTMoved