我遇到这种情况:
drop table #t1;
drop table #t2
select *
into #t1
from
(select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va4'c1,'vb4'c2,'vc4'c3) t
select *
into #t2
from #t1
where 0 = 1
;with tmp1 as
(
select
t1.*,
ROW_NUMBER() over (partition by t1.c1 order by (select null)) r
from
#t1 t1
left join
#t2 t2 on t1.c1 = t2.c1
where
t2.c1 is null
), tmp2 as
(
select
0 n,*
from
tmp1
union all
select
n+1 n, t1.c1, t1.c2, t1.c3, t1.r
from
tmp2 t1
join
tmp1 t2 on t1.c1 = t2.c1
and t2.r = t1.r + 1
where
n < 10
)
--insert #t2
select c1, c2, c3 --,r
from tmp2
当我运行它时,它会选择一切就好(103条记录)。
问题是当我把这段代码插入#t2(13条记录!!!)
时我认为SQL会一步一步地运行并在运行期间插入记录,而不是我在tmp1中的条件结束......
如何解决?
我的目标是检查数据是否存在,而不是循环和插入结果......但SQL在第1个循环后停止...
答案 0 :(得分:6)
您可以使用MERGE
:
select * into #t1
from(
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va1'c1,'vb1'c2,'vc1'c3 union all
select 'va2'c1,'vb2'c2,'vc2'c3 union all
select 'va3'c1,'vb3'c2,'vc3'c3 union all
select 'va4'c1,'vb4'c2,'vc4'c3
)t;
select * into #t2 from #t1 where 0=1;
;with tmp1 as(
select t1.*, ROW_NUMBER()over(partition by t1.c1 order by(select null))r
from #t1 t1
left join #t2 t2
on t1.c1=t2.c1
where t2.c1 is null
),tmp2 as (
select 0 n,*
from tmp1
union all
select n+1 n,t1.c1,t1.c2,t1.c3,t1.r
from tmp2 t1
join tmp1 t2
on t1.c1=t2.c1
and t2.r=t1.r+1
where n<10
)
MERGE #t2
USING tmp2
ON #t2.c1 = tmp2.c1
WHEN NOT MATCHED THEN
INSERT VALUES (tmp2.c1, tmp2.c2, tmp2.c3);
SELECT @@ROWCOUNT;
-- 103
<强> DBFiddle Demo 强>
修改强>:
感谢Bartosz Ratajczyk审查此案(很快就会有详细解释):
事实证明它与懒惰/渴望表/索引假脱机有关。至少还有两种方法可以强制SQL Server生成不同的执行计划:
a)使用TOP (100) PERCENT
DECLARE @n INT = 100;
;with tmp1 as (
select t1.*,
ROW_NUMBER()over(partition by t1.c1 order by(select null))r
from #t1 t1
left join #t2 t2
on t1.c1=t2.c1
where t2.c1 is null
),tmp2 as
(
select 0 n,*
from tmp1
union all
select n+1 n,t1.c1,t1.c2,t1.c3,t1.r
from tmp2 t1
join tmp1 t2
on t1.c1=t2.c1
and t2.r=t1.r+1
where n<10
)
insert #t2
select TOP (@n) PERCENT c1, c2, c3 --,r
from tmp2
SELECT @@ROWCOUNT;
b)使用ORDER BY .. OFFSET 0 ROWS
:
;with tmp1 as(
select t1.*,
ROW_NUMBER()over(partition by t1.c1 order by(select null))r
from #t1 t1
left join #t2 t2
on t1.c1=t2.c1
where t2.c1 is null
),tmp2 as
(
select 0 n,*
from tmp1
union all
select n+1 n,t1.c1,t1.c2,t1.c3,t1.r
from tmp2 t1
join tmp1 t2
on t1.c1=t2.c1
and t2.r=t1.r+1
where n<10
)
insert #t2
select c1, c2, c3 --,r
from tmp2
ORDER BY 1 OFFSET 0 ROWS;
SELECT @@ROWCOUNT;
<强> db<>fiddle demo2 强>
答案 1 :(得分:2)
您在MS SQL服务器的CTE实现中发挥了特殊性。在所有后端中都没有这样处理。您必须先选择一个临时游标,然后从中插入。即:
SELECT *
INTO #t1
FROM(
SELECT 'va1' c1, 'vb1' c2, 'vc1' c3
UNION ALL
SELECT 'va2' c1, 'vb2' c2, 'vc2' c3
UNION ALL
SELECT 'va3' c1, 'vb3' c2, 'vc3' c3
UNION ALL
SELECT 'va1' c1, 'vb1' c2, 'vc1' c3
UNION ALL
SELECT 'va2' c1, 'vb2' c2, 'vc2' c3
UNION ALL
SELECT 'va3' c1, 'vb3' c2, 'vc3' c3
UNION ALL
SELECT 'va1' c1, 'vb1' c2, 'vc1' c3
UNION ALL
SELECT 'va2' c1, 'vb2' c2, 'vc2' c3
UNION ALL
SELECT 'va3' c1, 'vb3' c2, 'vc3' c3
UNION ALL
SELECT 'va1' c1, 'vb1' c2, 'vc1' c3
UNION ALL
SELECT 'va2' c1, 'vb2' c2, 'vc2' c3
UNION ALL
SELECT 'va3' c1, 'vb3' c2, 'vc3' c3
UNION ALL
SELECT 'va4' c1, 'vb4' c2, 'vc4' c3
)t;
SELECT * INTO #t2 FROM #t1 WHERE 0=1;
DECLARE @tmp TABLE(c1 VARCHAR(10), c2 VARCHAR(10), c3 VARCHAR(10));
WITH
tmp1 AS (
SELECT t1.*, ROW_NUMBER() OVER (PARTITION BY t1.c1 ORDER BY(SELECT NULL)) r
FROM #t1 t1
LEFT JOIN #t2 t2 ON t1.c1=t2.c1
WHERE t2.c1 IS NULL
),
tmp2 AS (
SELECT 0 n, * FROM tmp1
UNION ALL
SELECT n+1 n, t1.c1, t1.c2, t1.c3, t1.r
FROM tmp2 t1
JOIN tmp1 t2 ON t1.c1=t2.c1
AND t2.r=t1.r+1
WHERE n<10
)
INSERT @tmp(c1, c2, c3)
SELECT c1, c2, c3 --,r
FROM tmp2;
INSERT #t2 SELECT * FROM @tmp;
SELECT * FROM #t2;
DROP TABLE #t1;
DROP TABLE #t2;