12

我在一次采访中得到了以下问题:给定一个包含一些缺失的自然数表,提供两个表的输出,第一个表中的数字差距开始,第二个结束。例子:

____ ________
| | | | |
| 1 | | 3 | 3 |
| 2 | | 6 | 7 |
| 4 | | 10| 12|
| 5 | |___|___|
| 8 |
| 9 |
| 13 |
|____|
4

7 回答 7

7

虽然这与菲尔桑德勒的回答几乎相同,但这应该返回两个单独的表(我认为它看起来更干净)(它至少在 SQL Server 中工作):

声明 @temp 表 (num int)
插入@temp 值 (1),(2),(4),(5),(8),(9),(13)

声明@min INT,@max INT
选择 @min = MIN(num), @max = MAX(num) FROM @temp

SELECT t.num + 1 AS range_start
    来自@temp t
    左连接 @temp t2 ON t.num + 1 = t2.num
    WHERE t.num < @max AND t2.num 为空

SELECT t.num - 1 AS range_end
    来自@temp t
    左连接 @temp t2 ON t.num - 1 = t2.num
    WHERE t.num > @min AND t2.num 为空
于 2010-09-24T16:54:20.903 回答
2

这是 SQL Server 语法:

CREATE TABLE #temp (columnA int)

INSERT INTO #temp VALUES(1)
INSERT INTO #temp VALUES(2)
INSERT INTO #temp VALUES(4)
INSERT INTO #temp VALUES(5)
INSERT INTO #temp VALUES(8)
INSERT INTO #temp VALUES(9)
INSERT INTO #temp VALUES(13)

SELECT 
    t1.columnA - 1
FROM 
    #temp t1
    LEFT JOIN #temp t2 ON t1.columnA = t2.ColumnA + 1
WHERE 
    t2.ColumnA IS NULL
    AND t1.ColumnA != (SELECT MIN(ColumnA) from #temp)  

SELECT 
    t1.columnA + 1
FROM 
    #temp t1
    LEFT JOIN #temp t2 ON t1.columnA = t2.ColumnA - 1
WHERE 
    t2.ColumnA IS NULL  
    AND t1.ColumnA != (SELECT MAX(ColumnA) from #temp)  

DROP table #temp
于 2010-09-24T15:49:41.503 回答
2

Itzik Ben Gan写了很多关于这些“差距和岛屿”问题的文章。他的row_number解决方案是

WITH C AS
(
SELECT N, ROW_NUMBER() OVER (ORDER BY N) AS RN
FROM t
)
SELECT Cur.N+1,Nxt.N-1
FROM C AS Cur 
JOIN C AS Nxt ON Nxt.RN = Cur.RN+1
WHERE Nxt.N-Cur.N>1

以及没有row_number来自同一来源的解决方案。

SELECT N+1 AS start_range,
(SELECT MIN(B.N) FROM t AS B WHERE B.N > A.N)-1 AS end_range
FROM t AS A
WHERE NOT EXISTS(SELECT * FROM t AS B WHERE B.N = A.N+1)
AND N< (SELECT MAX(N) FROM t)
于 2010-09-24T16:30:49.573 回答
2

这可以在没有特定于数据库的 SQL 的情况下工作,它可能会变得更干净一些,但它确实有效

编辑:您可以在 StackExchange 数据资源管理器 的此查询中看到此操作

SELECT low,high FROM 

(

SELECT col1, low 

FROM
(Select n1.col1 col1, min(n2.col1) + 1 low
 from numbers n1
inner join numbers n2
on n1.col1 < n2.col1 

Group by n1.col1) t
WHERE t.low not in (SELECT col1 FROM NUMBERS)
and t.low < (Select MAX(col1) from numbers) 
) t

INNER JOIN 
(

SELECT col1 - 1 col1, high
 FROM
(Select n1.col1 col1 , min(n2.col1) - 1 high
 from numbers n1
inner join numbers n2
on n1.col1 < n2.col1 

Group by n1.col1) t
WHERE t.high not in (SELECT col1 FROM NUMBERS) 
) t2
ON t.col1 = t2.col1
于 2010-09-24T16:41:29.290 回答
1

像这样的东西:

SELECT col1, col2 FROM
(
    SELECT x + 1 as col1, 
        ROW_NUMBER() OVER(ORDER BY x) AS 'rownum'  
    FROM tbl y 
    WHERE NOT EXISTS (SELECT x FROM tbl z WHERE z.x = y.x + 1) 
        AND x <> (SELECT MAX(x) FROM tbl)
) a
INNER JOIN
(
    SELECT x - 1 as col2,
        ROW_NUMBER() OVER(ORDER BY x) AS 'rownum'  
    FROM tbl y 
    WHERE NOT EXISTS (SELECT x FROM tbl z WHERE z.x = y.x - 1) 
        AND x <> (SELECT MIN(x) FROM tbl)
) b
ON a.rownum = b.rownum

对于不同的 DBMS,“rownum”语法会有所不同。以上可能适用于 SQL Server,但我尚未对其进行测试。

正如其中一条评论指出的那样,许多 DBMS 的分析功能将使这变得更容易。

于 2010-09-24T15:38:19.707 回答
0

您可以使用Lag函数访问上一行:

create table #a (n int)

insert #a values(1)
insert #a values(2)
insert #a values(4)
insert #a values(5)
insert #a values(8)
insert #a values(9)
insert #a values(13)

select  prev + 1, n - 1 from
(select lag(n) over(order by n) as prev, n
from    #a) a
where   prev < n - 1

结果:

|3  |3  |

|6  |7  |

|10 |12 |
于 2017-08-29T15:05:54.620 回答
0

SQL Fiddle 设置和解决方案

1. Step1

从 ID 列表中获取当前 ID 和所有可用的下一个 ID

select l1.id curr_id,l2.id next_id from
id_list l1,id_List l2
where l1.id < l2.id;

2. 第 2 步

从上面的列表中,我们将看到所有组合,但仅过滤每个当前 ID 的一个组合以及紧邻最小的下一个 ID,为此,获取每个当前 ID 的最小当前 ID 和最小下一个 ID。按当前 ID 使用分组

with id_combinations as
(
 select l1.id curr_id,l2.id next_id from
 id_list l1,id_List l2
 where l1.id < l2.id
)
select min(curr_id)+1 missing_id_start -- Need to add 1 from current available id
       ,min(next_id)-1 missing_id_end -- Need to subtract 1 from next available id 
from id_combinations
group by curr_id
having min(curr_id)+1 < min(next_id) -- Filter to get only the missing ranges
于 2019-03-08T23:56:14.257 回答