SQL 2000 UNION ALL 子查询增加排序列报错问题

--问题帖 http://topic.csdn.net/u/20100711/22/0d933e51-d02f-4dac-b9a3-07a2e3bd283a.html
--我的思路是想通过一个函数,
--传入统计的列数@COLNUM,然后根据UNION ALL分解后,增加一个按值从大到小的排序列NUM ,
--利用NUM<=@COLNUM来统计列和,效率其实不怎么好,对表的扫描过多!!!!
--(还有一思路,想利用COL1+','+COL2...,通过传入一个列字符串,来统计列值和,貌似比较难,请高手指点)

--正题

--> 生成测试数据表: [st_rain_s]
IF OBJECT_ID('[st_rain_s]') IS NOT NULL
    DROP TABLE [st_rain_s]
GO
create table st_rain_s
(
stcd char(8)
,TM datetime
,DYP DEC(18,2)
,p8 DEC(18,2)
,p9 DEC(18,2)
,p10 DEC(18,2)
,p11 DEC(18,2)
)

insert st_rain_s
select '90800001','2010-7-8 21:02:58',10,4,2,3,4
union all
select '90800001','2010-7-9 21:02:58',20,10,3,3,4

--1 平常写法(2000),利用子查询来增加排序列
 SELECT STCD,CONVERT(CHAR(10),TM,120) TM,(RN) NUM,
  (SELECT COUNT(1) FROM  
  (
   SELECT STCD,TM,P8 AS RN FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P9 FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P10 FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P11 FROM st_rain_s
  ) T1 WHERE STCD=T.STCD  AND RN<=T.RN )
 FROM
 (
  SELECT STCD,TM,P8 AS RN FROM st_rain_s
  UNION ALL
  SELECT STCD,TM,P9 FROM st_rain_s
  UNION ALL
  SELECT STCD,TM,P10 FROM st_rain_s
  UNION ALL
  SELECT STCD,TM,P11 FROM st_rain_s
 ) T
/*
ODBC: 消息 0,级别 19,状态 1
SqlDumpExceptionHandler: 进程 60 发生了严重的异常 c0000005 EXCEPTION_ACCESS_VIOLATION。SQL Server 将终止该进程。

连接中断
*/

