Mysql 53 | 53 |[NULL]| 54 | 54 |[零]| 55 | 55 |[零]| 56| 56| 56| 57 |[NULL]|[NULL]| 58 |[NULL]|[NULL]| {截取重复的空值} 74 |[NULL]|[NULL]
53 | 53 |[NULL]| 54 | 54 |[零]| 55 | 55 |[零]| 56| 56| 56| 57 |[NULL]|[NULL]| 58 |[NULL]|[NULL]| {截取重复的空值} 74 |[NULL]|[NULL]| 75 |[NULL]|[NULL]| 76| 76| 76| 77 |[NULL]|[NULL]| 78 |[NULL]|[NULL]| {截取重复的空值} 86 |[NULL]|[NULL]| 87 |[NULL]|[NULL]| 88| 88| 88| 89 |[NULL]|[NULL]| 90 |[NULL]|[NULL]| {截取重复的空值} 98 |[NULL]|[NULL]| 99 |[NULL]|[NULL]| 100| 100| 100| */Mysql 53 | 53 |[NULL]| 54 | 54 |[零]| 55 | 55 |[零]| 56| 56| 56| 57 |[NULL]|[NULL]| 58 |[NULL]|[NULL]| {截取重复的空值} 74 |[NULL]|[NULL],mysql,sql,Mysql,Sql,53 | 53 |[NULL]| 54 | 54 |[零]| 55 | 55 |[零]| 56| 56| 56| 57 |[NULL]|[NULL]| 58 |[NULL]|[NULL]| {截取重复的空值} 74 |[NULL]|[NULL]| 75 |[NULL]|[NULL]| 76| 76| 76| 77 |[NULL]|[NULL]| 78 |[NULL]|[NULL]| {截取重复的空值} 86 |[NULL]|[NULL]| 87 |[NULL]|[NULL
哪个版本的MySQL?@Nick
版本14.16发行版5.2.4-MariaDB-rp
使用子查询而不是左连接:选择1作为id union all select 2 union all select…
@juergend,在我的真实情况下,我有>3000 id。我认为使用select 1 union…
不是一个好的解决方案!此方法假定数字列表始终是连续的,没有gaps@RaymondNijland好的,我用MIN
编辑我的答案,MAX
函数为开始和结束值,然后执行CTE递归更新将不允许在数字列表中使用间隙。此方法还假设数字列表中没有间隙。您不认为如果数字列表增加到1000,仅使用Select或最多10000就几乎不可能生成一个列表,在任何情况下,我很确定它都会生成。@AnkitBajpai true给我一些时间来找出一个更具动态性的列表method@RaymondNijland,谢谢你的回答。尽管如此,我不喜欢使用这个SELECT。。UNION
语句,但我成功地创建了查询动态的这一部分(使用了Sublime文本编辑工具:P),现在我得到了我想要的。@AnkitBajpai“你不认为如果数字列表增加到1000,仅使用Select或最多10000就几乎不可能生成一个列表,我很确定这一点。”我已经发布了一个升级,使它更dynamic@HamzaAbdaoui我已经发布了一个升级,使它更具动态性
+--------+
| tab_id |
+--------+
| 1 |
| 2 |
| ... |
| 50 |
| 56 |
| 100 |
+--------+
create table my_tab(
tab_id int
);
insert into my_tab values (1);
insert into my_tab values (2);
insert into my_tab values (3);
insert into my_tab values (4);
insert into my_tab values (5);
insert into my_tab values (9);
insert into my_tab values (10);
insert into my_tab values (20);
WITH RECURSIVE cte AS (
SELECT MIN(tab_id) fromVal,MAX(tab_id) toVal
FROM my_tab
UNION ALL
SELECT (fromVal+1),toVal
FROM cte
WHERE fromVal < toVal
)
SELECT fromVal
FROM cte c
WHERE NOT exists
(
SELECT 1
FROM my_tab t1
WHERE t1.tab_id = c.fromVal
);
| fromVal |
| ------- |
| 6 |
| 7 |
| 8 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
select n+1 from my_tab
right outer join
(select (d1.n*10 + d2.n) n from (select 1 as n union all select 2 union all select 3 union all select 4 union all select 5 union all
select 6 union all select 7 union all select 8 union all select 9 union all select 0
) d1 cross join
(select 1 as n union all select 2 union all select 3 union all select 4 union all select 5 union all
select 6 union all select 7 union all select 8 union all select 9 union all select 0
) d2) temp_num
on tab_id = n+1
where tab_id is null
order by n
| number |
|--------|
| 3 |
| 4 |
| 51 |
| 52 |
| 53 |
| 54 |
| 55 |
SELECT
number_list.number
FROM (
SELECT
1 AS number
UNION
SELECT
2 AS number
UNION
SELECT
3 AS number
UNION
SELECT
4 AS number
# ...
# ...
UNION
SELECT
50 AS number
UNION
SELECT
51 AS number
UNION
SELECT
52 AS number
UNION
SELECT
53 AS number
UNION
SELECT
54 AS number
UNION
SELECT
55 AS number
UNION
SELECT
56 AS number
UNION
# ...
# ...
SELECT
100 AS number
) AS number_list
LEFT JOIN
Table1
ON
number_list.number = Table1.tab_id
WHERE
Table1.tab_id IS NULL
| number |
|--------|
| 3 |
| 4 |
| 51 |
| 52 |
| 53 |
| 54 |
| 55 |
SELECT
(@row_number := @row_number + 1) AS row_number
FROM (
SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_1
CROSS JOIN (
SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_2
CROSS JOIN (SELECT @row_number := 0) AS init_user_param
SELECT
SUBSTRING_INDEX(
SUBSTRING_INDEX(
'1,2,3,4,50,51,52,53,54,55,56,100'
,',', 1
)
, ','
, -1
) AS number
SELECT
number_list.number
FROM (
SELECT
DISTINCT
SUBSTRING_INDEX(
SUBSTRING_INDEX(
'1,2,3,4,50,51,52,53,54,55,56,100' #this is the number list
,',', number_generator.row_number
)
, ','
, -1
) AS number
FROM (
SELECT
(@row_number := @row_number + 1) AS row_number
FROM (
SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_1
CROSS JOIN (
SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 10
) AS record_2
CROSS JOIN (SELECT @row_number := 0) AS init_user_param
) AS number_generator
) AS number_list
LEFT JOIN
Table1
ON
number_list.number = Table1.tab_id
WHERE
Table1.tab_id IS NULL
drop table if exists tableA ;
create table tableA (tabId int) ;
insert into tableA (tabId) values
(1), (2), (3), (4), (22), (19), (50), (51), (52), (53), (54), (55), (56), (88), (76), (100) ;
drop table if exists tableB ;
create table tableB (tabId int) ;
insert into tableB (tabId) values
(1), (5), (3), (4), (22), (19), (50), (56), (88), (76), (100) ;
select *
from tableA
where tableA.tabId not in (select tabId from tableB) ;
2
51
52
53
54
55
-- ----------------------------------------------------------------
-- Example 2: Which Id's are in which table
--
select *
from
(
select distinct tabId from tableA
union
select distinct tabId from tableB
) as unionAB
left join tableA on unionAB.tabId = tableA.tabId
left join tableB on unionAB.tabId = tableB.tabId
order by unionAB.tabId
;
/*
tabId |tabId |tabId |
------|------|------|
1| 1| 1|
2| 2|[NULL]|
3| 3| 3|
4| 4| 4|
5|[NULL]| 5|
19| 19| 19|
22| 22| 22|
50| 50| 50|
51| 51|[NULL]|
52| 52|[NULL]|
53| 53|[NULL]|
54| 54|[NULL]|
55| 55|[NULL]|
56| 56| 56|
76| 76| 76|
88| 88| 88|
100| 100| 100|
*/
-- ----------------------------------------------------------------
-- Example 3: Which Id's are missing from both tables
--
-- Determine the start/end of the range of Id's
set @startId = least((select min(tabId) from tableA), (select min(tabId) from tableB)) ;
set @endId = greatest((select max(tabId) from tableA), (select max(tabId) from tableB)) ;
select @startId, @endId ;
/*
@startId|@endId|
--------|------|
1| 100|
*/
-- Build the full list of Id's from min to max (no gaps), using a "Common Table Expression"
-- This is based on @Brad's post in Stackoverflow: https://stackoverflow.com/questions/2157282/generate-days-from-date-range
with recursive lstIds as
(
select @startId as 'tabId'
union
select lstIds.tabId + 1 as 'tabId'
from lstIds
where lstIds.tabId < @endId
) -- no trailing ';' needed/allowed
-- Extract the new data so that it can be used
-- Note: this 'select' needs to be imediately after the 'with' block
select *
from lstIds
-- Join the other tables into the full list
left join tableA on lstIds.tabId = tableA.tabId
left join tableB on lstIds.tabId = tableB.tabId
-- where isnull(tableA.tabId) and isnull(tableB.tabId) -- uncomment this line to see only the Id's that don't have a match in both tables
order by lstIds.tabId
;
/*
tabId |tabId |tabId |
------|------|------|
1| 1| 1|
2| 2|[NULL]|
3| 3| 3|
4| 4| 4|
5|[NULL]| 5|
6|[NULL]|[NULL]|
7|[NULL]|[NULL]|
{ snipped repeated nulls }
17|[NULL]|[NULL]|
18|[NULL]|[NULL]|
19| 19| 19|
20|[NULL]|[NULL]|
21|[NULL]|[NULL]|
22| 22| 22|
23|[NULL]|[NULL]|
24|[NULL]|[NULL]|
{ snipped repeated nulls }
48|[NULL]|[NULL]|
49|[NULL]|[NULL]|
50| 50| 50|
51| 51|[NULL]|
52| 52|[NULL]|
53| 53|[NULL]|
54| 54|[NULL]|
55| 55|[NULL]|
56| 56| 56|
57|[NULL]|[NULL]|
58|[NULL]|[NULL]|
{ snipped repeated nulls }
74|[NULL]|[NULL]|
75|[NULL]|[NULL]|
76| 76| 76|
77|[NULL]|[NULL]|
78|[NULL]|[NULL]|
{ snipped repeated nulls }
86|[NULL]|[NULL]|
87|[NULL]|[NULL]|
88| 88| 88|
89|[NULL]|[NULL]|
90|[NULL]|[NULL]|
{ snipped repeated nulls }
98|[NULL]|[NULL]|
99|[NULL]|[NULL]|
100| 100| 100|
*/