注意其中的***** xx *******部分问题描述: 1.如果将aa处的full join,改为join,则出错 2.如果将aa处的full join,改为join,同时修改bb处,取消条件: and aa.afields=bb.bfields 则正确,大家分析一下是什么原因?
补充2: 若将 aa,bb的内容分别先存到临时表,再用临时表来join也是可以的 补充3: 最后几行 on aa.id=bb.id and aa.afields=bb.bfields --********** bb ********* where aa.id is not null ) b on a.id=b.id 若改成on aa.id=bb.id --and aa.afields=bb.bfields --********** bb ********* where aa.id is not null ) b on a.id=b.id也是可以的,但结果就不对了。
这么长?那么多substring,头晕。大概看了一下,好像是因为join 消除了哪笔记录。
哦,长是长点,但结构清晰,且能COPY到查询分析器中直接运行。
不对,根本没错。 我把 aa、bb视图内容 Insert 到一张临时表里就什么都好使了!!
--帮你断下括号:不然没对齐每办法快速定位: declare @t1 table(id int,afields varchar(30)) insert into @t1 select 1,'A+B+C' union all select 2,'B+C' union all select 3,'A+C' union all select 4,'C' union all select 5,'B+A'declare @t2 table(id int,bfields varchar(30)) insert into @t2 select 1,'A+D+C' union all select 2,'A+W' union all select 3,'D+C' union all select 4,'D+F+C' union all select 5,'C+D'--查询处理 select a.* from @t2 a join ( select distinct bb.id from ( select a.id,afields=substring(afields,b.id,charindex('+',afields+'+',b.id)-b.id) from @t1 a, ( select id=a.id+b.id from ( select id=0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 )a, ( select id=0 union all select 10 union all select 20 union all select 30 union all select 40 union all select 50 union all select 60 union all select 70 union all select 80 union all select 90 ) b ) b where substring('+'+afields,b.id,1)='+' ) aa full join ( --*************** aa *********************** select a.id,bfields=substring(bfields,b.id,charindex('+',bfields+'+',b.id)-b.id) from @t2 a , ( select id=a.id+b.id from ( select id=0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 )a, ( select id=0 union all select 10 union all select 20 union all select 30 union all select 40 union all select 50 union all select 60 union all select 70 union all select 80 union all select 90 ) b ) b where substring('+'+bfields,b.id,1)='+' )bb on aa.id=bb.id and aa.afields=bb.bfields --********** bb ********* where aa.id is not null ) b on a.id=b.id/*--测试结果id bfields ----------- ------------------------------ 1 A+D+C 3 D+C 4 D+F+C(所影响的行数为 3 行) --*/
好玩,我妄图用left join 和right join 找出问题出在哪边,但但但。。真好玩。。
好像是Cross join 导致的问题。他在分析的时候可能以为有外连接,然后不知道怎么执行执行出了错误结果。。指定了外连接以后分析的话直接用外连接分析,它就不出错了!!! 我 把 ( select id=a.id+b.id from ( select id=0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 )a, ( select id=0 union all select 10 union all select 20 union all select 30 union all select 40 union all select 50 union all select 60 union all select 70 union all select 80 union all select 90 ) b ) 这个视图替换以后就好使了。 中间我 尝试使用不同的outer join 来确定问题所在,发现排除了 aa.afields =bb.bfields 条件进行join 时写法是标准写法时无差别均可得出结果,使用 *= 或=* 时会提示“在包含已联接的表的查询中,不能指定外联接操作符。”SQL Servr 疯了。
我也有个很怪的问题 执行下面的语句 -------------------------------------------------- select 厂内料号 from ( select 厂内料号,convert(int,substring(厂内料号,charindex('-',厂内料号,1)+1,len(厂内料号)-8-charindex('-',厂内料号,1))) as 层数,floor(round(1/单PCS重量,0)) as 块数 --注意***** floor(round(1/单PCS重量,0)) from tblproduct_num where 单PCS重量 is not null and 单PCS重量<>0 ) as a where a.层数='4' and a.块数=6 --------------------------------------------- 报错 Divide by zero error encountered.但我执行 select 厂内料号,convert(int,substring(厂内料号,charindex('-',厂内料号,1)+1,len(厂内料号)-8-charindex('-',厂内料号,1))) as 层数,floor(round(1/单PCS重量,0)) as 块数 from tblproduct_num where 单PCS重量 is not null and 单PCS重量<>0又没问题郁闷了半天 不知道sql server中嵌套语句是如何判断where 条件的
--还有一个order by的问题,供大家研究,注意其中的********标注部分 --测试数据 create table a表([产品编号] varchar(4),[产品名称] varchar(10),[产品种类] varchar(1)) insert into a表 select '1001','a01','a' union all select '1002','a02','a' union all select '1003','a03','a' union all select '1004','b01','b' union all select '1005','b02','b' union all select '1006','b03','b'create table b表([客户编号] varchar(3),[产品编号] varchar(4),[数量] int,[时间] datetime) insert into b表 select '001','1001',100,'2003-07-18' union all select '001','1003',200,'2003-11-02' union all select '001','1005',60,'2003-12-06' union all select '002','1002',30,'2003-01-01 ' union all select '002','1005',500,'2003-12-07' union all select '003','1003',70,'2003-02-05' union all select '003','1004',500,'2003-06-02' union all select '003','1006',20,'2003-06-02' union all select '004','1002',110,'2003-02-09' union all select '005','1001',22,'2003-03-07' union all select '005','1006',20,'2003-06-01' go--处理的存储过程 create proc p_qry @开始年月 varchar(6), --查询的开始年月,格式:YYYYMM @结束年月 varchar(6)=null, --查询的结束年月,如果不指定(NULL),则与结束年月相同 @产品种类 varchar(10)='<全部>' --查询的产品种类,为<全部>是,不限制产品种类 as set nocount on declare @s varchar(8000),@tj varchar(1000) ,@d1 datetime,@d2 datetime,@i intselect @s='' ,@d1=@开始年月+'01' ,@d2=dateadd(month,1,isnull(@结束年月,@开始年月)+'01') ,@tj=case @产品种类 when '<全部>' then '' else 'where 产品种类='''+@产品种类+'''' endselect @s=@s+',['+left(dt,4)+'年'+right(dt,2)+'月]=sum(case 时间 when ''' +dt+''' then 数量 else 0 end)' from( select dt=convert(varchar(6),dateadd(month,a.id+b.id,@d1),112) from( select id=0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 union all select 10 union all select 11 ) a,(select id=0 union all select 12 union all select 24 union all select 36 union all select 48 union all select 60 union all select 72 union all select 84 union all select 96 union all select 108 union all select 120 union all select 132 ) b where (a.id+b.id)<datediff(month,@d1,@d2) ) a --order by dt --********* 不加order by正常.加上则不能出现正确的结果 ********exec('select 产品名称=case grouping(产品名称) when 1 then ''合计'' else 产品名称 end '+@s+',合计=sum(数量) from( select a.产品名称,b.数量,时间=convert(varchar(6),b.时间,112) from a表 a join b表 b on a.产品编号=b.产品编号 '+@tj+' ) a group by 产品名称 with rollup') go--调用示例 exec p_qry '200311','200402' go--删除测试 drop proc p_qry drop table a表,b表/*--测试结果 产品名称 2003年11月 2003年12月 2004年01月 2004年02月 合计 ---------- ----------- ----------- ----------- ----------- ----------- a01 0 0 0 0 122 a02 0 0 0 0 140 a03 200 0 0 0 270 b01 0 0 0 0 500 b02 0 560 0 0 560 b03 0 0 0 0 40 合计 200 560 0 0 1632 --*/
昏, 不过有一点:加不加order by 的结果不一样是肯定的。测试: create table t1(a int) insert t1 values(3) insert t1 values(1) insert t1 values(2)declare @s varchar(10) set @s = '' select @s = @s + cast(a as varchar) from t1 order by a select @s
---------- 312(所影响的行数为 1 行)declare @s varchar(10) set @s = '' select @s = @s + cast(a as varchar) from t1 order by a select @s ---------- 123(所影响的行数为 1 行)
select @s=@s+',['+left(dt,4)+'年'+right(dt,2)+'月]=sum(case 时间 when ''' +dt+''' then 数量 else 0 end)' from( select top 100 percent dt=convert(varchar(6),dateadd(month,a.id+b.id,@d1),112) from( select id=0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9 union all select 10 union all select 11 ) a,(select id=0 union all select 12 union all select 24 union all select 36 union all select 48 union all select 60 union all select 72 union all select 84 union all select 96 union all select 108 union all select 120 union all select 132 ) b where (a.id+b.id)<datediff(month,@d1,@d2) order by dt) a order by dt 这种内部联接生成的表, 且ORDER BY不是本身的列的时候,默认为ORDER BY最后一个。 在内部先排序,就行了。
反正是可以了,我也不知道是BUG,还是我概念没清楚。
declare @s varchar(8000) set @s=''只要加上top 100 percent就行了! 应该.可能.也许.说不定是语句自动优化过程中的问题。 declare @s varchar(8000) set @s='' select @s=@s+s from ( select top 100 percent rtrim(a.id+B.id)+',' as s from (select id=0 union all select 1 union all select 2) A, (select id=0 union all select 12 union all select 24) b ) s order by s print @s
同样的道理,你标题上语句: 上下各加上: top 100 percentselect top 100 percent a.id,afields=substring(afields,b.id,charindex('+',afields+'+',b.id)-b.id)用JOIN也不会了。
再测试几个: 1:ok declare @s varchar(8000) set @s='' select @s=@s+s from ( select a.id as id1,b.id as id2, rtrim(a.id+B.id)+',' as s from (select id=0 union all select 1 union all select 2) A, (select id=0 union all select 12 union all select 24) b ) s order by id1,id2 print @s2:不对 declare @s varchar(8000) set @s='' select @s=@s+s from ( select a.id as id1,b.id as id2, rtrim(a.id+B.id)+',' as s from (select id=0 union all select 1 union all select 2) A, (select id=0 union all select 12 union all select 24) b ) s order by id1,id2,s print @s3:不对 declare @s varchar(8000) set @s='' select @s=@s+s from ( select a.id as id1,b.id as id2, rtrim(a.id+B.id)+',' as s from (select id=0 union all select 1 union all select 2) A, (select id=0 union all select 12 union all select 24) b ) s order by id1+id2 print @s
果然内部机制是游标的机制。加上DISTINCT也可以。只要子查询中有:order by ,top,distinct三个关键字中的一个就行。当然order by 在本题子查询内部不能用。 准一个游标机制。
程序太繁琐,看不过来哦!但是出错的方向很明显!select ... from a,b where a.x=b.x 与 select ... from a inner join b on a.x=b.x是根本不同的查询。我从来不用后者含混的关联操作。如果用,就请搞清楚它的查询规划生成的具体查询方法——与内连接本来就是不同的!看起来逻辑相同,其实含混的关联操作往往先将很多冗余数据关联起来,然后再剔除他们,很自然,与先选择记录后关联的规范的写法相比会生成很多导致运行失败的记录。 最后那个问题,在子查询中不能使用order by,除非使用了 top ... 的查询形式,这在SQL Server手册中是白纸黑字写明了的。
1.如果将aa处的full join,改为join,则出错
2.如果将aa处的full join,改为join,同时修改bb处,取消条件:
and aa.afields=bb.bfields
则正确,大家分析一下是什么原因?
补充3:
最后几行
on aa.id=bb.id and aa.afields=bb.bfields --********** bb *********
where aa.id is not null
) b on a.id=b.id
若改成on aa.id=bb.id --and aa.afields=bb.bfields --********** bb *********
where aa.id is not null
) b on a.id=b.id也是可以的,但结果就不对了。
我把 aa、bb视图内容 Insert 到一张临时表里就什么都好使了!!
declare @t1 table(id int,afields varchar(30))
insert into @t1
select 1,'A+B+C'
union all select 2,'B+C'
union all select 3,'A+C'
union all select 4,'C'
union all select 5,'B+A'declare @t2 table(id int,bfields varchar(30))
insert into @t2
select 1,'A+D+C'
union all select 2,'A+W'
union all select 3,'D+C'
union all select 4,'D+F+C'
union all select 5,'C+D'--查询处理
select a.*
from @t2 a
join
(
select distinct bb.id from
(
select a.id,afields=substring(afields,b.id,charindex('+',afields+'+',b.id)-b.id)
from @t1 a, (
select id=a.id+b.id from
(
select id=0 union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
)a,
(
select id=0 union all select 10 union all select 20 union all select 30 union all select 40
union all select 50 union all select 60 union all select 70 union all select 80 union all select 90
) b
) b where substring('+'+afields,b.id,1)='+'
) aa
full join
( --*************** aa ***********************
select a.id,bfields=substring(bfields,b.id,charindex('+',bfields+'+',b.id)-b.id)
from @t2 a ,
(
select id=a.id+b.id from
(
select id=0 union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
)a,
(
select id=0 union all select 10 union all select 20 union all select 30 union all select 40
union all select 50 union all select 60 union all select 70 union all select 80 union all select 90
) b
) b where substring('+'+bfields,b.id,1)='+'
)bb on aa.id=bb.id and aa.afields=bb.bfields --********** bb *********
where aa.id is not null
) b on a.id=b.id/*--测试结果id bfields
----------- ------------------------------
1 A+D+C
3 D+C
4 D+F+C(所影响的行数为 3 行)
--*/
我 把
(
select id=a.id+b.id from
(
select id=0 union all select 1 union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
)a,
(
select id=0 union all select 10 union all select 20 union all select 30 union all select 40
union all select 50 union all select 60 union all select 70 union all select 80 union all select 90
) b
)
这个视图替换以后就好使了。
中间我 尝试使用不同的outer join 来确定问题所在,发现排除了
aa.afields =bb.bfields 条件进行join 时写法是标准写法时无差别均可得出结果,使用 *= 或=* 时会提示“在包含已联接的表的查询中,不能指定外联接操作符。”SQL Servr 疯了。
执行下面的语句
--------------------------------------------------
select 厂内料号
from
(
select 厂内料号,convert(int,substring(厂内料号,charindex('-',厂内料号,1)+1,len(厂内料号)-8-charindex('-',厂内料号,1))) as 层数,floor(round(1/单PCS重量,0)) as 块数 --注意***** floor(round(1/单PCS重量,0))
from tblproduct_num where 单PCS重量 is not null and 单PCS重量<>0
) as a
where a.层数='4' and a.块数=6
---------------------------------------------
报错
Divide by zero error encountered.但我执行
select 厂内料号,convert(int,substring(厂内料号,charindex('-',厂内料号,1)+1,len(厂内料号)-8-charindex('-',厂内料号,1))) as 层数,floor(round(1/单PCS重量,0)) as 块数 from tblproduct_num where 单PCS重量 is not null and 单PCS重量<>0又没问题郁闷了半天
不知道sql server中嵌套语句是如何判断where 条件的
--测试数据
create table a表([产品编号] varchar(4),[产品名称] varchar(10),[产品种类] varchar(1))
insert into a表
select '1001','a01','a'
union all select '1002','a02','a'
union all select '1003','a03','a'
union all select '1004','b01','b'
union all select '1005','b02','b'
union all select '1006','b03','b'create table b表([客户编号] varchar(3),[产品编号] varchar(4),[数量] int,[时间] datetime)
insert into b表
select '001','1001',100,'2003-07-18'
union all select '001','1003',200,'2003-11-02'
union all select '001','1005',60,'2003-12-06'
union all select '002','1002',30,'2003-01-01 '
union all select '002','1005',500,'2003-12-07'
union all select '003','1003',70,'2003-02-05'
union all select '003','1004',500,'2003-06-02'
union all select '003','1006',20,'2003-06-02'
union all select '004','1002',110,'2003-02-09'
union all select '005','1001',22,'2003-03-07'
union all select '005','1006',20,'2003-06-01'
go--处理的存储过程
create proc p_qry
@开始年月 varchar(6), --查询的开始年月,格式:YYYYMM
@结束年月 varchar(6)=null, --查询的结束年月,如果不指定(NULL),则与结束年月相同
@产品种类 varchar(10)='<全部>' --查询的产品种类,为<全部>是,不限制产品种类
as
set nocount on
declare @s varchar(8000),@tj varchar(1000)
,@d1 datetime,@d2 datetime,@i intselect @s=''
,@d1=@开始年月+'01'
,@d2=dateadd(month,1,isnull(@结束年月,@开始年月)+'01')
,@tj=case @产品种类 when '<全部>' then ''
else 'where 产品种类='''+@产品种类+'''' endselect @s=@s+',['+left(dt,4)+'年'+right(dt,2)+'月]=sum(case 时间 when '''
+dt+''' then 数量 else 0 end)'
from(
select dt=convert(varchar(6),dateadd(month,a.id+b.id,@d1),112)
from(
select id=0 union all select 1 union all select 2
union all select 3 union all select 4 union all select 5
union all select 6 union all select 7 union all select 8
union all select 9 union all select 10 union all select 11
) a,(select id=0 union all select 12 union all select 24
union all select 36 union all select 48 union all select 60
union all select 72 union all select 84 union all select 96
union all select 108 union all select 120 union all select 132
) b where (a.id+b.id)<datediff(month,@d1,@d2)
) a --order by dt --********* 不加order by正常.加上则不能出现正确的结果 ********exec('select 产品名称=case grouping(产品名称) when 1 then ''合计'' else 产品名称 end
'+@s+',合计=sum(数量)
from(
select a.产品名称,b.数量,时间=convert(varchar(6),b.时间,112)
from a表 a join b表 b on a.产品编号=b.产品编号
'+@tj+'
) a group by 产品名称 with rollup')
go--调用示例
exec p_qry '200311','200402'
go--删除测试
drop proc p_qry
drop table a表,b表/*--测试结果
产品名称 2003年11月 2003年12月 2004年01月 2004年02月 合计
---------- ----------- ----------- ----------- ----------- -----------
a01 0 0 0 0 122
a02 0 0 0 0 140
a03 200 0 0 0 270
b01 0 0 0 0 500
b02 0 560 0 0 560
b03 0 0 0 0 40
合计 200 560 0 0 1632
--*/
不过有一点:加不加order by 的结果不一样是肯定的。测试:
create table t1(a int)
insert t1 values(3)
insert t1 values(1)
insert t1 values(2)declare @s varchar(10)
set @s = ''
select @s = @s + cast(a as varchar) from t1 order by a
select @s
----------
312(所影响的行数为 1 行)declare @s varchar(10)
set @s = ''
select @s = @s + cast(a as varchar) from t1 order by a
select @s
----------
123(所影响的行数为 1 行)
+dt+''' then 数量 else 0 end)'
from(
select top 100 percent
dt=convert(varchar(6),dateadd(month,a.id+b.id,@d1),112)
from(
select id=0 union all select 1 union all select 2
union all select 3 union all select 4 union all select 5
union all select 6 union all select 7 union all select 8
union all select 9 union all select 10 union all select 11
) a,(select id=0 union all select 12 union all select 24
union all select 36 union all select 48 union all select 60
union all select 72 union all select 84 union all select 96
union all select 108 union all select 120 union all select 132
) b where (a.id+b.id)<datediff(month,@d1,@d2)
order by dt) a
order by dt 这种内部联接生成的表,
且ORDER BY不是本身的列的时候,默认为ORDER BY最后一个。
在内部先排序,就行了。
set @s=''只要加上top 100 percent就行了!
应该.可能.也许.说不定是语句自动优化过程中的问题。
declare @s varchar(8000)
set @s=''
select @s=@s+s from (
select top 100 percent rtrim(a.id+B.id)+',' as s
from
(select id=0 union all select 1 union all select 2) A,
(select id=0 union all select 12 union all select 24) b
) s
order by s
print @s
上下各加上:
top 100 percentselect top 100 percent
a.id,afields=substring(afields,b.id,charindex('+',afields+'+',b.id)-b.id)用JOIN也不会了。
就是SQLSERVER的自动优化程序中的内部处理机制问题。
SQLSERVER不一定是先生成结果再处理的。
用了TOP 100 percent强迫它先生成结果集。再联接。
top 100 percent
j9988 说:
就是SQLSERVER的自动优化程序中的排序问题。SQLSERVER不一定是先生成结果再处理的。
马可 说:
有意思
j9988 说:
是边生成结果边处理。
j9988 说:
所以会出现这个问题。
j9988 说:
用了TOP 100 percent强迫它先生成结果集。再联接。
j9988 说:
这样就好了。
马可 说:
不知道哪些情况是先生成结果集再联接哪些情况下是先连接后生成结果集
马可 说:
SQL中有没有这方面的介绍资料
j9988 说:
就是。但以后碰到这种两表以上联接生成结果集,且列也不是原列时(组合生成的)。就要注意了
马可 说:
刚试了一下第1个问题,加上top percent就行
马可 说:
发现好多超难问题都是你搞定的
马可 说:
想不服都难
j9988 说:
我中午没机器测,晚上才有。不过我想象它的处理机制。因为我常为一个语句的效率测相当长时间。
马可 说:
这种问题看来只能以后注意点
j9988 说:
特别有两表组合还要当子查询且列是:a.field+B.field时还要排序时才会
j9988 说:
其它情况不会。
j9988 说:
比如刚才的如果是order by A.id,B.id就不会。但order by A.id+B.id就会。
马可 说:
确实如此
1:ok
declare @s varchar(8000)
set @s=''
select @s=@s+s from (
select a.id as id1,b.id as id2, rtrim(a.id+B.id)+',' as s
from
(select id=0 union all select 1 union all select 2) A,
(select id=0 union all select 12 union all select 24) b
) s
order by id1,id2
print @s2:不对
declare @s varchar(8000)
set @s=''
select @s=@s+s from (
select a.id as id1,b.id as id2, rtrim(a.id+B.id)+',' as s
from
(select id=0 union all select 1 union all select 2) A,
(select id=0 union all select 12 union all select 24) b
) s
order by id1,id2,s
print @s3:不对
declare @s varchar(8000)
set @s=''
select @s=@s+s from (
select a.id as id1,b.id as id2, rtrim(a.id+B.id)+',' as s
from
(select id=0 union all select 1 union all select 2) A,
(select id=0 union all select 12 union all select 24) b
) s
order by id1+id2
print @s
你怎么突然出现了,明摆着妨碍我讲话吗,看来有几颗星星的都不是好人!
不是斑竹也这样!ps:受 j老师的启发也试了下第一个问题,好玩。
无上光荣,高兴ing...
宝马撞人白撞,你们没意见,我多上几贴你们就吵。
记下了,下次有这种问题就用来和星星们抢楼。
你用宝马撞我当然有意见,不过用钱砸我我就不敢吭气了!
realgz(realgz) ( ) 信誉:105 2004-01-08 20:57:00 得分:0
楼上 握手先!
怎么...
斑竹灌水也牛比!
准一个游标机制。
与
select ... from a inner join b on a.x=b.x是根本不同的查询。我从来不用后者含混的关联操作。如果用,就请搞清楚它的查询规划生成的具体查询方法——与内连接本来就是不同的!看起来逻辑相同,其实含混的关联操作往往先将很多冗余数据关联起来,然后再剔除他们,很自然,与先选择记录后关联的规范的写法相比会生成很多导致运行失败的记录。
最后那个问题,在子查询中不能使用order by,除非使用了 top ... 的查询形式,这在SQL Server手册中是白纸黑字写明了的。