我有一个包含五列的表格:
示例数据:
mykey name otherdata groupID date active
----------------------------------------------------------
1 123_abc_nt cat 1 6-6-16 0
2 123_abc_nt dog 1 6-7-16 0
3 123_abc_nt car 1 6-8-16 1
4 123_xyz_nt red 2 6-9-16 0
5 123_xyz_nt blue 2 6-10-16 1
此表格中的所有条目均按groupID
和名称分组。换句话说,如果名称是123_abc_nt,则该组将是" #insertgroupidhere
"。由于使用此表的过程的性质(我不能以任何方式改变),对" name"的任何更改都是如此。或"其他数据"列将生成一个新行。
所以说用户更改第5行"其他数据"从blue
到green
从使用此表的单独应用程序。在这种情况下,该单独的应用程序将生成新行:6, 123_xyz_nt, green
并将旧列标记为无效0
。
mykey name otherdata groupID date active
-----------------------------------------------------------
1 123_abc_nt cat 1 6-6-16 0
2 123_abc_nt dog 1 6-7-16 0
3 123_abc_nt car 1 6-8-16 1
4 123_xyz_nt red 2 6-9-16 0
5 123_xyz_nt blue 2 6-10-16 0 <--- old row deactivated
6 123_xyz_nt green 2 6-11-16 1 <--- new row inserted and activated
表格中任何列的更改都会发生这种情况。因此,如果我将名称从_nt更改为_rt,则表格将如下所示:
mykey name otherdata groupID date active
---------------------------------------------------------
1 123_abc_nt cat 1 6-6-16 0
2 123_abc_nt dog 1 6-7-16 0
3 123_abc_nt car 1 6-8-16 1
4 123_xyz_nt red 2 6-9-16 0
5 123_xyz_nt blue 2 6-10-16 0
6 123_xyz_nt green 2 6-11-16 0 <--- old row deactivated
7 123_xyz_rt green 2 6-12-16 1 <--- new row inserted and activated
我需要编写一个查询,专门检测从_nt
到_rt
的此名称更改(反之亦然,从_rt
到_nt
)并返回 active 行。所以在最后一种情况下,我的查询需要返回7, 123_xyz_rt, green, 2, 1
。此外,它需要忽略任何其他列更改,并仅检测nt / rt名称列更改。可能会出现我同时更改多行的情况,我的查询需要检测到这一点。
示例:
mykey name otherdata groupID date active
----------------------------------------------------------
1 123_abc_nt cat 1 6-6-16 0
2 123_abc_nt dog 1 6-7-16 0
3 123_abc_nt car 1 6-8-16 0 <-- deactivated
4 123_xyz_nt red 2 6-9-16 0
5 123_xyz_nt blue 2 6-10-16 0
6 123_xyz_nt green 2 6-11-16 0
7 123_xyz_rt green 2 6-12-16 0 <-- deactivated
8 123_xyz_nt green 2 6-13-16 1 <-- activated
9 123_abc_rt car 1 6-13-16 1 <-- activated (note the groupID)
我一直试图确定这样做的查询,但这非常困难。我无法在此数据库中的表上使用触发器,因此需要严格基于查询。以下是我的尝试:
我有一个临时表来捕获任何新插入的行:
DECLARE @NEWROWS_TEMP TABLE(mykey, name, active)
INSERT INTO @NEWROWS_TEMP
--PROCESS TO CATCH NEW ROWS....
然后使用该列表,我试图在while循环中找到已更改名称的行:
--Loop Variables:
DECLARE @TOTALCOUNT INT = (SELECT COUNT(*) FROM @TEMP)
DECLARE @NAME_INVERTED VARCHAR(MAX)
DECLARE @NAME VARCHAR(MAX)
DECLARE @LOOPNUM INTEGER = 1
DECLARE @CURRENT_KEY INT = 0
--Loop to find entries that changed from (nt->rt) OR (rt->nt):
WHILE ((SELECT COUNT(*) FROM @TEMP) > 0 AND (SELECT @LOOPNUM) <= @TOTALCOUNT)
BEGIN
SET @CURRENT_KEY = (SELECT TOP 1 mykey FROM @TEMP)
SET @NAME = (SELECT name
FROM @TEMP
WHERE CLASSIC_KEY = @CURRENT_KEY)
SET @NAME_INVERTED = (SELECT CASE WHEN (CHARINDEX('_rt_',@NAME) > 0)
THEN
REPLACE(@NAME,'_rt_', '_nt_')
ELSE
CASE WHEN (CHARINDEX('_nt_',@NAME) > 0)
THEN
REPLACE(@NAME,'_nt_', '_rt_')
ELSE
NULL
END
END)
IF(EXISTS(
SELECT TOP 1 mykey
FROM mytable
WHERE name = @NAME_INVERTED AND
active = 0)
)
BEGIN
INSERT INTO @RESULT_LIST
SELECT @CURRENT_KEY
END
DELETE FROM @TEMP WHERE mykey = @CURRENT_KEY
SET @LOOPNUM = @LOOPNUM +1
END
除了行名称从未改变但otherdata
确实存在并且存在过去的nt-rt变化的情况之外,这是有效的。该循环只是跳过了行的名称没有改变的事实。
例如,如果我这样做:
mykey name otherdata groupID date active
----------------------------------------------------------
1 123_abc_nt cat 1 6-6-16 0
2 123_abc_nt dog 1 6-7-16 0
3 123_abc_nt car 1 6-8-16 0
4 123_xyz_nt red 2 6-9-16 0
5 123_xyz_nt blue 2 6-10-16 0
6 123_xyz_nt green 2 6-11-16 0
7 123_xyz_rt green 2 6-12-16 0
8 123_xyz_nt green 2 6-13-16 1
9 123_abc_rt car 1 6-13-16 0
10 123_abc_rt bike 1 6-13-16 1 <-- Name did not actually change. Otherdata did, but current query picks this up anuway since there once was a change from "123_abc_nt" to "123_abc_rt"
是否有更简单的方法可以在不使用循环的情况下获得类似的结果?我的方法证明是非常不准确和难以维护的。
答案 0 :(得分:1)
这应返回预期结果,如果不同,请使用active=0
检查上一行的名称:
select * from mytable as t1
where active = 1
and name <>
( select top 1 name
from mytable as t2
where t1.groupID = t2.groupID
and active = 0
order by t2.date desc
)