用过order by newid()吧? 发现问题了吗?谁给解释一下。

txlicenhe 2005-12-27 08:20:14
declare @tb table (aa int,bb char(1))
insert @tb values(1,'A')
insert @tb values(1,'B')
insert @tb values(1,'C')
insert @tb values(1,'D')
insert @tb values(2,'A')
insert @tb values(2,'B')
insert @tb values(2,'C')
insert @tb values(2,'D')
insert @tb values(3,'A')
insert @tb values(3,'B')
insert @tb values(3,'C')
insert @tb values(3,'D')

-- 执行语句1 ,多次执行都没问题
select top 1 * from @tb order by newid()

-- 执行语句2 ,多次执行都没问题
select * from @tb a
where bb in (select top 1 bb from @tb
where aa = a.aa)

-- 执行语句3 ,多执行几次,问题出来了
select * from @tb a
where bb in (select top 1 bb from @tb
where aa = a.aa order by newid())

-- 谁给解释一下
...全文
602 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
luckyprg 2006-01-04
  • 打赏
  • 举报
回复
可惜,今天才看到这个问题。
之前也遇到过这样的问题。
我写了一个分页的存储过程,3个select top组合的,当排序字段用newid()时总是没有数据,只能得出总记录数。后来检查了N久才搞掂,呵呵~~~
mislrb 2005-12-28
  • 打赏
  • 举报
回复
不知道你们怎么会不一样,
我执行楼主的第3个SQL N次,
结果永远都是:

aa bb
----------- ----
1 A
2 A
3 A

是你们见鬼了,还是我见鬼了
txlicenhe 2005-12-28
  • 打赏
  • 举报
回复
暂时以子陌的答案为准。

declare @tb table (aa int,bb char(1))
insert @tb values(1,'A')
insert @tb values(1,'B')
insert @tb values(1,'C')
insert @tb values(1,'D')
insert @tb values(2,'A')
insert @tb values(2,'B')
insert @tb values(2,'C')
insert @tb values(2,'D')
insert @tb values(3,'A')
insert @tb values(3,'B')
insert @tb values(3,'C')
insert @tb values(3,'D')

-- 执行语句1 ,多次执行都没问题
select top 1 * from @tb order by newid()

-- 执行语句2 ,多次执行都没问题
select * from @tb a
where bb in (select top 1 bb from @tb
where aa = a.aa)

-- 执行语句3 ,多执行几次,问题出来了
select * from @tb a
where bb in (select top 1 bb from @tb
where aa = a.aa order by newid())

-- 执行语句4(把in 改成=) ,也没有问题
select * from @tb a
where bb = (select top 1 bb from @tb
where aa = a.aa order by newid())



txlicenhe 2005-12-28
  • 打赏
  • 举报
回复
不知为什么昨天想回复就是没法回,今天终于可以了。

还是没有一个合理的解释啊。

OracleRoob 2005-12-28
  • 打赏
  • 举报
回复
up!
DreamStrat 2005-12-28
  • 打赏
  • 举报
回复
因为子查询语句中存在where语句,而且是引用了 a.aa,所以SQL对其进行了优化,而且正因为存在这样一个条件,所以子查询在每次执行比较时都更新了一次,即tb a表有多少条记录,它就执行了多少次(而这个执行的结果却是不固定的)

之所以这样说的原因,我们可以在查询分析器中分析一下很容易地看出来,仔细比较一下下面两行SQL的[显示预计的执行计划](选中SQL语句-->Ctrl+L)就明白了(为方便调试,将@tb改为物理表):

-- 执行语句3 ,多执行几次,问题出来了
select * from tb a
where bb in (select top 1 bb from tb
where aa = a.aa order by newid())
--****这行语句,先执行 aa=a.aa,然后执行Order by语句,那么在此子数据集就产生了不确定性,最后执行的才是bb之间的比较

-- 执行语句4(把in 改成=) ,也没有问题
select * from tb a
where bb = (select top 1 bb from tb
where aa = a.aa order by newid())
--**而这行语句,先执行 aa=a.aa,然后执行的却是bb之间的比较,之后才是Order by语句
Andy__Huang 2005-12-28
  • 打赏
  • 举报
回复
UP
pbsql 2005-12-28
  • 打赏
  • 举报
