这个相关的子查询,子查询后面的子查询是不是对外键的空检查,是否用连接替换?例如:
select * from TableABC as t
where
(t.label_id is null or t.label_id in ( select t1.id from Labels as t1 where t1.type = '123'))
and
(t.tag_id is null or t.tag_id in ( select t2.id from Tags as t2 where t2.type = '123'))
用文字描述:让我们说,我正在查找所有记录,如果他们已经定义了标签参考,那么标签必须是某种类型;同样适用于标签。
或者可以通过其他方式改进此查询?
适用于TSQL(MS SQL)。
更新:
我已经添加了HABO提示的表别名。希望它会提高可读性。
答案 0 :(得分:2)
我倾向于把它写成:
select t.*
from TableABC abc
where (abc.label_id is null or
exists (select 1 from labels where l.id = abc.label_id and l.type = 123)
) and
(abc.tag_id is null or
exists (select 1 from tags t where t.id = abc.tag_id and t.type = 123)
);
然后我确定我在labels(id, type)
和tags(id, type)
的索引中(如果id
不是主键)。
但是,您的版本可能还有一个合理的执行计划和正确的索引。
答案 1 :(得分:1)
我不确定这是一项改进,但确实使用了left outer join
而不是相关的子查询。
-- Sample data.
declare @TableABC as Table( ABCId Int Identity, LabelId Int, TagId Int );
declare @Labels as Table( LabelId Int Identity, Label VarChar(3) );
declare @Tags as Table( TagId Int Identity, Tag VarChar(3) );
insert into @Labels ( Label ) values ( '123' ), ( '12' ), ( '123' );
insert into @Tags ( Tag ) values ( '123' ), ( '213' ), ( '123' ), ( '312' );
insert into @TableABC ( LabelId, TagId ) values
( 1, 1 ), ( 1, 2 ), ( 1, 3 ), ( 1, 4 ),
( 2, 1 ), ( 2, 2 ), ( 2, 3 ), ( 2, 4 ),
( 3, 1 ), ( 3, 2 ), ( 3, 3 ), ( 3, 4 ),
( NULL, 1 ), ( NULL, 3 ), ( 1, NULL ), ( 3, NULL ), ( NULL, NULL );
select ABC.ABCId, ABC.LabelId, ABC.TagId,
L.LabelId as L_LabelId, L.Label as L_Label,
case when ABC.LabelId is NULL or L.Label = '123' then '<<<' else '' end as 'L_Match',
T.TagId as T_TagId, T.Tag as T_Tag,
case when ABC.TagId is NULL or T.Tag = '123' then '<<<' else '' end as 'T_Match'
from @TableABC as ABC left outer join
@Labels as L on L.LabelId = ABC.LabelId left outer join
@Tags as T on T.TagId = ABC.TagId;
-- "Original" query:
select *
from @TableABC
where ( LabelId is null or LabelId in ( select LabelId from @Labels where Label = '123' ) ) and
( TagId is null or TagId in ( select TagId from @Tags where Tag = '123' ) );
-- Left outer joins:
select ABC.*
from @TableABC as ABC left outer join
@Labels as L on L.LabelId = ABC.LabelId and L.Label = '123' left outer join
@Tags as T on T.TagId = ABC.TagId and T.Tag = '123'
where ( ABC.LabelId is NULL or L.LabelId is not NULL ) and ( ABC.TagId is NULL or T.TagId is not NULL );
提示:始终将有用的表别名与连接一起使用,并将它们应用于所有列。
答案 2 :(得分:0)
使用联盟
on TableABC.label_id = Lables.id or TableABC.label_id is null
ec2-metadata
会返回太多行