繁体   English   中英

SQL Server交叉应用不起作用?

[英]SQL Server cross apply not working?

http://sqlfiddle.com/#!3/78273/1

create table emptb1
(
id int,
name varchar(20),
dept int
)

insert into emptb1 values (1,'vish',10);
insert into emptb1 values (2,'vish',10);
insert into emptb1 values (3,'vish',30);
insert into emptb1 values (4,'vish',20);

create table depttb1
(
id int,
name varchar(20)
)

insert into depttb1 values(10,'IT')
insert into depttb1 values(20,'AC')
insert into depttb1 values(30,'LIC')

select * from emptb1

select e.id, e.name, a.id
from emptb1 e
cross apply
(
select top 1 * from depttb1 d
where d.id = e.dept
order by d.id desc
) a

我试图学习交叉应用,因为它类似于内连接,但与函数一起工作。

在上面的查询我假设它应该只采取dept = 30因为订单d.id desc将只给出top的第一个id为30然后它应该返回dept id = 30的员工但是它给了我所有的行和所有的DEPTID。

查询有什么问题,或者我错误地解释了交叉申请的概念。

你说“ 在上面的查询我假设它应该只采取dept = 30因为订单d.id desc将只给出top的第一个id为30然后它应该返回dept id = 30的员工 ”。

这不是它的工作原理。 这是您的查询(为了清晰起见,重新格式化了一点):

select e.id, e.name, a.id
from   emptb1 e
cross apply
(
    select top 1 * 
    from depttb1 d
    where d.id = e.dept
    order by d.id desc
) a

APPLY关键字表示内部查询(逻辑上)为外部查询的每一行调用一次。 对于内部查询中发生的事情,理解执行SELECT子句的逻辑顺序是有帮助的。这个顺序是:

  1. FROM子句
  2. WHERE子句
  3. SELECT
  4. ORDER BY子句
  5. TOP运营商

请注意,在内部查询中, TOP运算符最后应用于WHERE子句之后。 这意味着where d.id = e.dept将首先减小内行那些d.id的匹配e.dept外排的(这不一定是30),然后对它们进行排序,然后返回第一个。 为外部查询中的每一行执行此操作 显然,他们中的许多人不会是30

你想要的更像是这个(仍然保留了CROSS APPLY ):

select e.id, e.name, a.id
from   emptb1 e
cross apply
(
    select top 1 * 
    from
    (
        select top 1 * 
        from depttb1 d
        order by d.id desc
    ) b
    where b.id = e.dept
) a

这里,逻辑已经通过使用另一个嵌套的子查询进行了重新排序,该子查询确保在WHERE子句之前应用ORDER BY ,然后应用TOP 1 (请注意,这通常不建议这样做,因为嵌套的子查询会妨碍可读性,我只是在这里使用它来保留CROSS APPLY并保留原始结构的其余部分)。

为了夸大Damien的评论,内部查询:

select top 1 * from depttb1 d
where d.id = e.dept
order by d.id desc

将在外部查询中的每一行运行:

select e.id, e.name, a.id
from emptb1 e

因此,您将始终从每行的内部查询中获得匹配。 我认为你期望内部查询只运行一次,但这不是APPLY作用。

因此,从外部查询的第一行开始,ID为1,dept id为10,您的内部查询将转换为:

select top 1 * from depttb1 d
where d.id = 10  //this is the dept id for the current row from your outer query
order by d.id desc

要在没有交叉应用的情况下解决此问题,请使用子查询。 但是在您的示例中,它只返回一行,最后一个部门输入,假设id值正在增加。

-- Using a sub query to find max dept
select e.id, e.name
from emptb1 e
where e.dept in
(
select top 1 id 
from depttb1 
order by id desc
)

CROSS APPLY背后的想法有点像CROSS JOIN。 这将返回所有行。 它由DBA用于许多表值函数(TVF)的动态管理视图(DMV)

你想要的是一个外部应用,有点像LEFT JOIN。

select e.id, e.name
from emptb1 e
outer apply 
    (
    select top 1 d.id from depttb1 d order by d.id desc
    ) AS m (id)
where e.dept = m.id

查看我关于这些概念的文章。

交叉申请 - http://craftydba.com/?p=3767

外部申请 - http://craftydba.com/?p=3796

表值功能(内联) - http://craftydba.com/?p=3733

表值功能(多行) - http://craftydba.com/?p=3754

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM