5

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,因为 order d.id desc 只会给出前 1st id,即 30,然后它应该返回 dept id = 30 的员工,但它给了我所有的行和所有的部门。

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

4

3 回答 3

9

你说“在上面的查询中,我假设它应该只需要 dept=30,因为 order d.id desc 只会给出前 1st 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关键字意味着内部查询(逻辑上)为外部查询的每一行调用一次。对于内部查询中发生的事情,了解 a 的子句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

在这里,逻辑已通过使用另一个嵌套子查询重新排序,以确保ORDER BY, then在子句之前TOP 1应用。(请注意,这通常不是推荐的方法,因为嵌套的子查询会妨碍可读性,我只是在这里使用它来保留和保留原始结构的其余部分)。WHERECROSS APPLY

于 2013-12-16T15:02:09.917 回答
1

为了扩展 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,部门 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
于 2013-12-16T14:55:43.823 回答
-2

要在没有交叉应用的情况下解决此问题,请使用子查询。但是,在您的示例中,它只会返回一行,假设 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 将它与许多动态管理视图 (DMV) 一起使用,这些动态管理视图 (DMV) 是表值函数 (TVF)

你想要的是一个类似于 LEFT JOIN的OUTER APPLY 。

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

于 2013-12-16T14:41:14.717 回答