Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 查找记录中的差距_Sql_Oracle - Fatal编程技术网

Sql 查找记录中的差距

Sql 查找记录中的差距,sql,oracle,Sql,Oracle,我有一个Oracle表,表中有标签号、时间戳和方向,可以是输入也可以是输出。 有时候,读者会失败,会有差距 对于相同的标语牌编号,我应该: Placard Timestamp Direction 2533 15:36 IN 2533 15:41 OUT 但有时,我会: Placard Timestamp Direction 2533 15:36 IN 2533 15:41

我有一个Oracle表,表中有标签号、时间戳和方向,可以是输入也可以是输出。 有时候,读者会失败,会有差距

对于相同的标语牌编号,我应该:

Placard   Timestamp     Direction
2533      15:36         IN
2533      15:41         OUT
但有时,我会:

Placard   Timestamp     Direction
2533      15:36         IN
2533      15:41         IN
2533      15:49         OUT
表示第一个输入的读出失败,或

Placard   Timestamp     Direction
2533      15:36         IN
2533      15:41         OUT
2533      15:52         OUT
意味着第二次通过的读取失败

为了填补空白,我只需在结果中插入一条记录,如果是遗漏,则为+1分钟;如果是遗漏,则为-1分钟;我将添加第四个字段,指示是正常记录还是错误记录。例如,预期输出为:

Placard   Timestamp     Direction   Status
2533      15:36         IN          OK
2533      15:41         OUT         OK
2533      15:51         IN          Error IN
2533      15:52         OUT         OK
2533      15:36         IN          OK
2533      15:37         OUT         Error OUT
我希望我的解释是正确的


我不能提供任何SQL,因为我不知道怎么做。非常感谢您的帮助。

您需要使用分析函数,但也需要联合来创建新行。请看一下,我试图将所有可能性都放在测试数据中:

with t(Placard   ,ts  ,Direction   ,Status) as (
select 2533   ,   to_timestamp('15:36','hh24:mi')   ,      'IN'      ,    'OK' from dual union all
select 2533   ,   to_timestamp('15:41','hh24:mi')   ,     'IN'     ,    'OK' from dual union all
select 2533   ,   to_timestamp('15:49','hh24:mi')   ,     'OUT'     ,    'OK' from dual UNION ALL
select 2533   ,   to_timestamp('15:55','hh24:mi')   ,     'OUT'     ,    'OK' from dual UNION ALL
select 2533   ,   to_timestamp('16:00','hh24:mi')   ,     'IN'     ,    'OK' from dual)
--test data  

(SELECT PLACARD,TO_CHAR(CASE WHEN (DIRECTION = 'IN') THEN TS+INTERVAL '1' MINUTE ELSE TS_NEXT-INTERVAL '1' minute end,'HH24:MI') TS,
CASE WHEN DIRECTION = 'IN' THEN 'OUT' ELSE 'IN' END DIRECTION,
'ERROR '||CASE WHEN DIRECTION = 'IN' THEN 'OUT' ELSE 'IN' END STATUS
 FROM 
(select t1.*,lead(TS) over(order by TS) TS_NEXT,
case when (lead(t1.direction) over(order by TS) = direction) or 
(direction = 'IN' AND lead(t1.direction) over(order by TS) IS NULL) then 'Y' else 'N' end WRONG from t t1)
WHERE WRONG = 'Y')
UNION ALL SELECT PLACARD,TO_CHAR(TS,'HH24:MI'),DIRECTION,STATUS FROM T
ORDER BY TS;
输出:

   PLACARD TS    DIRECTION STATUS   
---------- ----- --------- ---------
      2533 15:36 IN        OK       
      2533 15:37 OUT       ERROR OUT
      2533 15:41 IN        OK       
      2533 15:49 OUT       OK       
      2533 15:54 IN        ERROR IN 
      2533 15:55 OUT       OK       
      2533 16:00 IN        OK       
      2533 16:01 OUT       ERROR OUT

8 rows selected.

您需要使用分析函数,但也需要union来创建新行。请看一下,我试图将所有可能性都放在测试数据中:

