如何处理SQL中任意数量的间隔?

如何处理SQL中任意数量的间隔?,sql,snowflake-cloud-data-platform,ansi-sql,Sql,Snowflake Cloud Data Platform,Ansi Sql,我在一个SQL数据库中有两个表。第一个路径是路径,保存路径(或轨迹)上的点。每个点都有一行 第二个表“Interval”列出了第一个表中表示的路径上的间隔。它们在某种程度上被认为是特殊的,例如,在路径的一部分中,对象移动不多 我们期望在路径上确定多个间隔 我想在path表中添加一个新列,其值表示路径的该部分是否在其中一个间隔内。我在下面的示例中给出了这个附加列的示例 如果只有一个间隔,我会使用 CASE WHEN p.time BETWEEN i.Start_Time AND i.End_Tim

我在一个SQL数据库中有两个表。第一个路径是路径,保存路径(或轨迹)上的点。每个点都有一行

第二个表“Interval”列出了第一个表中表示的路径上的间隔。它们在某种程度上被认为是特殊的,例如,在路径的一部分中,对象移动不多

我们期望在路径上确定多个间隔

我想在
path
表中添加一个新列,其值表示路径的该部分是否在其中一个间隔内。我在下面的示例中给出了这个附加列的示例

如果只有一个间隔,我会使用

CASE WHEN p.time BETWEEN i.Start_Time AND i.End_Time THEN True ELSE False END
我可以做些什么来处理任意数量的间隔

间隔时间:

| Interval ID | Start_Time | End_Time |
|-------------|------------|----------|
| 1           | 5          | 36       |
| 2           | 71         | 78       |
| 3           | 206        | 308      |
| ...         |            |          |
下面是成功添加了所需“at_rest”列的
路径
表的示例

| time | x | y  | at_rest |
|------|---|----|---------|
| 0    | 5 | 9  | 0       |
| 1    | 6 | 10 | 0       |
| 2    | 7 | 31 | 1       |
| 3    | 9 | 49 | 1       |
| ...  |   |    |         |

在不同的DBMS中,答案可能不同。 我认为这种逻辑是可行的,但是实现取决于您的环境。 我假设间隔没有重叠

案例中,当存在
选择
语句时,可以组合使用

CASE WHEN EXISTS(
        SELECT Interval_ID
        FROM intervals
        WHERE p.time BETWEEN Start_Time AND End_Time
    ) THEN (
            SELECT Interval_ID
            FROM intervals
            WHERE p.time BETWEEN Start_Time AND End_Time
    )
     ELSE 0

我认为,拥有间隔_ID比只是一个是/否指示器更有意义。列atRest保留了您最初的Yes/No概念。此外,我向path表添加了更多数据以获得结果--

这需要转换为更新sql以替换现有值。结果是--


如果只需要一行带有
true
/
false
,请使用
exists
。许多数据库直接支持布尔类型,因此您只需使用:

select . . .,
       (exists (select 1
                from intervals i
                where p.time bertween i.start_time and i.end_time
               )
       ) as flag
在其他数据库中,需要一个
case
表达式:

select . . .,
       (case when exists (select 1
                          from intervals i
                          where p.time bertween i.start_time and i.end_time
                         )
             then 1 else 0
       ) as flag

我的同事和我提出的解决方案使用了可怕的
交叉联接
,但我们可以预先将表过滤到几千行,这样就不会出现这样的问题

WITH interval_path AS (SELECT path.*, intervals.*
FROM path
CROSS JOIN intervals
WHERE path.time BETWEEN intervals.Start_Time AND intervals.End_Time)

SELECT path.time, path.x, path.y, 
COALESCE(interval_path.in_cluster, 0) AS in_cluster
FROM path
LEFT JOIN interval_path ON interval_path.time = path.time
ORDER BY path.time

正如donPablo所指出的,这可以通过连接来解决(正如您所描述的):

WITH intervals AS (
  SELECT * 
  FROM VALUES 
    (1,1,5,36)
    ,(1,2,71,78)
    ,(1,3,206,308) 
  v(unit_id, interval_id, start_time, end_time)
), paths AS (
  SELECT * 
  FROM VALUES
    (1,0,5,9 )
    ,(1,1,6,10)
    ,(1,2,7,31)
    ,(1,3,9,49) 
    ,(1,4,9,48) 
    ,(1,5,9,47) 
    ,(1,6,9,46) 
    p(unit_id, time, x, y) 
)
SELECT p.unit_id
    ,p.time
    ,p.x
    ,p.y
    ,i.unit_id is not null as atRest
FROM paths p 
LEFT JOIN intervals i 
    ON p.unit_id = i.unit_id and p.time between i.start_time and i.end_time
order by 1,2;
给予:

UNIT_ID TIME    X   Y   ATREST
1   0   5   9   FALSE
1   1   6   10  FALSE
1   2   7   31  FALSE
1   3   9   49  FALSE
1   4   9   48  FALSE
1   5   9   47  TRUE
1   6   9   46  TRUE
UNIT_ID TIME    X   Y   ATREST
1   0   5   9   FALSE
1   1   6   10  FALSE
1   2   7   31  TRUE
1   3   9   49  TRUE
1   4   9   48  TRUE
1   5   9   47  TRUE
1   6   9   46  TRUE
请注意,您给出的示例间隔并不意味着您给出的第一个点处于“静止”状态,因为这些点不在间隔内

我还包括一个“单位id”,因为只有一个实体拥有大量数据是非常不可能的

现在,如果间隔数据重叠,则需要更改计数:

WITH intervals AS (
  SELECT * 
  FROM VALUES 
    (1,1,2,4)
    ,(1,2,4,6)
    ,(1,3,206,308) 
  v(unit_id, interval_id, start_time, end_time)
), paths AS (
  SELECT * 
  FROM VALUES
    (1,0,5,9 )
    ,(1,1,6,10)
    ,(1,2,7,31)
    ,(1,3,9,49) 
    ,(1,4,9,48) 
    ,(1,5,9,47) 
    ,(1,6,9,46) 
    p(unit_id, time, x, y) 
)
SELECT p.unit_id
    ,p.time
    ,p.x
    ,p.y
    ,count(i.unit_id) > 0 as atRest
FROM paths p 
LEFT JOIN intervals i 
    ON p.unit_id = i.unit_id and p.time between i.start_time and i.end_time
group by 1,2,3,4
order by 1,2;
给予:

UNIT_ID TIME    X   Y   ATREST
1   0   5   9   FALSE
1   1   6   10  FALSE
1   2   7   31  FALSE
1   3   9   49  FALSE
1   4   9   48  FALSE
1   5   9   47  TRUE
1   6   9   46  TRUE
UNIT_ID TIME    X   Y   ATREST
1   0   5   9   FALSE
1   1   6   10  FALSE
1   2   7   31  TRUE
1   3   9   49  TRUE
1   4   9   48  TRUE
1   5   9   47  TRUE
1   6   9   46  TRUE
如果您想要
0
1
作为雪花中的at_rest值,则交换到内联IFF是最紧凑的

    ,iff(count(i.unit_id) > 0,1,0) as atRest

path.at_rest是否是现有的旧列?还是你新专栏的名字?或者,您想为新列命名什么?用您正在使用的数据库标记您的问题。同时显示您想要的结果。@donPablo我在文本中添加了一些说明。“at_rest”列的意思是我们正在添加的新列。抱歉,这不清楚。不幸的是,在一个时间间隔内可能有大量行。@keith。那又怎么样?这提供了一个标志,表示给定行是否在任何间隔内。