0

我带着大量的命令式经验来到 SQL,并试图弄清楚如何做感觉它需要一个循环而不需要 SQL 中的循环。即,在您绝对会在命令式语言中循环的情况下,不循环 SQL 的惯用方法是什么?

我在 SQL (Server) 中有一个类似这样的表(假设我们选择标签 ID 为 999 的位置,并且 inc_indx 是自动递增的)

inc_indx | State | Tag_Id
     400       5      999
     399       3      "
     397       0      "
     395      50      "
     392      39      "
...etc

本质上,状态会增加一段时间,然后不可预测地为零。我想获得给定集合中每个零值之前的最后一个值。

要这样做一次,我会这样做:

SELECT TOP 1 [State]
FROM [mytable]
WHERE [inc_indx] <
    (SELECT TOP 1 [inc_ndx]
    FROM [mytable]
    WHERE Tag_Id = 999
    AND State = 0)
AND Tag_Id = 999

要重复执行此操作,在命令式 pythonish 伪代码中并假设某种类型的 DB 连接处理类,我会这样做:

setOfZeroes = handler.query("SELECT [inc_ndx]
    FROM [mytable]
    WHERE Tag_Id = 999
    AND State = 0")

setOfMaxes = []
for index in setOfZeroes:
    max = handler.query("SELECT TOP 1 [State]
                  FROM [mytable]
                  WHERE [inc_indx] < "
                  + index + 
                  " AND Tag_Id = 999")
    setOfMaxes.add(max)

但是,假设我想在 SQL 中完成这一切并且我不想循环,那么 SQLese 的方法是什么?

回答:

简短版本:CTE 和联接

长版(其中一些可能是不必要的):

-- narrow the scope, add a numbered row
WITH numbered AS (SELECT [State]
            ,inc_indx
            ,ROW_NUMBER() OVER (Order by inc_indx) As [row]
        FROM mytable
        WHERE Tag_Id = 999)
-- put the row numbers where state is zero in a second CTE
, zeroes AS (SELECT [row]
        FROM numbered
        WHERE State = 0)
SELECT [State], [inc_indx]
FROM numbered, zeroes
WHERE numbered.[row] = zeroes.[row] - 1
ORDER BY [inc_indx] desc
4

2 回答 2

1

使用apply怎么样?毫无疑问,还有其他几种方法,但这个方法有效

select q1.*
from mytable as q1
cross apply (
    select top 1 *
    from mytable as q2
    where q2.Tag_Id = q1.Tag_Id
        and q2.State = 0
        and q2.inc_indx > q1.inc_indx
    order by q2.inc_indx desc
) as q2

这是我使用的架构/数据

CREATE TABLE mytable (
    inc_indx int,
    State int,
    Tag_Id int
)

insert into mytable
values
    (1, 5, 999), 
    (2, 3, 998), 
    (3, 0, 999), 
    (4, 50, 991), 
    (5, 39, 989), 
    (6, 0, 991)

编辑:

好的,从我从您的示例和伪代码中了解到,一个标签可以有多个状态(包括 0),并且您想要特定标签的 0 状态之前的状态?像这样?

于 2013-10-18T15:28:21.493 回答
1

我通常用 CTE 分解问题:s

WITH FirstZeroIndex AS (
    SELECT Tag_Id
          ,MIN(inc_indx) AS ZeroIdx
    FROM mytable
    WHERE State = 0
    GROUP BY Tag_Id
)
,LastNonZeroIndex AS (
    SELECT mytable.Tag_Id
          ,MAX(mytable.inc_indx) AS NonZeroIdx
    FROM mytable
         LEFT JOIN FirstZeroIndex
             ON myTable.Tag_Id = FirstZeroIndex.Tag_Id
    WHERE FirstZeroIndex.ZeroIdx IS NULL -- If we want tags without zeros
          OR mytable.inc_indx < FirstZeroIndex.ZeroIdx
    GROUP BY mytable.Tag_Id
)
SELECT * 
FROM LastNonZeroIndex
WHERE Tag_id = 999
于 2013-10-18T16:06:55.260 回答