with t(Placard   ,ts  ,Direction   ,Status) as (
select 2533   ,   to_timestamp('15:36','hh24:mi')   ,      'IN'      ,    'OK' from dual union all
select 2533   ,   to_timestamp('15:41','hh24:mi')   ,     'IN'     ,    'OK' from dual union all
select 2533   ,   to_timestamp('15:49','hh24:mi')   ,     'OUT'     ,    'OK' from dual UNION ALL
select 2533   ,   to_timestamp('15:55','hh24:mi')   ,     'OUT'     ,    'OK' from dual UNION ALL
select 2533   ,   to_timestamp('16:00','hh24:mi')   ,     'IN'     ,    'OK' from dual)
--test data  

(SELECT PLACARD,TO_CHAR(CASE WHEN (DIRECTION = 'IN') THEN TS+INTERVAL '1' MINUTE ELSE TS_NEXT-INTERVAL '1' minute end,'HH24:MI') TS,
CASE WHEN DIRECTION = 'IN' THEN 'OUT' ELSE 'IN' END DIRECTION,
'ERROR '||CASE WHEN DIRECTION = 'IN' THEN 'OUT' ELSE 'IN' END STATUS
 FROM 
(select t1.*,lead(TS) over(order by TS) TS_NEXT,
case when (lead(t1.direction) over(order by TS) = direction) or 
(direction = 'IN' AND lead(t1.direction) over(order by TS) IS NULL) then 'Y' else 'N' end WRONG from t t1)
WHERE WRONG = 'Y')
UNION ALL SELECT PLACARD,TO_CHAR(TS,'HH24:MI'),DIRECTION,STATUS FROM T
ORDER BY TS;
输出:

   PLACARD TS    DIRECTION STATUS   
---------- ----- --------- ---------
      2533 15:36 IN        OK       
      2533 15:37 OUT       ERROR OUT
      2533 15:41 IN        OK       
      2533 15:49 OUT       OK       
      2533 15:54 IN        ERROR IN 
      2533 15:55 OUT       OK       
      2533 16:00 IN        OK       
      2533 16:01 OUT       ERROR OUT

8 rows selected.

您需要识别输入/输出值对,其中一些可能缺失。在结果集中创建一个额外的行并不简单(如Aramillo所示,至少不需要敲表两次);您可以使用lead和lag来发现行不存在,但创建行则是另一回事

一种方法是使用lead和lag将数据压缩到in/out对中,这将为缺少的值留下空白,填补空白,然后再次扩展。使用稍微修改的起始数据:

select placard, timestamp, direction
from t42 order by placard, timestamp;

   PLACARD TIMESTAMP DIRECTION
---------- --------- ---------
      2533 15:36     IN        
      2533 15:41     OUT       
      2533 15:52     OUT       
      2533 15:56     IN        
      2533 16:02     IN        
      2533 16:07     OUT       
      2533 16:10     IN        
您可以在后面和前面达到峰值:

select placard, timestamp, direction,
  lag(direction) over (partition by placard order by timestamp) as last_dir,
  lead(direction) over (partition by placard order by timestamp) as next_dir,
  lag(timestamp) over (partition by placard order by timestamp) as last_ts,
  lead(timestamp) over (partition by placard order by timestamp) as next_ts
from t42;

   PLACARD TIMESTAMP DIRECTION LAST_DIR NEXT_DIR LAST_TS NEXT_TS
---------- --------- --------- -------- -------- ------- -------
      2533 15:36     IN                 OUT              15:41   
      2533 15:41     OUT       IN       OUT      15:36   15:52   
      2533 15:52     OUT       OUT      IN       15:41   15:56   
      2533 15:56     IN        OUT      IN       15:52   16:02   
      2533 16:02     IN        IN       OUT      15:56   16:07   
      2533 16:07     OUT       IN       IN       16:02   16:10   
      2533 16:10     IN        OUT               16:07           
和用例语句作为一种手动轴心:

