SQL将糟糕的表设计迁移到良好的表设计?

时间:2017-12-08 15:13:10

标签: sql sql-server database-normalization

我正在努力将旧的Access数据库转换为SQL Server。在规范化数据库方面,所有这些都非常简单,但我遇到了一个我似乎无法跨越的障碍。

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

这有一个优雅的解决方案吗?

TL:DR;

旧表正在返回这样的数据,

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

我希望它返回,

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.

如果小提琴消失了,这是我的架构,

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')

我正在寻找一个返回以下结构的查询,

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

以下是我用来显示小提琴中的例子的查询,

--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

1 个答案:

答案 0 :(得分:1)

试试这个: -

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