前几天写一个程序时,无意中遇到一个怪问题.
症状描述如下:
一台联想服务器上安装了SQLSERVER服务,在其一个数据库里写了一个存储过程.此存储过程接受一个参数,里面的语句对参数进行判断然后执行分支.
if @CustType=0
..................
else if @CustType=1
.......................
else
...............
基本结构是这样.
当我在开发的时候,用我的笔记本(康柏)上的程序连上服务器,程序里用的ADO中的Recordset来处理.当执行到rs.open时一点问题也没有.在服务器上也用此程序执行调用存储过程也没有问题,一切正常.
但是当用该单位的其他计算机(都是联想),用同样的程序访问时,当执行到存储过程中第一种情况时,所有的窗体都自动关闭,也没有任何的异常出现.
还有一种特别的情况存在,因为这个问题以前在其中一台联想机上有过,后来我去查看这个问题,查不出原因.于是我在这台计算机上安装了VS6,现场调试,可是我调试时一切正常,过了一个月后,又出现原来的问题(窗体全关闭)
这下问题大了.同样的程序在不同的计算机上执行时有时正常有时不正常,程序我相信绝对没有错.我想可能是计算机配置有问题.于是当一台计算机重做了,再试,还是不行.
想想会不会是SP没打,又会了近二个小时把所有的SP安装好.还是不正常. 再安装VS6,也没有用. 问题到底在哪里呢.我仔细想想,我曾想到会不会是联想的破机器有问题,会不会是他的CPU指令不对.(因为机器比较旧一点,再说在其他计算机上从来不出现这种问题). 我试着将程序中第一种情况的值改变一下,本来是0,改成3 这样没有问题.于是我将存储过程中的if @CustType=0 改成 if @CustType=3.问题又出现了. 会不会问题出现在这个分支,里面的逻辑肯定都是对的.看到此分支最后有一行代码,此代码是调试时用的.用来查看存储过程执行时,扭亏为执行了什么语句,也就是一句print (@SqlStr),会不会是这语句引起的.将其注释了).打开程序再试. 在刀有的计算机上通过.
原来这个问题是print语句引起的.怪就怪在有的客户端执行时不会有问题.,而出现问题时又不报任何异常,只是将客户端窗体自动关闭.看来以后写程序时一定要注意这个问题.要将调试代码清理掉. 害得我白白花了近一天的时间.
关于SQL server中字段值为null的查询
某天有个同事问我怎么在一个表中查找某字段值为null并把它替换为另一值。
开始我觉得用 select * from 表名 where 字段=null 应该可以的。
但结果是没有报错,但什么也没有显示出来。
后来又试:
select * from 表名 where len(字段)=0 结果仍是什么也没有显示。
无意中,用 select * from 表名 where 字段 is null 却对了。
看来好多知识是要多试才能知道的。呵呵。
SQL Server编写存储过程小工具(一)
eNet技术学院,版权所有
在开发数据库系统的过程中,经常要写很多的存储过程。为了统一格式和简化开发过程,我编写一些存储过程,用来自动生成存储过程。下面就为您简单介绍一下它们。其中一个用于生成Insert过程,另一个用于生成Update过程。
Sp_GenInsert
该过程运行后,它为给定的表生成一个完整的Insert过程。如果原来的表有标识列,您得将生成的过程中的SET IDNTITY_INSERT ON 语句手工删除。
语法如下
sp_GenInsert < Table Name >,< Stored Procedure Name >
以northwind 数据库为例
sp_GenInsert ’Employees’, ’INS_Employees’
最后会生成一个Insert存储过程。利用它,您可以作进一步的开发。
Sp_GenUpdate
它会为一个表生成update存储过程。语法如下:
sp_GenUpdate < Table Name >,< Primary Key >,< Stored Procedure Name >
以northwind 数据库为例
sp_GenUpdate ’Employees’,’EmployeeID’,’UPD_Employees’
运行后生成如下所示的存储过程:
Create Procedure UPD_Employees
@EmployeeID int
@LastName nvarchar(40) ,
@FirstName nvarchar(20) ,
@Title nvarchar(60) ,
@TitleofCourtesy nvarchar(50) ,
@BirthDate datetime ,
@HireDate datetime ,
@Address nvarchar(120) ,
@City nvarchar(30) ,
@Region nvarchar(30) ,
@PostalCode nvarchar(20) ,
@Country nvarchar(30) ,
@HomePhone nvarchar(48) ,
@Extension nvarchar(8) ,
@Phote image ,
@Notes ntext ,
@ReportsTo int ,
@PhotoPath nvarchar(510)
AS
UPDATE Employees
SET
LastName = @LastName,
FirstName = @FirstName,
Title = @Title,
TitleofCourtesy = @TitleofCourtesy,
BirthDate = @BirthDate,
HireDate = @HireDate,
Address = @Address,
City = @City,
Regin = @Regin,
PostalCode = @PostCode,
Country = @Country,
HomePhone = @HomePhone,
Extension = @Extension,
Photo = @Photo
Notes = @Notes,
ReportsTo = @ReportsTo,
PhotoPath = @PhotoPath
WHERE EmployeeID = @EmployeeID
使用以上的两个存储过程,节省了我不少时间。特别是在改变了表结构后,重新构造各个存储过程的过程中。您可以改写这两个程序,来自动生成别的存储过程。
SQL Server 某些条件下求某日的日期
/*需要得结果: 某一天的日期
已知条件: 这天的年,月,星期几,在这个月中处于第几周
举例说明: 希望求出2004-11-22
已知条件: 2004年, 11 月, 星期一 ,这天在11月是第四周
declare @year numeric(4),@month numeric(2),@weekday varchar(6),@week numeric(1)
set @year=2004
set @month=11
set @weekday='星期一'
set @week=4
*/
alter function RequestDate
(@year numeric(4),@month numeric(2),@weekday varchar(6),@week numeric(1))
returns datetime as
begin
declare @date1 varchar(10) --得到该月的第一天的日期
declare @month1 varchar(2)
if @month<10
set @month1='0' ltrim(rtrim(str(@month)))
else
set @month1=ltrim(rtrim(str(@month)))
set @date1=ltrim(rtrim(str(@year))) '-' @month1 '-' '01'
declare @num1 numeric(3)
declare @num2 numeric(3)
declare @num3 numeric(3)
set @num1=datepart(ww,@date1) --得到该月的第一天在该年的周数
set @num1=@num1 @week-2 --得到该月的要求得的那天所在的周数与该年的第一周第一天的周数差
set @num2=datepart(dw,dateadd(ww,@num1,'2004-01-01')) --得到日期对应的星期代号
select @num3=case @weekday
when '星期日' then 1
when '星期一' then 2
when '星期二' then 3
when '星期三' then 4
when '星期四' then 5
when '星期五' then 6
when '星期六' then 7
end
return dateadd(dd,@num3-datepart(dw,dateadd(ww,@num1,'2004-01-01')),dateadd(ww,@num1,'2004-01-01'))
end
-- select dbo.RequestDate(2004,11,'星期一',4)
如何保持Oracle数据库的优良性能
作者:Brent
Oracle数据库以其高可靠性、安全性、可兼容性,得到越来越多的企业的青睐。如何使Oracle数据库保持优良性能,这是许多数据库管理员关心的问题,根据笔者经验建议不妨针对以下几个方面加以考虑。
一、分区
根据实际经验,在一个大数据库中,数据空间的绝大多数是被少量的表所占有。为了简化大型数据库的管理,改善应用的查询性能,一般可以使用分区这种手段。所谓分区就是动态表中的记录分离到若干不同的表空间上,使数据在物理上被分割开来,便于维护、备份、恢复、事务及查询性能。当使用的时候可建立一个连接所有分区的视图,使其在逻辑上仍以一个整体出现。
1.建立分区表
Create table Employee(
EmpNo varchar2(10) primary key,
Name varchar2(30),
DeptNo Number(2)
)
Partition by range(DeptNo)
(partition PART1 values less than (11)
tablespace PART1_TS,
partition PART2 values less than(21)
tablespace PART2_TS,
partition PART3 valuse less than(31)
tablespace PART3_TS
partition PART4 values less than(MAXVALUE)
tablespace PART4_TS
);
表Employee依据DeptNo列进行分区。
2.分区索引
Create index Employee_DeptNo on Employee (DeptNo)local(
partition PART1 tablespace PART1_NDX_TS,
partition PART2 tablespace PART2_NDX_TS,
partition PART3 tablespace PART3_NDX_TS,
partition PART4 tablespace PART4_NDX_TS,
);
当分区中出现许多事务并且要保证所有分区中的数据记录的惟一性时采用全局索引,在建立全局索引时,Global子句允许指定索引的范围值,这个范围值可以不同于表分区的范围值。只有建立局部索引才会使索引分区与表分区间建立起一一对应关系。因此,在大多数情况下,应该使用局部索引分区。若使用了此索引,分区就能够很容易地将索引分区与表分区建立关联,局部索引比全局索引更易于管理。
3.分区管理
根据实际需要,还可以使用Alter table命令来增加、删除、交换、移动、修改、重命名、划分、截短一个已存在分区的结构。
二、重建索引
如果表中记录频繁地被删除或插入,尽管表中的记录总量保持不变,索引空间的使用量会不断增加。虽然记录从索引中被删除,但是该记录索引项的使用空间不能被重新使用。因此,如果表变化不定,索引空间量会不断增加,不论表中记录数量是否增加,只是因为索引中无效空间会增加。
关于sql数据库维护失败的问题查找方法
查看JOB的错误日志
查看数据库维护计划的历史纪录,找出错误的信息
用sql事件跟踪器
使用一下sql语句做进一步检查
dbcc dbreindex(N'[dbo].[tblSiteWantProd]', N'', 90, sorted_data_reorg)
DBCC CHECKIDENT ('tblSiteWantProd')
DBCC CHECKDB
dbcc checktable
sql 错误信息
CREATE UNIQUE INDEX 终止,因为发现了索引 ID %1! 的重复键。最重要的主键为 ''%2!''。
%1=可能是表示当前表的第几个索引???
%2=重复键的值
解决windows 2003 Sql2000中OLEDB分布式事务无法启动的解决方案
在开发分布式数据库软件时,经常碰到下面的错误:
服务器: 消息 7391,级别 16,状态 1,行 6
该操作未能执行,因为 OLE DB 提供程序 'SQLOLEDB' 无法启动分
布式事务。
[OLE/DB provider returned message: 不能在指定的事务处理器中
获得新事务。]
-----------------------------------------
服务器: 消息 8520,级别 20,状态 1,行 8
内部 MSDTC 事务的提交失败: Result Code = 0x8004d019。
连接中断
-----------------------------------------
搜索了网上类似问题的解决方案,都建议采用下面的方法(方法一):
1、运行 regedt32,浏览至 HKEY_LOCAL_MACHINE oftwareMicrosoftMSDTC。
添加一个 DWORD 值 TurnOffRpcSecurity,值数据为 1。
2、重启MS DTC服务。
3、打开“管理工具”的“组件服务”。
a. 浏览至"启动管理工具"。
b. 选择"组件服务"。
c. 展开"组件服务"树,然后展开"我的电脑"。
d. 右键单击"我的电脑",然后选择"属性"。
在 MSDTC 选项卡中,确保选中了下列选项:
网络 DTC 访问 网络管理 网络事务XA 事务
另外,"DTC 登录帐户"一定要设置为"NT AuthorityNetworkService"。4、重启MS DTC服务。
5、再次运行 regedt32,浏览至 HKEY_LOCAL_MACHINE oftwareMicrosoftMSDTC,然后删除 TurnOffRpcSecurity 项。
但是实际上该方法基本上解决不了问题,经过长时间的反复实践,我终于按下面的方法解决了:
(方法二)
1、按照方法一的方法处理一遍,如果不行,再继续下面的方法
2、安装windows 2003 sp1,安装好后,方法一中的第4步设置对话框和原来不一样了,选择“事务管理通讯”中的“不要求验证”
3、最好安装好MDAC2.8
3、通过查找,在C:找到名为“hosts”的文件(没有扩展名),通常路径为C:WINDOWSsystem32driversetc,将对方服务器的IP和计算机对应起来,参考如下:
========================================
# Copyright (c) 1993-1999 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
Mysql日期和函数不求人
DATE_FORMAT(date,format)
根据format字符串格式化date值。下列修饰符可以被用在format字符串中: %M 月名字(January……December)
%W 星期名字(Sunday……Saturday)
%D 有英语前缀的月份的日期(1st, 2nd, 3rd, 等等。)
%Y 年, 数字, 4 位
%y 年, 数字, 2 位
%a 缩写的星期名字(Sun……Sat)
%d 月份中的天数, 数字(00……31)
%e 月份中的天数, 数字(0……31)
%m 月, 数字(01……12)
%c 月, 数字(1……12)
%b 缩写的月份名字(Jan……Dec)
%j 一年中的天数(001……366)
%H 小时(00……23)
%k 小时(0……23)
%h 小时(01……12)
%I 小时(01……12)
%l 小时(1……12)
%i 分钟, 数字(00……59)
%r 时间,12 小时(hh:mm:ss [AP]M)
%T 时间,24 小时(hh:mm:ss)
%S 秒(00……59)
%s 秒(00……59)
%p AM或PM
%w 一个星期中的天数(0=Sunday ……6=Saturday )
%U 星期(0……52), 这里星期天是星期的第一天
%u 星期(0……52), 这里星期一是星期的第一天
%% 一个文字“%”。
所有的其他字符不做解释被复制到结果中。
mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
-> 'Saturday October 1997'
mysql> select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
-> '22:23:00'
mysql> select DATE_FORMAT('1997-10-04 22:23:00',
'%D %y %a %d %m %b %j');
-> '4th 97 Sat 04 10 Oct 277'
mysql> select DATE_FORMAT('1997-10-04 22:23:00',
'%H %k %I %r %T %S %w');
-> '22 22 10 10:23:00 PM 22:23:00 00 6'
MySQL3.23中,在格式修饰符字符前需要%。在MySQL更早的版本中,%是可选的。
TIME_FORMAT(time,format)
这象上面的DATE_FORMAT()函数一样使用,但是format字符串只能包含处理小时、分钟和秒的那些格式修饰符。
其他修饰符产生一个NULL值或0。
CURDATE()
CURRENT_DATE
以'YYYY-MM-DD'或YYYYMMDD格式返回今天日期值,取决于函数是在一个字符串还是数字上下文被使用。
mysql> select CURDATE();
-> '1997-12-15'
mysql> select CURDATE() 0;
SQL Server 中易混淆的数据类型
近来在做数据库设计,有时候真弄不清SQL2000里的数据类型,所以摘了这篇文章。
(1)char、varchar、text和nchar、nvarchar、ntext
char和varchar的长度都在1到8000之间,它们的区别在于char是定长字符数据,而varchar是变长字符数据。所谓定长就是长度固定的,当输入的数据长度没有达到指定的长度时将自动以英文空格在其后面填充,使长度达到相应的长度;而变长字符数据则不会以空格填充。text存储可变长度的非Unicode数据,最大长度为2^31-1(2,147,483,647)个字符。
后面三种数据类型和前面的相比,从名称上看只是多了个字母"n",它表示存储的是Unicode数据类型的字符。写过程序的朋友对Unicode应该很了解。字符中,英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。nchar、nvarchar的长度是在1到4000之间。和char、varchar比较:nchar、nvarchar则最多存储4000个字符,不论是英文还是汉字;而char、varchar最多能存储8000个英文,4000个汉字。可以看出使用nchar、nvarchar数据类型时不用担心输入的字符是英文还是汉字,较为方便,但在存储英文时数量上有些损失。
(2)datetime和smalldatetime
datetime:从1753年1月1日到9999年12月31日的日期和时间数据,精确到百分之三秒。
smalldatetime:从1900年1月1日到2079年6月6日的日期和时间数据,精确到分钟。
(3)bitint、int、smallint、tinyint和bit
bigint:从-2^63(-9223372036854775808)到2^63-1(9223372036854775807)的整型数据。
int:从-2^31(-2,147,483,648)到2^31-1(2,147,483,647)的整型数据。
smallint:从-2^15(-32,768)到2^15-1(32,767)的整数数据。
tinyint:从0到255的整数数据。
bit:1或0的整数数据。
(4)decimal和numeric
这两种数据类型是等效的。都有两个参数:p(精度)和s(小数位数)。p指定小数点左边和右边可以存储的十进制数字的最大个数,p必须是从 1到38之间的值。s指定小数点右边可以存储的十进制数字的最大个数,s必须是从0到p之间的值,默认小数位数是0。
(5)float和real
float:从-1.79^308到1.79^308之间的浮点数字数据。
real:从-3.40^38到3.40^38之间的浮点数字数据。在SQL Server中,real的同义词为float(24)。
如何在把超过固定长度的文字以……表示
有次,有个以前的同事(是个小MM)问我一个问题:她想在一个网页中显示一个文章标题的列表,但是考虑到有的标题太长,影响美观,就想参照别的网站上的样式,把超过固定长度的文字用省略号代替,但是自己又不知道如何实现,所以想到我(唉,需要我的时候才会想到我,呜……)
拿到题目后,我决定从数据库来着手,写查询语句来实现,结果如下:
说明语句:
SELECT (LEFT(原字段,位数) '...') AS 新字段
FROM 表名 WHERE DATALENGTH(原字段)>位数
UNION ALL
SELECT 原字段 AS 新字段 FROM 表名 WHERE DATALENGTH(原字段)<=位数
后来考虑到ACCESS中不支持DATALENGTH()函数,所以改为LEN(),不过这样的话,中文字也算作一位,而不是原来的两位。
最后写成:
select top 5 * from(
SELECT id,(LEFT([description],25) '...') AS descriptionx,kind,datetime, description, author, hit FROM [xjx] WHERE len(description)>25
UNION ALL
SELECT id,description AS descriptionx,kind,datetime, description, author, hit FROM [xjx] WHERE len(description)<=25) TempTable where kind='活动简报' order by datetime "
关于SQL Server SQL语句查询分页数据的解决方案
比如:要求选取 tbllendlist 中 第3000页的记录,每一页100条记录。
----------
方法1:
----------
select top 100 * from tbllendlist
where fldserialNo not in
(
select top 300100 fldserialNo from tbllendlist
order by fldserialNo
)
order by fldserialNo
----------
方法2:
----------
SELECT TOP 100 *
FROM tbllendlist
WHERE (fldserialNo >
(SELECT MAX(fldserialNo)
FROM (SELECT TOP 300100 fldserialNo
FROM tbllendlist
ORDER BY fldserialNo) AS T))
ORDER BY fldserialNo
方法1执行速度比较快!
不过,这种做法还是很麻烦,强烈期待微软发明新的可分页的SQL语句来!!!!
删除Access数词库中的空记录
作者:淘特网
出处:淘特网
注:转载请注明出处
用零长度字符指示不存在数据
若要在 Microsoft Access 数据库中指示不存在数据,可以在“文本”或“备注”字段输入零长度字符串 (零长度字符串:不含字符的字符串。可以使用零长度字符串来表明您知道该字段没有值。输入零长度字符串的方法是键入两个彼此之间没有空格的双引号 (" ")。)。在连接到 Microsoft SQL Server 数据库的 Microsoft Access 项目 (Microsoft Access 项目:与 Microsoft SQL Server 数据库连接且用于创建客户/服务器应用程序的 Access 文件。项目文件中不包含任何数据或基于数据定义的对象(如表或视图)。)中,可以在其数据类型 (数据类型:决定字段可拥有的数据类型的字段特征。数据类型包括 Boolean、Integer、Long、Currency、Single、Double、Date、String 和 Variant(默认)。)为 varchar 或 nvarchar 的字段中输入零长度字符串。
打开数据表 (“数据表”视图:以行列格式显示来自表、窗体、查询、视图或存储过程的窗口。在“数据表”视图中,可以编辑字段、添加和删除数据,以及搜索数据。),或在“窗体”视图 (“窗体”视图:一个显示窗体以便显示或接受数据的窗口。“窗体”视图是添加和修改表中数据的主要方式。在该视图中还可以更改窗体的设计。)中打开窗体。
若要在字段中输入零长度字符串,请键入中间不带空格的双引号 (" ")。
即使在移到其他字段或对象时双引号将消失,但该字段仍为零长度字符串。
Null 值与零长度字符串的区别 (MDB)
/*注释 本主题中的信息仅适用于 Microsoft Access 数据库 (.mdb)。*/
在查看含有 Null (Null:可以在字段中输入或用于表达式和查询,以标明丢失或未知的数据。在 Visual Basic 中,Null 关键字表示 Null 值。有些字段(如主键字段)不可以包含 Null 值。) 值和零长度字符串 (零长度字符串:不含字符的字符串。可以使用零长度字符串来表明您知道该字段没有值。输入零长度字符串的方法是键入两个彼此之间没有空格的双引号 (" ")。)的数据时,字段看起来是相同的,都没有任何值。但可以用表达式 (表达式:算术或逻辑运算符、常数、函数和字段名称、控件和属性的任意组合,计算结果为单个值。表达式可执行计算、操作字符或测试数据。)来区分 Null 值和零长度字符串。
在“设计”视图 (“设计”视图:显示数据库对象(包括:表、查询、窗体、宏和数据访问页)的设计的窗口。在“设计”视图中,可以新建数据库对象和修改现有数据库对象的设计。)中打开窗体、报表或数据访问页。