with t as (
  ...
)
select placard, timestamp, direction,
  case when direction = 'IN' then timestamp
    when last_dir is null or last_dir = 'OUT'
    then timestamp - interval '1' minute
    else last_ts end as in_ts,
  case when direction = 'OUT' then timestamp
    when next_dir is null or next_dir = 'IN'
    then timestamp + interval '1' minute
    else next_ts end as out_ts,
  case when direction = 'OUT' and (last_dir is null or last_dir = 'OUT')
    then 'Error IN' else 'OK' end as in_error,
  case when direction = 'IN' and (next_dir is null or next_dir = 'IN')
    then 'Error OUT' else 'OK' end as out_error
from t
order by placard, timestamp;

   PLACARD TIMESTAMP DIRECTION IN_TS OUT_TS IN_ERROR OUT_ERROR
---------- --------- --------- ----- ------ -------- ---------
      2533 15:36     IN        15:36 15:41  OK       OK        
      2533 15:41     OUT       15:36 15:41  OK       OK        
      2533 15:52     OUT       15:51 15:52  Error IN OK        
      2533 15:56     IN        15:56 15:57  OK       Error OUT 
      2533 16:02     IN        16:02 16:07  OK       OK        
      2533 16:07     OUT       16:02 16:07  OK       OK        
      2533 16:10     IN        16:10 16:11  OK       Error OUT 
现在,对于最初有两个值的对,它有重复的值,对于没有的对,它有一分钟的调整值;丢失原始方向行和时间戳行,您可以进入核心对:

with t as (
  ...
)
select distinct placard,
  case when direction = 'IN' then timestamp
    when last_dir is null or last_dir = 'OUT'
    then timestamp - interval '1' minute
    else last_ts end as in_ts,
  case when direction = 'OUT' then timestamp
    when next_dir is null or next_dir = 'IN'
    then timestamp + interval '1' minute
    else next_ts end as out_ts,
  case when direction = 'OUT' and (last_dir is null or last_dir = 'OUT')
    then 'Error IN' else 'OK' end as in_error,
  case when direction = 'IN' and (next_dir is null or next_dir = 'IN')
    then 'Error OUT' else 'OK' end as out_error
from t
order by placard, in_ts;

   PLACARD IN_TS OUT_TS IN_ERROR OUT_ERROR
---------- ----- ------ -------- ---------
      2533 15:36 15:41  OK       OK        
      2533 15:51 15:52  Error IN OK        
      2533 15:56 15:57  OK       Error OUT 
      2533 16:02 16:07  OK       OK        
      2533 16:10 16:11  OK       Error OUT 
最后,您可以为输入和输出记录将其反打印回单独的行:

with t as (
  ...
)
select * from (
  select distinct placard,
    case when direction = 'IN' then timestamp
      when last_dir is null or last_dir = 'OUT'
      then timestamp - interval '1' minute
      else last_ts end as in_ts,
    case when direction = 'OUT' then timestamp
      when next_dir is null or next_dir = 'IN'
      then timestamp + interval '1' minute
      else next_ts end as out_ts,
    case when direction = 'OUT' and (last_dir is null or last_dir = 'OUT')
      then 'Error IN' else 'OK' end as in_error,
    case when direction = 'IN' and (next_dir is null or next_dir = 'IN')
      then 'Error OUT' else 'OK' end as out_error
  from t
)
unpivot ((timestamp, error) for direction in
  ((in_ts, in_error) as 'IN', (out_ts, out_error) as 'OUT'))
order by placard, timestamp;

   PLACARD DIRECTION TIMESTAMP ERROR    
---------- --------- --------- ---------
      2533 IN        15:36     OK        
      2533 OUT       15:41     OK        
      2533 IN        15:51     Error IN  
      2533 OUT       15:52     OK        
      2533 IN        15:56     OK        
      2533 OUT       15:57     Error OUT 
      2533 IN        16:02     OK        
      2533 OUT       16:07     OK        
      2533 IN        16:10     OK        
      2533 OUT       16:11     Error OUT 

,包括第二个标牌。

您需要识别输入/输出值对,其中一些可能缺失。在结果集中创建一个额外的行并不简单(如Aramillo所示,至少不需要敲表两次);您可以使用lead和lag来发现行不存在,但创建行则是另一回事