--结果,竟然报错,严重异常,不明白!!然后想换换临时表随便试试这种写法会不会出错,结果正常
--2
IF OBJECT_ID('TEMPDB..#T') IS NOT NULL
    DROP TABLE [#T]
GO
  
  SELECT STCD,TM,P8 AS RN,1 AS CNT INTO #T  FROM st_rain_s
  UNION ALL
  SELECT STCD,TM,P9,2 FROM st_rain_s
  UNION ALL
  SELECT STCD,TM,P10,3 FROM st_rain_s
  UNION ALL
  SELECT STCD,TM,P11,4 FROM st_rain_s

  SELECT *,
  (SELECT COUNT(1) FROM #T WHERE STCD=T.STCD AND DATEDIFF(DD,TM,T.TM)=0 AND (RN>T.RN OR (RN=T.RN AND CNT>T.CNT)))+1 NUM
   FROM #T T ORDER BY TM
/*

(所影响的行数为 8 行)

STCD     TM                                                     RN                   CNT         NUM        
-------- ------------------------------------------------------ -------------------- ----------- -----------
90800001 2010-07-08 21:02:58.000                                4.00                 1           2
90800001 2010-07-08 21:02:58.000                                2.00                 2           4
90800001 2010-07-08 21:02:58.000                                3.00                 3           3
90800001 2010-07-08 21:02:58.000                                4.00                 4           1
90800001 2010-07-09 21:02:58.000                                4.00                 4           2
90800001 2010-07-09 21:02:58.000                                3.00                 3           3
90800001 2010-07-09 21:02:58.000                                3.00                 2           4
90800001 2010-07-09 21:02:58.000                                10.00                1           1

(所影响的行数为 8 行)


*/

--临时表是正常了,但函数里边用不了,为什么那样写报错了呢?
--只能在MSDN搜索了,查了一下,没有具体讲到,不过一般报这种的,解答都是SQL版本和最新补丁的问题

--http://support.microsoft.com/kb/888799/zh-cn
--http://support.microsoft.com/kb/299575/zh-cn
--http://support.microsoft.com/kb/892451/zh-cn
--http://support.microsoft.com/kb/302664/zh-cn

SELECT @@VERSION

--我的SQL版本是无SP4的SQL2000 ,装在XP系统的企业版,没服务的
/*Microsoft SQL Server  2000 - 8.00.194 (Intel X86)
 Aug  6 2000 00:57:48
 Copyright (c) 1988-2000 Microsoft Corporation
 Desktop Engine on Windows NT 5.1 (Build 2600: Service Pack 3)


(所影响的行数为 1 行)*/

--上面的第一条子查询语句发与其他人测试,SQL2005与SQL2000 SP4均无错
--整了这么久时间,没得到个结果,不想放弃,另寻其它解决办法

----------连接查询(写法可通过上面子查询转换)

 SELECT  T.*,COUNT(T1.CNT)+1 AS COLNUM
   FROM 
  (
   SELECT STCD,TM,P8 AS RN ,1 as CNT  FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P9,2  FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P10,3 FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P11,4 FROM st_rain_s
  )  T
  LEFT JOIN
  (
   SELECT STCD,TM,P8 AS RN ,1 as CNT  FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P9,2  FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P10,3 FROM st_rain_s
   UNION ALL
   SELECT STCD,TM,P11,4 FROM st_rain_s
  )  T1
  
  ON T1.STCD=T.STCD AND DATEDIFF(DD,T.TM,T1.TM)=0 AND (T1.RN>t.RN or (T1.RN=t.RN AND T1.CNT>T.CNT))
  
  GROUP BY T.STCD,T.TM,T.RN,T.CNT
/*
STCD     TM                                                     RN                   CNT         COLNUM     
-------- ------------------------------------------------------ -------------------- ----------- -----------
90800001 2010-07-08 21:02:58.000                                2.00                 2           4
90800001 2010-07-08 21:02:58.000                                3.00                 3           3
90800001 2010-07-08 21:02:58.000                                4.00                 1           2
90800001 2010-07-08 21:02:58.000                                4.00                 4           1
90800001 2010-07-09 21:02:58.000                                3.00                 2           4
90800001 2010-07-09 21:02:58.000                                3.00                 3           3
90800001 2010-07-09 21:02:58.000                                4.00                 4           2
90800001 2010-07-09 21:02:58.000                                10.00                1           1

(所影响的行数为 8 行)

警告: 聚合或其它 SET 操作消除了空值。
*/


--既然这样可以,那么函数里就应该可以了(此方法效率不好,等待高手解决效率问题)

CREATE FUNCTION GET_MAXSUM(@stcd char(8),@TM datetime,@COLNUM INT=1)
RETURNS INT
AS
BEGIN
DECLARE @SUM INT
SET @SUM=
(
SELECT SUM(RN)
 FROM(
  
  SELECT  T.*,COUNT(T1.CNT)+1 AS COLNUM
   FROM 
  (SELECT STCD,TM,P8 AS RN ,1 as CNT  FROM st_rain_s UNION ALL SELECT STCD,TM,P9,2  FROM st_rain_s UNION ALL SELECT STCD,TM,P10,3 FROM st_rain_s UNION ALL SELECT STCD,TM,P11,4 FROM st_rain_s)  t
  LEFT JOIN
  (SELECT STCD,TM,P8 AS RN ,1 as CNT  FROM st_rain_s UNION ALL SELECT STCD,TM,P9,2  FROM st_rain_s UNION ALL SELECT STCD,TM,P10,3 FROM st_rain_s UNION ALL SELECT STCD,TM,P11,4 FROM st_rain_s)  T1
  
  ON T1.stcd=T.stcd and datediff(DD,T.tm,T1.tm)=0 and (T1.rn>t.rn or (T1.rn=t.rn and T1.cnt>T.cnt))
  
  GROUP BY T.STCD,T.TM,T.RN,T.CNT
 ) T WHERE STCD=@STCD AND DATEDIFF(DD,TM,@TM)=0 AND COLNUM<=@COLNUM
)
RETURN @SUM
END


SELECT STCD,TM,DYP,DBO.GET_MAXSUM(STCD,TM,1),DBO.GET_MAXSUM(STCD,TM,2),DBO.GET_MAXSUM(STCD,TM,3),DBO.GET_MAXSUM(STCD,TM,4) FROM st_rain_s

/*
STCD     TM                                                     DYP                                                                 
-------- ------------------------------------------------------ -------------------- ----------- ----------- ----------- -----------
90800001 2010-07-08 21:02:58.000                                10.00                4           8           11          13
90800001 2010-07-09 21:02:58.000                                20.00                10          14          17          20

(所影响的行数为 2 行)

*/


--结论,安装SQL还是要注意打好补丁,避免出现不必要的问题
--请各位高手抛砖指点子查询为何会报错的具体原因
--转载可不注明作者信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值