T-SQL:查找之前发生的乱序值

时间:2018-08-25 06:44:24

标签: sql tsql sql-server-2014

此问题与查找乱序事件有关,但仅查找之前发生的事件。在下表中的机器人动作数据中,每个动作应依次到达相同或更高的点号,如果为真,则DIR(方向)= 1。已正确编程了正确的序列(SeqCorr),并记录了实际的序列(SeqAct)以进行比较。

Spot Dir SeqCorr SeqAct moveID
------------------------------
 9    1    113    117    1085
 9    1    114    118    1086
 10   1    115    119    1087
 10   1    116    120    1088
 2    0    1      121    1089
 2    1    2      122    1090
 2    1    3      123    1091
 6    1    5      124    1092
 6    1    6      125    1093
 2    0    4      126    1094
 6    1    7      127    1095
 6    1    8      128    1096

问题是我将如何查询数据以检测Spot的Dir = 0(例如moveID = 1094的Spot2)和Spot至少被访问过一次(moveID 1089至1091)的情况。

输出将是moveID的列表,以及另一个Status列,其中显示了返回到先前访问的Spot的移动。

Status moveID
-------------
 0    1085
 0    1086
 0    1087
 0    1088
 0    1089
 0    1090
 0    1091
 0    1092
 0    1093
 1    1094
 0    1095
 0    1096

3 个答案:

答案 0 :(得分:1)

这将为您提供给定ID之前曾参观过景点的所有动作

select m1.*
from moves m1
join moves m2 ON m1.spot = m2.spot and m1.moveID > m2.moveID
where m2.dir = 0

这将为您提供连续发生的移动

select distinct m1.*
from moves m1
join moves m2 ON m1.spot = m2.spot and m1.dir = m2.dir and m1.moveID > m2.moveID
where m1.dir = 1

答案 1 :(得分:0)

我怀疑机器人可以坐在一个位置上进行相邻移动很好。问题稍后又回到了较早的位置。

如果是这样,则这是一个空白与孤岛问题的示例。当机器人在给定位置上时,可以使用不同的行号来解决该问题,以得到相邻的移动:

select spot, min(moveid) as min_moveid, max(moveid) as max_moveid
from (select m.*,
             row_number() over (order by moveid) as seqnum,
             row_number() over (partition by spot order by moveid) as seqnum_s
      from moves m
     ) m
group by (seqnum - seqnum_s), spot;

为什么这个方法有些难以解释,但很容易理解。如果运行子查询,您将看到行号的差异如何定义每个点。

现在,问题是每个点的移动范围-一个点是否出现不止一次。为此,我们现在可以将count(*)用作窗口函数。因此,要获取重复移动的发生:

with s as (
      select spot, min(moveid), max(moveid)
      from (select m.*,
                   row_number() over (order by moveid) as seqnum,
                   row_number() over (partition by spot order by moveid) as seqnum_s
            from moves m
           ) m
      group by (seqnum - seqnum_s), spot
     )
select s.*
from (select s.*,
             count(*) over (partition by spot) as cnt
      from s
     ) s
where cnt > 1;

我相信这可以回答您的问题。

答案 2 :(得分:0)

这是问题的最终解决方案。这次,我添加了基于更大数据集的分区和分组,这些数据集涵盖了不同生产线和制造工厂不同部门中的机器人。

SELECT line, robot, min(moveid) moveIDmin, max(moveid) moveIDmax
        from (select m.*,
                     row_number() over (partition by line, robot order by moveid) as seqnum,
                     row_number() over (partition by line, robot, spot order by moveid) as seqnum_s
              from #Temp2 m
             ) m
        group by line, robot, (seqnum - seqnum_s), spot
        order by line, robot, moveIDmin

最终的输出结果使无效动作的定位很容易,就像在moveIDmin 298处一样,在该位置机器人已移回先前访问过的地点。

   line  robot spot moveIDmin moveIDmax
  AER389X  G    26       1        72
  AER389X  G    30      73       137
  AER389X  J     2     138       139
  AER389X  J     6     140       224
  AER389X  J    10     225       297
  AER389X  J     6     298       301
  AER389X  J    14     302       319
  AER389X  K    14     320       380
  AER389X  K    18     381       468