一种方法是使用lead和lag将数据压缩到in/out对中,这将为缺少的值留下空白,填补空白,然后再次扩展。使用稍微修改的起始数据:

select placard, timestamp, direction
from t42 order by placard, timestamp;

   PLACARD TIMESTAMP DIRECTION
---------- --------- ---------
      2533 15:36     IN        
      2533 15:41     OUT       
      2533 15:52     OUT       
      2533 15:56     IN        
      2533 16:02     IN        
      2533 16:07     OUT       
      2533 16:10     IN        
您可以在后面和前面达到峰值:

select placard, timestamp, direction,
  lag(direction) over (partition by placard order by timestamp) as last_dir,
  lead(direction) over (partition by placard order by timestamp) as next_dir,
  lag(timestamp) over (partition by placard order by timestamp) as last_ts,
  lead(timestamp) over (partition by placard order by timestamp) as next_ts
from t42;

   PLACARD TIMESTAMP DIRECTION LAST_DIR NEXT_DIR LAST_TS NEXT_TS
---------- --------- --------- -------- -------- ------- -------
      2533 15:36     IN                 OUT              15:41   
      2533 15:41     OUT       IN       OUT      15:36   15:52   
      2533 15:52     OUT       OUT      IN       15:41   15:56   
      2533 15:56     IN        OUT      IN       15:52   16:02   
      2533 16:02     IN        IN       OUT      15:56   16:07   
      2533 16:07     OUT       IN       IN       16:02   16:10   
      2533 16:10     IN        OUT               16:07           
和用例语句作为一种手动轴心:

with t as (
  ...
)
select placard, timestamp, direction,
  case when direction = 'IN' then timestamp
    when last_dir is null or last_dir = 'OUT'
    then timestamp - interval '1' minute
    else last_ts end as in_ts,
  case when direction = 'OUT' then timestamp
    when next_dir is null or next_dir = 'IN'
    then timestamp + interval '1' minute
    else next_ts end as out_ts,
  case when direction = 'OUT' and (last_dir is null or last_dir = 'OUT')
    then 'Error IN' else 'OK' end as in_error,
  case when direction = 'IN' and (next_dir is null or next_dir = 'IN')
    then 'Error OUT' else 'OK' end as out_error
from t
order by placard, timestamp;

   PLACARD TIMESTAMP DIRECTION IN_TS OUT_TS IN_ERROR OUT_ERROR
---------- --------- --------- ----- ------ -------- ---------
      2533 15:36     IN        15:36 15:41  OK       OK        
      2533 15:41     OUT       15:36 15:41  OK       OK        
      2533 15:52     OUT       15:51 15:52  Error IN OK        
      2533 15:56     IN        15:56 15:57  OK       Error OUT 
      2533 16:02     IN        16:02 16:07  OK       OK        
      2533 16:07     OUT       16:02 16:07  OK       OK        
      2533 16:10     IN        16:10 16:11  OK       Error OUT 
现在,对于最初有两个值的对,它有重复的值,对于没有的对,它有一分钟的调整值;丢失原始方向行和时间戳行,您可以进入核心对:

with t as (
  ...
)
select distinct placard,
  case when direction = 'IN' then timestamp
    when last_dir is null or last_dir = 'OUT'
    then timestamp - interval '1' minute
    else last_ts end as in_ts,
  case when direction = 'OUT' then timestamp
    when next_dir is null or next_dir = 'IN'
    then timestamp + interval '1' minute
    else next_ts end as out_ts,
  case when direction = 'OUT' and (last_dir is null or last_dir = 'OUT')
    then 'Error IN' else 'OK' end as in_error,
  case when direction = 'IN' and (next_dir is null or next_dir = 'IN')
    then 'Error OUT' else 'OK' end as out_error
from t
order by placard, in_ts;

   PLACARD IN_TS OUT_TS IN_ERROR OUT_ERROR
---------- ----- ------ -------- ---------
      2533 15:36 15:41  OK       OK        
      2533 15:51 15:52  Error IN OK        
      2533 15:56 15:57  OK       Error OUT 
      2533 16:02 16:07  OK       OK        
      2533 16:10 16:11  OK       Error OUT 
