在SQL中使用危险的IN子句

时间:2012-09-07 13:34:14

标签: sql sql-server sql-server-2005

为什么SQL服务器会以这种方式运行。我在SQL 2005上运行它。

IN子句不验证子查询中的列名,但验证它 对外部查询中的表名称。以下是获取

的示例
Create table #table1(col1 int, col2 char(10), col3 char(15));

Create table #table2(col10 int, col11 char(10), col2 char(15));


insert into #table1(col1, col2, col3)
select 1, 'one', 'three'

insert into #table1(col1, col2, col3)
select 2, 'two', 'three'

insert into #table1(col1, col2, col3)
select 3, 'three', 'four'


insert into #table2(col10, col11, col2)
select 1, 'one', 'three'

insert into #table2(col10, col11, col2)
select 2, 'two', 'three'

insert into #table2(col10, col11, col2)
select 3, 'three', 'four'


select * from #table1
where col1 IN
(select col1 from #table2)

好像我只选择“从#table2中选择col1”然后运行它会发出错误

Msg 207, Level 16, State 1, Line 1
Invalid column name 'col1'.

2 个答案:

答案 0 :(得分:13)

为什么呢?因为它经常有用能够从子查询中的外部查询引用列。没有任何设置可以用来关闭这种行为,但是如果你习惯使用别名,你应该避免使用别名的大部分问题:

select * from #table1 t1
where t1.col1 IN
(select t2.col1 from #table2 t2)

会产生错误。

答案 1 :(得分:6)

这不是IN条款的问题。

此:

SELECT * 
  FROM #table1
 WHERE col1 IN (SELECT col1 
                  FROM #table2)

...有效,因为优化器假定col1来自#table1。如果你使用表别名,那么没有歧义:

SELECT t1.* 
  FROM #table1 t1
 WHERE t1.col1 IN (SELECT t2.col1 
                     FROM #table2 t2)

...你会得到Msg 207: Invalid column error

这与使用DELETE和UPDATE语句时的原理相同,因为典型的语法不允许您对要删除或更新的表进行别名。