SQL Query按时间对项目进行分组,但仅限于彼此靠近?

时间:2013-04-04 18:11:02

标签: sql sql-server sql-server-2012 gaps-and-islands

我正在尝试制作一个SQL语句来从数据库中提取样本值。该表包含与CNC机床中的刀具更改有关的值。我当前的语句正确地提取了值,但只有在给定程序中出现一个工具时才会这样。如果工具多次出现,则时间值对应于从第一次加载到最后一次加载。只有一个TIME列,通过查找它的第一个和最后一个,我可以确定工具进/出时间。

基本示例:

Raw Data:
Tool_Number    TIME    
100            12:00
100            12:01
100            12:02
100            12:03

Current Query Returns: 
Tool_Number    TIME_IN     TIME_OUT    
100            12:00       12:03

当工具多次出现时,事情会变得毛茸茸,因为我不能再使用TOP和DISTINCT规则了。

Raw Data:
Tool_Number    TIME    
100            12:00
100            12:01
100            12:02
100            12:03
200            12:04
200            12:05
100            12:06
100            12:07

Current Query Returns: 
Tool_Number    TIME_IN     TIME_OUT    
100            12:00       12:07
200            12:04       12:05

Ideal Query Returns:
Tool_Number    TIME_IN     TIME_OUT    
100            12:00       12:03
200            12:04       12:05
100            12:06       12:07

我们正在进行时间分析,当然这严重影响了总时间值。 目前的查询是:

SELECT * FROM (SELECT DISTINCT SPINDLE_POT FROM TBL_SPINDLE_DATA_M1 
WHERE TIME BETWEEN '4/3/20131:24:13 PM' AND '4/3/2013 3:07:33 PM') AS A 

CROSS APPLY

((SELECT TOP 1 TIME FROM TBL_SPINDLE_DATA_M1 B WHERE B.SPINDLE_POT = A.SPINDLE_POT AND
TIME BETWEEN '4/3/2013 1:24:13 PM' AND '4/3/2013 3:07:33 PM') AS NEWTABLE1

JOIN

(SELECT TOP 1 TIME FROM TBL_SPINDLE_DATA_M1 B WHERE B.SPINDLE_POT = A.SPINDLE_POT 
AND TIME BETWEEN '4/3/2013 1:24:13 PM' AND '4/3/2013 3:07:33 PM' ORDER BY TIME DESC) 
AS NEWTABLE2 ON (0=0))

我绝不是任何一种SQL查询专家!上面的查询可能是非常错误的,但实际上确实返回了我需要的内容。无论如何都要对类似的项目进行分组,但是如果他们的索引没有相互接触,那么司法足以不对它们进行分组吗?

2 个答案:

答案 0 :(得分:9)

这被称为“岛屿问题”,我已经看到这是一个解决方案(信用Itzik Ben Gan)

select  tool_number,
        min(time) 'in',
        max(time) 'out',
        count(*)
from    (
    select  tool_number,
            time,
            ROW_NUMBER() OVER (ORDER BY time) - ROW_NUMBER() OVER (PARTITION BY Tool_Number ORDER BY time) AS Grp
    from    #temp
    ) as a
group by grp, tool_number
order by min(time)

答案 1 :(得分:7)

这是使用LAG/LEAD的另一种方法:

DECLARE @rawdata TABLE(Tool_Number INT, [Time] TIME(0));

INSERT @rawdata VALUES
(100,'12:00'), (100,'12:01'), (100,'12:02'), (100,'12:03'),
(200,'12:04'), (200,'12:05'),
(100,'12:06'), (100,'12:07');

;WITH x AS
(
  SELECT Tool_Number, [Time], 
    s = CASE Tool_number WHEN LAG(Tool_number,1) OVER (ORDER BY [Time]) 
        THEN 0 ELSE 1 END,
    e = CASE Tool_number WHEN LEAD(Tool_number,1) OVER (ORDER BY [Time]) 
        THEN 0 ELSE 1 END
  FROM @rawdata
),
y AS 
(
  SELECT Tool_Number, s, [Time], e = LEAD([Time],1) OVER (ORDER BY [Time]) 
  FROM x WHERE 1 IN (s,e)
)
SELECT Tool_number, TIME_IN = [Time], TIME_OUT = e 
FROM y 
WHERE s = 1
ORDER BY TIME_IN;

结果:

Tool_number  TIME_IN   TIME_OUT
-----------  --------  --------
100          12:00:00  12:03:00
200          12:04:00  12:05:00
100          12:06:00  12:07:00