回复
区别在于:
3是Left Semi Join
4是Inner Join
pbsql 2005-12-28
  • 打赏
  • 举报
回复
着重比较一下3、4:
if exists(select * from sysobjects where xtype='U' and name='tb')
drop table tb
go
create table tb(aa int,bb char(1))
insert tb values(1,'A')
insert tb values(1,'B')
insert tb values(1,'C')
insert tb values(1,'D')
insert tb values(2,'A')
insert tb values(2,'B')
insert tb values(2,'C')
insert tb values(2,'D')
insert tb values(3,'A')
insert tb values(3,'B')
insert tb values(3,'C')
insert tb values(3,'D')
GO
SET SHOWPLAN_ALL ON
GO
select * from tb a
where bb in (select top 1 bb from tb
where aa = a.aa order by newid())
GO
select * from tb a
where bb = (select top 1 bb from tb
where aa = a.aa order by newid())
GO
SET SHOWPLAN_ALL OFF
GO
while1228 2005-12-27
  • 打赏
  • 举报
回复
mark
yjzhg 2005-12-27
  • 打赏
  • 举报
回复
zhang_yzy 2005-12-27
  • 打赏
  • 举报
回复
我估计是这样的,
-------------------
只能从查询语句的解析步骤上假设了,

select * from @tb a
where bb in (select top 1 bb from @tb
where aa = a.aa order by newid())
0、假设SQL是按顺序取@Tb记录
1、SQL先取第一条记录 1,A
用他们带入where 中,即A in (select top 1 bb from @tb
where aa =1 order by newid())
那么满足与不满足的情况就都存在了
2、SQL继续取下下一条记录 1,B
同样带入
3、一直到最后,也就可以解释这种情况了
新鲜鱼排 2005-12-27
  • 打赏
  • 举报
回复
怎么会出现为空的情况哪??
冷箫轻笛 2005-12-27
  • 打赏
  • 举报
回复
非常支持libin_ftsafe(子陌红尘)的理解
这个问题以前我也遇到过
个人理解也是对于语句3
select * from @tb a
where bb in (select top 1 bb from @tb
where aa = a.aa order by newid())

执行的时候会遍历a的所有记录,然后对a的每一条记录都执行select top 1 bb from @tb
where aa = a.aa order by newid()这个语句

因为是随机的,所以可能得出的bb是好多值
新鲜鱼排 2005-12-27
  • 打赏
  • 举报
回复
我不太明白where aa = a.aa的作用
xueguang 2005-12-27
  • 打赏
  • 举报
回复
可是为什么有时候的返回结果又是空的呢,看来要达到目的就要这么写了
select a.* from @tb a,(select top 1 aa,bb from @tb order by newid()) b
where a.aa=b.aa and a.bb=b.bb
pbsql 2005-12-27
  • 打赏
  • 举报
回复
没有问题啊:语句2、3中的子查询,对于每条记录都会执行一次,语句2的子查询返回的值是固定的所以主查询记录也是固定的,而语句3的子查询返回的值不固定当然主查询记录也不固定了

这个与用exists的道理一样
lsqkeke 2005-12-27
  • 打赏
  • 举报
回复
to DreamStrat(梦启动的摇篮…)
------------------------------
select top 1 * from @tb where aa = 1 order by newid()
执行这个语句得到的结果集是唯一的一条满足 aa = 1的记录(我们不关心是具体的哪一条)

那么楼主的SQL语句中,关键是子查询返回的BB值有多个!!!!!!!
newid排序后 不管满足aa=a.aa条件的记录是那两行记录匹配,是不是一但获取top 1该子查询就返回呢???
子陌红尘 2005-12-27
  • 打赏
  • 举报
回复
我的分析:
在查询过程中,SQL Server查询计划为@tb表变量中每条记录都执行了一次子查询,而每次子查询返回的bb值都是随机的,可能满足当前记录,也可能不满足。
新鲜鱼排 2005-12-27
  • 打赏
  • 举报
回复
select * from @tb a
where bb in (select top 1 bb from @tb
order by newid())
我觉得where aa = a.aa是一个多余的定义,随机的事件如果多余的定义太多的话当然会有问题,
加载更多回复(12)

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