最后,您可以为输入和输出记录将其反打印回单独的行:

with t as (
  ...
)
select * from (
  select distinct placard,
    case when direction = 'IN' then timestamp
      when last_dir is null or last_dir = 'OUT'
      then timestamp - interval '1' minute
      else last_ts end as in_ts,
    case when direction = 'OUT' then timestamp
      when next_dir is null or next_dir = 'IN'
      then timestamp + interval '1' minute
      else next_ts end as out_ts,
    case when direction = 'OUT' and (last_dir is null or last_dir = 'OUT')
      then 'Error IN' else 'OK' end as in_error,
    case when direction = 'IN' and (next_dir is null or next_dir = 'IN')
      then 'Error OUT' else 'OK' end as out_error
  from t
)
unpivot ((timestamp, error) for direction in
  ((in_ts, in_error) as 'IN', (out_ts, out_error) as 'OUT'))
order by placard, timestamp;

   PLACARD DIRECTION TIMESTAMP ERROR    
---------- --------- --------- ---------
      2533 IN        15:36     OK        
      2533 OUT       15:41     OK        
      2533 IN        15:51     Error IN  
      2533 OUT       15:52     OK        
      2533 IN        15:56     OK        
      2533 OUT       15:57     Error OUT 
      2533 IN        16:02     OK        
      2533 OUT       16:07     OK        
      2533 IN        16:10     OK        
      2533 OUT       16:11     Error OUT 

,包括第二张海报。

使用分析函数
LAG
。是的,我一直在读这些,但仍然觉得有点难理解脚本。使用分析函数
LAG
。是的,我一直在读这些,但仍然觉得有点难理解脚本。好的,因此@Aramillo使在结果集中创建行看起来很简单。*8-)但这只会在表中出现一次,这对您可能并不重要。还忘了说CTE不是真正必要的,因为超前/滞后可以在主查询中重复,但我发现代码分离出来后可读性更强。这很重要。我必须通过我们公司的一个复杂的变更请求来处理每一个查询,并且在投入生产之前必须得到批准,而且查询的次数越少,就越重要。很多好的,您的查询非常有效。有一件事。当标语牌更改时,最后一条是IN,文本记录的时间戳为NULL,错误为OK。思想?非常感谢@user1753599-抱歉,我有点假设第一个和最后一个记录是正确的,因为每个公告都是正确的。修正了,没问题。完美的非常感谢。亚历克斯,最后一个问题。因为我需要“规范化”查询,所以我需要在每个列中输入和输出时间戳,每次访问公告牌。我的意思是,如果有6对输入/输出,那意味着3次访问。我试图使用coalesce,但它将来自同一个标语牌的所有访问分组。我没有一个“访问”字段可以在小组中使用。您是否认为有可能在每对记录中添加一个访问id(连续编号)?不管两条记录上的数字是否相同?再次感谢。好的,@Aramillo使在结果集中创建行看起来很简单。*8-)但这只会在表中出现一次,这对您可能并不重要。还忘了说CTE不是真正必要的,因为超前/滞后可以在主查询中重复,但我发现代码分离出来后可读性更强。这很重要。我必须通过我们公司的一个复杂的变更请求来处理每一个查询,并且在投入生产之前必须得到批准,而且查询的次数越少,就越重要。很多好的,您的查询非常有效。有一件事。当标语牌更改时,最后一条是IN,文本记录的时间戳为NULL,错误为OK。思想?非常感谢@user1753599-抱歉,我有点假设第一个和最后一个记录是正确的,因为每个公告都是正确的。修正了,没问题。完美的非常感谢。亚历克斯,最后一个问题。因为我需要“规范化”查询,所以我需要在每个列中输入和输出时间戳,每次访问公告牌。我的意思是,如果有6对输入/输出,那意味着3次访问。我试图使用coalesce,但它将来自同一个标语牌的所有访问分组。我没有一个“访问”字段可以在小组中使用。您认为是否有可能添加访问id(连续编号)