如何检查 SQL 条记录是否按特定顺序排列
How to check if SQL records are in a specific order
我无法弄清楚如何检查 table 上的记录是否按特定顺序排列。简化的 table 设计本质上是这样的:
+------------+----------------+--------+
| ID (GUID) | StartDate | NumCol |
+------------+----------------+--------+
| CEE8C17... | 8/17/2019 3:11 | 22 |
| BB22001... | 8/17/2019 3:33 | 21 |
| 4D40B12... | 8/17/2019 3:47 | 21 |
| 3655125... | 8/17/2019 4:06 | 20 |
| 3456CD1... | 8/17/2019 4:22 | 20 |
| 38BAF92... | 8/17/2019 4:40 | 19 |
| E60CBE8... | 8/17/2019 5:09 | 19 |
| 5F2756B... | 8/17/2019 5:24 | 18 |
+------------+----------------+--------+
ID
列是非顺序 GUID。输入数据时,table 默认排序在 StartDate
上。但是,我试图标记 NumCol
值不按降序排列的实例。 NumCol
值在相邻记录上可以相同,但最终它们必须降序。
+--------+
| NumCol |
+--------+
| 22 |
| *20 | <- I want the ID where this occurs
| 21 |
| 20 |
| 20 |
| 19 |
| 19 |
| 18 |
+--------+
我已经尝试 LEFT JOIN
这个 table 本身,但似乎无法想出一个 ON
子句来给出正确的结果:
ON a.ID <> b.ID AND a.NumCol > b.NumCol
我还认为我可以使用 OFFSET n ROWS
将默认排序的 table 与对其执行 ORDER BY NumCol
的排序进行比较。我想不出任何有用的东西。
我需要一个适用于 SQL Server 和 SQL Compact 的解决方案。
这可能是最简单的:
select * from T t1
where NumCol < (select max(NumCol) from T t2 where t2.StartDate > t1.StartDate);
exists
版本可能更适合优化。
使用分析函数,您可以尝试这种方法,它可以在连续行的单调性中找到中断。它可能不会 return 您感兴趣的所有行:
with data as (
select *, lag(NumCol) over (order by StartDate desc) as prevNumCol
from T
)
select * from data where prevNumCol > NumCol;
这里有一个更好的解决方案,可能在您的两个环境中都不可用:
with data as (
select *,
max(NumCol) over (
order by StartDate desc
rows between unbounded preceding and current row
) as prevMax
from T
)
select * from data where prevMax > NumCol;
有 EXISTS:
select t.* from tablename t
where exists (
select 1 from tablename
where numcol > t.numcol and startdate > t.startdate
)
或使用 row_number() window 函数:
select t.id, t.startdate, t.numcol
from (
select *,
row_number() over (order by startdate desc) rn1,
row_number() over (order by numcol) rn2
from tablename
) t
where rn1 > rn2
参见demo。
我无法弄清楚如何检查 table 上的记录是否按特定顺序排列。简化的 table 设计本质上是这样的:
+------------+----------------+--------+
| ID (GUID) | StartDate | NumCol |
+------------+----------------+--------+
| CEE8C17... | 8/17/2019 3:11 | 22 |
| BB22001... | 8/17/2019 3:33 | 21 |
| 4D40B12... | 8/17/2019 3:47 | 21 |
| 3655125... | 8/17/2019 4:06 | 20 |
| 3456CD1... | 8/17/2019 4:22 | 20 |
| 38BAF92... | 8/17/2019 4:40 | 19 |
| E60CBE8... | 8/17/2019 5:09 | 19 |
| 5F2756B... | 8/17/2019 5:24 | 18 |
+------------+----------------+--------+
ID
列是非顺序 GUID。输入数据时,table 默认排序在 StartDate
上。但是,我试图标记 NumCol
值不按降序排列的实例。 NumCol
值在相邻记录上可以相同,但最终它们必须降序。
+--------+
| NumCol |
+--------+
| 22 |
| *20 | <- I want the ID where this occurs
| 21 |
| 20 |
| 20 |
| 19 |
| 19 |
| 18 |
+--------+
我已经尝试 LEFT JOIN
这个 table 本身,但似乎无法想出一个 ON
子句来给出正确的结果:
ON a.ID <> b.ID AND a.NumCol > b.NumCol
我还认为我可以使用 OFFSET n ROWS
将默认排序的 table 与对其执行 ORDER BY NumCol
的排序进行比较。我想不出任何有用的东西。
我需要一个适用于 SQL Server 和 SQL Compact 的解决方案。
这可能是最简单的:
select * from T t1
where NumCol < (select max(NumCol) from T t2 where t2.StartDate > t1.StartDate);
exists
版本可能更适合优化。
使用分析函数,您可以尝试这种方法,它可以在连续行的单调性中找到中断。它可能不会 return 您感兴趣的所有行:
with data as (
select *, lag(NumCol) over (order by StartDate desc) as prevNumCol
from T
)
select * from data where prevNumCol > NumCol;
这里有一个更好的解决方案,可能在您的两个环境中都不可用:
with data as (
select *,
max(NumCol) over (
order by StartDate desc
rows between unbounded preceding and current row
) as prevMax
from T
)
select * from data where prevMax > NumCol;
有 EXISTS:
select t.* from tablename t
where exists (
select 1 from tablename
where numcol > t.numcol and startdate > t.startdate
)
或使用 row_number() window 函数:
select t.id, t.startdate, t.numcol
from (
select *,
row_number() over (order by startdate desc) rn1,
row_number() over (order by numcol) rn2
from tablename
) t
where rn1 > rn2
参见demo。