假设我有一个如下所示的数据库:
tblA:
ID, Name, Sequence, tblBID
1 a 5 14
2 b 3 15
3 c 3 16
4 d 3 17
tblB:
ID, Group
14 1
15 1
16 2
17 3
我想对A进行排序,以便每组B的序列为1 ... n。 因此,在这种情况下,下降的序列应为1,2,1,1。
订购需要与当前订购一致,但不保证当前订购。
我不是一个sql主人,我确信有一个相当简单的方法可以做到这一点,但我真的不知道正确的路线。任何提示?
答案 0 :(得分:5)
如果您使用的是SQL Server 2005+或更高版本,则可以使用排名功能:
Select tblA.Id, tblA.Name
, Row_Number() Over ( Partition By tblB.[Group] Order By tblA.Id ) As Sequence
, tblA.tblBID
From tblA
Join tblB
On tblB.tblBID = tblB.ID
这是另一个可以在SQL Server 2000及之前版本中使用的解决方案。
Select A.Id, A.Name
, (Select Count(*)
From tblB As B1
Where B1.[Group] = B.[Group]
And B1.Id < B.ID) + 1 As Sequence
, A.tblBID
From tblA As A
Join tblB As B
On B.Id = A.tblBID
修改强>
还想明确表示我想实际更新tblA以反映正确的序列。
在SQL Server中,您可以在Update语句中使用其专有的From子句,如下所示:
Update tblA
Set Sequence = (
Select Count(*)
From tblB As B1
Where B1.[Group] = B.[Group]
And B1.Id < B.ID
) + 1
From tblA As A
Join tblB As B
On B.Id = A.tblBID
Hoyle ANSI解决方案可能类似于:
Update tblA
Set Sequence = (
Select (Select Count(*)
From tblB As B1
Where B1.[Group] = B.[Group]
And B1.Id < B.ID) + 1
From tblA As A
Join tblB As B
On B.Id = A.tblBID
Where A.Id = tblA.Id
)
修改强>
我们可以根据A.Sequence而不是B.ID来进行[内部组]比较吗?
Select A1.*
, (Select Count(*)
From tblB As B2
Join tblA As A2
On A2.tblBID = B2.Id
Where B2.[Group] = B1.[Group]
And A2.Sequence < A1.Sequence) + 1
From tblA As A1
Join tblB As B1
On B1.Id = A1.tblBID
答案 1 :(得分:2)
因为它是SQL 2000,所以我们不能使用窗口函数。没关系。
托马斯的询问很好并且会有效。但是,随着行数的增加,它们会变得越来越糟 - 具有不同的特征,具体取决于行的宽度(组数)和深度(每组的项目数)。这是因为那些查询使用了部分交叉连接,也许我们可以将其称为“金字塔交叉连接”,其中交叉部分限于小于左侧值的右侧值,而不是左侧交叉到所有正确的值。
怎么办?
我认为你会惊讶地发现,以下长而痛苦的剧本将在一定数量的数据(可能不是那么大)上胜过金字塔连接,最终, 包含非常大的数据集必须被视为尖叫表演者:
CREATE TABLE #tblA (
ID int identity(1,1) NOT NULL,
Name varchar(1) NOT NULL,
Sequence int NOT NULL,
tblBID int NOT NULL,
PRIMARY KEY CLUSTERED (ID)
)
INSERT #tblA VALUES ('a', 5, 14)
INSERT #tblA VALUES ('b', 3, 15)
INSERT #tblA VALUES ('c', 3, 16)
INSERT #tblA VALUES ('d', 3, 17)
CREATE TABLE #tblB (
ID int NOT NULL PRIMARY KEY CLUSTERED,
GroupID int NOT NULL
)
INSERT #tblB VALUES (14, 1)
INSERT #tblB VALUES (15, 1)
INSERT #tblB VALUES (16, 2)
INSERT #tblB VALUES (17, 3)
CREATE TABLE #seq (
seq int identity(1,1) NOT NULL,
ID int NOT NULL,
GroupID int NOT NULL,
PRIMARY KEY CLUSTERED (ID)
)
INSERT #seq
SELECT
A.ID,
B.GroupID
FROM
#tblA A
INNER JOIN #tblB B ON A.tblBID = b.ID
ORDER BY B.GroupID, A.Sequence
UPDATE A
SET A.Sequence = S.seq - X.MinSeq + 1
FROM
#tblA A
INNER JOIN #seq S ON A.ID = S.ID
INNER JOIN (
SELECT GroupID, MinSeq = Min(seq)
FROM #seq
GROUP BY GroupID
) X ON S.GroupID = X.GroupID
SELECT * FROM #tblA
DROP TABLE #seq
DROP TABLE #tblB
DROP TABLE #tblA
如果我理解正确,那么ORDER BY B.GroupID, A.Sequence
是正确的。如果没有,您可以将A.Sequence切换为B.ID。
另外,我应该对临时表上的索引进行实验。对于一定数量的行,以及这些行的宽度和深度特征,在#seq表中的另外两列之一上进行聚类可能会有所帮助。
最后,可能存在不同的数据组织:将GroupID从#seq表中删除并再次加入。我怀疑情况会更糟,但并非百分百肯定。
答案 2 :(得分:0)
类似的东西:
SELECT a.id, a.name, row_number() over (partition by b.group order by a.id) FROM tblA a JOIN tblB on a.tblBID = b.ID;