存档

文章标签 ‘ASE’,文章数:63

Sybase ASE自版本15.0.2开始增加判断字符串是否为日期类型的函数:isdate,以及判断字符串是否为数字类型的函数:isnumeric

函数:isdate

Syntax

isdate(character_expression)

Parameters

character_expression

    is a character-type variable, constant expression, or column name.

Usage

Returns 1 if the expression is a valid datetime value; returns 0 if it is not. Returns 0 for NULL input.

演示在用java连接Sybase ASE数据库。用了一个简单的java程序作试验。

第一步:获得jdbc for sybase驱动程序
下载JDBC驱动:http://www.sybase.com/detail?id=1009726

也可到CSDN下载:http://download.csdn.net/source/2697077
有jConnect6.05和jConnect5.5两种。jConnect6.05中包含jconn3.jar包,jConnect5.5中包含jconn2.jar包。建议最新的Sybase驱动jconn3.jar。不过我的这个例子很简单,两者都可以用。

下载:jconn3.jar ,下载:jconn2.jar

第二步:设置环境变量CLASSPATH

将下载下来的jconn2.jar或jconn3.jar放到目录D:\sybase\Shared\lib下。将环境变量CLASSPATH设置为:D:\sybase\Shared\lib\jconn2.jar

set CLASSPATH=.;d:\sybase\shared\lib\jconn2.jar;   (注意:第一个“.”,这个代表当前目录。)

第三步:编写一段简单的java程序。

下面的这段程序用jconn2.jar连接Sybase ASE15.0.3数据库并提取master数据库中的用户表的ID和name两列信息。

Sybase ASE数据库的ip地址为:192.168.0.168,端口:5000。登录sa的密码为:sybase

执行:select id,name,crdate from dbo.sysobjects where type='U'   这条语句返回当前数据库(这在url中指定!)中的用户表的id和name列。

以下存储过程能够自动批量删除数据库库内的所有用户表。

可以修改存储过程内的条件来删除指定的表。

删除表时请谨慎!

CREATE PROCEDURE sp_drop_tbl
AS
BEGIN
    DECLARE @tblname varchar(80)
    DECLARE @dropsql varchar(100)
    DECLARE cur1 CURSOR FOR
        SELECT name FROM dbo.sysobjects WHERE  type = 'U'
    OPEN cur1
    FETCH cur1 INTO @tblname

    WHILE (@@SQLSTATUS = 0)
    BEGIN
        SELECT @dropsql = "DROP TABLE " + @tblname
        EXEC (@dropsql)
        FETCH cur1 INTO @tblname
    END

    CLOSE cur1
    DEALLOCATE cursor cur1
END

 提供一个能够自动生成Sybase数据库内所有表的表结构、索引语法的存储过程。

存储过程名字:sp_gettabledll 下载

过程语法如下:

----------------------------------------------------------------------------------------------------------------------

if exists(select 1 from sysobjects where name = 'sp_gettabledll' and type = 'P')
  drop procedure sp_gettabledll
go

create procedure sp_gettabledll 
@tblname varchar(30) = null, 
@prechar varchar(4) = null,   --$:no print 
@table_dll varchar(16384) = null out, 
@dbname varchar(32) = null, 
@droptg char(1) = '1', 
@prxytx varchar(255) = null, 
@replace varchar(20) = null, 
@tabtype varchar(1) = 'A', --A:所有表;P:代理表;U:用户表 
@indextg varchar(3) = 'TPI',  --T:纯表;P:主键;I:纯索引;J:除主键外的纯索引(和TP使用与I相同,和I同时使用I失效) 
@table_seg varchar(32) = null, 
@index_seg varchar(32) = null 
as 
begin 
     set nocount on  
 

以下的脚本能够自动创建数据库、登录、用户并能给用户分配命令权限。只需要指定用户数据库的名称,数据设备、日志设备的大小,登录名称以及登录密码即可。

局限性:

没有判断即将要创建的设备是否存在?

将数据库设备创建在和master设备同一目录下,不能提高物理IO的性能。

脚本文件下载:sybase数据库自动创建脚本.sql

-----------------------------------------------------------------------------------------------------------------------------

use master
go
declare @dbname varchar(30)
declare @MasterDevicePath varchar(255),@LogicalDataDevName varchar(30),@LogicalLogDevName varchar(30)
declare @DATDevicePath varchar(255),@LOGDevicePath varchar(255),@DataDevSize int,@LogDevSize int,@DataDevPageCount  int,@LogDevPageCount int
declare @SQLTEXT varchar(255)
declare @loginname varchar(30),@loginpasswd varchar(30)
set nocount on
begin
-- @dbname 代表将要创建的数据库名称

Adaptive Server version 15.0.2 uses row-level locking on system tables to enhance performance.

Versions of Adaptive Server earlier than 15.0.2 used exclusive table locks on system tables while executing data definition language (DDL) and utility commands. The set of system tables Adaptive Server locked depended on the type of DDL operation you executed. If another DDL running concurrently tried to take a conflicting exclusive table lock on the same system table, this DDL had to wait to acquire the lock on any system catalogs. These DDL operations were executed serially.

This methodology impeded performance in temporary databases, where their DDL activity is very high also, and consequently their catalog contention is very high. This limited the Adaptive Server throughput for applications using temporary tables.
Adaptive Server version 15.0.2 uses row-level locking to resolve these issues:

*

System-table contention, caused a bottleneck for many DDLs and utilities.
*

tempdb contention. Because the system tables are locked at the row level, Adaptive Server 15.0.2 eliminates tempdb contention.
*

Shared or exclusive table-level locks while executing DDLs and utilities. Earlier versions converted most system tables to data-only locking (DOL), but still created shared or exclusive table-level locks while executing DDLs and utilities. Using row-level locks for system tables eliminates this contention.

Adaptive Server sets intent locks on catalogs only, which removes potential contention (An intent lock indicates that page-level or row-level locks are currently held on a table.).
*

DDLs and utilities blocking each other. Adaptive Server 15.0.2 allows DDLs and utilities to run in parallel.

Earlier versions of Adaptive Server used table locks to achieve system catalog synchronization. Adaptive Server 15.0.2 uses intent locks for table-level synchronization and row locks for row-level synchronization. Earlier releases of Adaptive Server locked the entire system catalog while performing operations on the object, so a single lock request was made. However, Adaptive Server version 15.0.2 requests locks for all applicable rows while performing operations on the object if there are multiple rows corresponding to an object in a system catalog.

This change means that Adaptive Server 15.0.2 requests more locks to perform the same operation than earlier releases, and increases the number of lock resources the system needs. Consequently, you may need to change the number of locks configuration option after you upgrade Adaptive Server.

问题描述:

在UNIX及某些系统内不能启动Sybase Center,那么在这种情况下怎样修改sa密码呢,同时如果我们不需要密码时也可以使用该方法将sa密码置为空。

如何将sa的密码置为空,假设当前sa密码为:123456。

解决方案:
$isql -Usa -P123456 -SSYBASE
1>sp_configure "upgrade version"
2>go
#记录打印的版本号,Run Value表示当前系统版本是:11920 (sybase 11.9.2)

1>sp_configure "upgrade version",492
2>go
#更改版本号为492

1>sp_password   '123456',NULL,sa
2>go
#修改密码将123456密码置为空

1>sp_configure "upgrade version",11920
2>go
#务必更改版本号为原来的版本号

如果将参数upgrade version修改为492后忘记改回原来的值,则在Sybase服务器关闭后再启动的时候报错:

Pre 10.0 database cannot work with this version of the server. Please upgrade the databases to 10.0 or above release and then try to start with this version of the server. Shutting down ***.

这说明master数据库已经损坏了。因此,通过修改参数upgrade version重置sa口令为空时千万要谨慎,最后一定要将upgrade version修改回原值!

修复的方法请参考:

master数据库配置区域(configuration area)损坏的一种修复方法

https://www.dbainfo.net/one-way-to-recover-master-configuration-area.htm

接上篇的关于MySQL中的分页方法,本篇简单讨论在Sybase ASE中实现数据结果分页的方式。

本篇介绍三种方法。

第一种:利用游标

程序开发人员比较喜欢使用游标,因为游标的“循环”遍历方式类似编程语言中的for,while,loop语句的实现方法,写起来比较容易。使用游标一般步骤是:为指定的SQL语句定义一个游标,打开并移动游标,当移动到指定行号的记录行之后,再按照需要提取的行数来取数据。从表面上看解决了提取指 定范围数据的问题;但是在实际应用上,有可能会出现严重的性能问题。建立游标需要耗用一定的系统资源之外;当表内的数据量有上千万甚至到亿级别并且需要取大量的数据结果时,用游标每移动一 次就取这行数据,然后再移动游标,这个过程将是缓慢的。在使用游标的过程中,系统会给相应的表加上共享锁,导致锁竞争而严重影响数据库的性能。

在此不再介绍游标的实现方式,此法比较简单。一个使用游标分页的例子:sp_splitpage_by_cursor.sql

第二种:利用临时表和标志列

在Sybase ASE12.5.3及以后的版本中,我们可以用top关键字来限定只返回结果集的前N行数据。在ASE12.5.3之前的版本中只能用set rowcount N 的方法来“曲线救国”了。

对于取结果集的第N行至第N+M行数据的要求,我们考虑利用top来实现的话,比较容易想到的是:执行两次top,再加一次倒序排序。

步骤如下:

          (1) select top N+M * from table_name where_clause order by ID ASC     --把此结果集派生为表:table_name1

                  (2)   select top M * from table_name1 order by ID  DESC                          --把此结果集派生为表:table_name2

                  (3)   select * from table_name2 order by ID  ASC

上面的3条语句好像能够实现返回第N行至第N+M行数据的要求。但是,在Sybase ASE中仅仅利用派生表而不利用临时表是不能实现这个要求的。

仅仅是ASE中的“派生出派生表(derived table)的SQL语句中不能含有order by 子句”这个限制就足以使上面的方法行不通。还有一个限制是,上面的3个步骤中都利用ID列进行排序。如果表中没有可用的排序列时,那么上述方法也不能用 了。不过幸运的是,一般要求对其结果集进行分页的表都是有可以用作排序的列的(数字型或者日期型)。

继续寻找一个能用的方法,下面着重介绍目前通用的ASE的分页思路。此思路的关键是产生identity自增列和临时表。

在ASE中大家要是找到了不用临时表就可以实现分页的方法请麻烦告诉我一声。 我尝试了很多次,都不是很理想。

概括起来主要语句有两条:

                (1)   select syb=identity(10),*  into #temp_table from table_name where_clause   order_by_clause

                (2)   select  * from #temp_table where_clause and syb >= N   and syb <= N+M

使用此方法实现ASE分页的一个存储过程为:

-- 此存储过程适用于所有版本的ASE中
use sybsystemprocs
go
if exists(select 1 from sybsystemprocs.dbo.sysobjects where type='P' and name='sp_page')
  drop procedure sp_page
go

create procedure sp_page @qry varchar(16384),@ipage int,@num int
as
begin
 
  declare @rcount int
  declare @execsql varchar(16384)
 
  select @rcount=@ipage*@num
  set @execsql = 'set rowcount '|| convert(varchar,@rcount)
  set @execsql = @execsql || stuff(@qry,charindex('SELECT ',upper(@qry)),6,' SELECT sybid=identity(12),')
  set @execsql = stuff(@execsql,charindex(' FROM ',upper(@execsql)),6,' INTO #temptable FROM ')
  set @execsql = @execsql || ' SELECT * FROM #temptable  WHERE sybid >' || convert(varchar,(@ipage-1)*@num)
  set @execsql = @execsql || ' AND sybid<=' || convert(varchar,@ipage*@num) + ' set rowcount 0'
  execute(@execsql)
 
end
go

exec sp_procxmode 'sp_page',anymode
go
grant execute on sp_page to public
go

用一个例子演示一下:

(1) 建立测试表:testA

create table testA(id int not null,name varchar(30) null)
go

(2) 插入测试数据

insert into testA
select 1,'liuzhenfu'
go
insert into testA
select 2,'andkylee'
go

(3) 循环插入大量的重复数据

insert into testA
select id+(select max(id) from testA),name from testA
go 15

向表testA循环插入已有的数据,15次之后,表testA内的数据达到2^16 = 65536 行。

 

(4) 利用临时表 + 自增标志列来提取第100行至第200行的数据。

语句如下:

select syb=identity(10) ,* into #tempA from testA
select * from #tempA where syb>=100 and syb<=200
drop table #tempA

返回的结果为:

1> select syb=identity(10),* into #tempA from testA
2> select * from #tempA where syb>=100 and syb<=200
3> go
(65536 rows affected)
 syb           id          name
 ------------- ----------- ---------------------------
           100         100 andkylee
           101         101 liuzhenfu
           102         102 andkylee
           103         103 liuzhenfu
           104         104 andkylee
           105         105 liuzhenfu
           106         106 andkylee
           107         107 liuzhenfu
           108         108 andkylee
           109         109 liuzhenfu
           110         110 andkylee
           111         111 liuzhenfu
           112         112 andkylee
           113         113 liuzhenfu
           114         114 andkylee
           115         115 liuzhenfu
           116         116 andkylee
           117         117 liuzhenfu
           118         118 andkylee
           119         119 liuzhenfu
           120         120 andkylee
           121         121 liuzhenfu
           122         122 andkylee
           123         123 liuzhenfu
           124         124 andkylee
           125         125 liuzhenfu
           126         126 andkylee
           127         127 liuzhenfu
           128         128 andkylee
           129         129 liuzhenfu
           130         130 andkylee
           131         131 liuzhenfu
           132         132 andkylee
           133         133 liuzhenfu
           134         134 andkylee
           135         135 liuzhenfu
           136         136 andkylee
           137         137 liuzhenfu
           138         138 andkylee
           139         139 liuzhenfu
           140         140 andkylee
           141         141 liuzhenfu
           142         142 andkylee
           143         143 liuzhenfu
           144         144 andkylee
           145         145 liuzhenfu
           146         146 andkylee
           147         147 liuzhenfu
           148         148 andkylee
           149         149 liuzhenfu
           150         150 andkylee
           151         151 liuzhenfu
           152         152 andkylee
           153         153 liuzhenfu
           154         154 andkylee
           155         155 liuzhenfu
           156         156 andkylee
           157         157 liuzhenfu
           158         158 andkylee
           159         159 liuzhenfu
           160         160 andkylee
           161         161 liuzhenfu
           162         162 andkylee
           163         163 liuzhenfu
           164         164 andkylee
           165         165 liuzhenfu
           166         166 andkylee
           167         167 liuzhenfu
           168         168 andkylee
           169         169 liuzhenfu
           170         170 andkylee
           171         171 liuzhenfu
           172         172 andkylee
           173         173 liuzhenfu
           174         174 andkylee
           175         175 liuzhenfu
           176         176 andkylee
           177         177 liuzhenfu
           178         178 andkylee
           179         179 liuzhenfu
           180         180 andkylee
           181         181 liuzhenfu
           182         182 andkylee
           183         183 liuzhenfu
           184         184 andkylee
           185         185 liuzhenfu
           186         186 andkylee
           187         187 liuzhenfu
           188         188 andkylee
           189         189 liuzhenfu
           190         190 andkylee
           191         191 liuzhenfu
           192         192 andkylee
           193         193 liuzhenfu
           194         194 andkylee
           195         195 liuzhenfu
           196         196 andkylee
           197         197 liuzhenfu
           198         198 andkylee
           199         199 liuzhenfu
           200         200 andkylee
(101 rows affected)

需要将select * from #tempA中的星号*替换为需要返回的列名。

继续。。。。

当要求返回满足name='andkylee'的所有行中的第100行至第200行的数据时, 利用

select syb=identity(10),* into #tempA from testA where name='andkylee'

select * from #tempA where syb>=100 and syb<=200

drop table #tempA

 

第三种:利用rowcount

此种方法有点不足:必须利用可用作排序的列 对结果集进行排序。

还是上面的测试表testA,如果从第9000行开始选择10行数据,那么语句如下:

declare @id1 int
set rowcount 9000
select @id1 = id from testA order by id
set rowcount 10
select *from testA where id >= @id1 order by id
set rowcount 0
go

 

此种方法中核心语句是select @id1=id from testA order by id , 在对表testA执行查询的过程中,每读取一行都会把id列的值赋给@id1这个变量,一直持续到最后一行,@id1这个变量反复被下一行的id值刷新, 最后结果只得到最后一行的id值。如果在此select语句之前加上rowcount的限定,那么就可用变量@id1来获得第rowcount行的id 值,于是我们也就获得了要返回的范围结果集的起点了。

后面的 set rowcount 10

         select * from testA where id >= @id1 order by id

这两句实际上可以用一句select top 10 * from testA where id >= @id1 order by id  来替代。 

这样,两种不同的实现形式为:

declare @id1 int
set rowcount 9000
select @id1 = id from testA  order by id
set rowcount 0
select top 10  *from testA where  id >= @id1 order by id
go

 

分别看看执行结果吧!

第一种方式的执行结果:

1> declare @id1 int
2> set rowcount 9000
3> select @id1 = id from testA order by id
4> set rowcount 10
5> select *from testA where id >= @id1 order by id
6> set rowcount 0
7> go
(9000 rows affected)
 id          name
 ----------- ------------------------------
        9000 andkylee
        9001 liuzhenfu
        9002 andkylee
        9003 liuzhenfu
        9004 andkylee
        9005 liuzhenfu
        9006 andkylee
        9007 liuzhenfu
        9008 andkylee
        9009 liuzhenfu
(10 rows affected)
1>
 

第二种方式的执行结果:

1> declare @id1 int
2> set rowcount 9000
3> select @id1 = id from testA order by id
4> set rowcount 0
5> select top 10  *from testA where id >= @id1 order by id
6> go
(9000 rows affected)
 id          name
 ----------- ------------------------------
        9000 andkylee
        9001 liuzhenfu
        9002 andkylee
        9003 liuzhenfu
        9004 andkylee
        9005 liuzhenfu
        9006 andkylee
        9007 liuzhenfu
        9008 andkylee
        9009 liuzhenfu
(10 rows affected)
1>

当然,两种结果一模一样。

最后我们测试表testA中的ID列顺序值打乱, 来看看以上语句的执行情况。执行:

update testA set id = id + cast( rand() * 65536 as int ) 

ID列值打乱之后,前100行的数据为:

1> select top 100 * from testA
2> go
 id          name
 ----------- ------------------------------
       51366 liuzhenfu
       33573 andkylee
       19447 liuzhenfu
       19408 andkylee
       57839 liuzhenfu
       18817 andkylee
     ......................
       19075 liuzhenfu
       17081 andkylee
       26444 liuzhenfu
        6620 andkylee
       52344 liuzhenfu
       49348 andkylee
(100 rows affected)

我们要求返回满足name='andkylee'的从第9000行开始的10行数据。

declare @id1 int
set rowcount 9000
select @id1 = id from testA where name='andkylee' order by id
set rowcount 10
select *from testA where name='andkylee' and id >= @id1 order by id
set rowcount 0
go

结果为:

1> declare @id1 int
2> set rowcount 9000
3> select @id1 = id from testA where name='andkylee' order by id
4> set rowcount 10
5> select *from testA where name='andkylee' and id >= @id1 order by id
6> set rowcount 0
7> go
(9000 rows affected)
 id          name
 ----------- ------------------------------
       48639 andkylee
       48639 andkylee
       48641 andkylee
       48641 andkylee
       48642 andkylee
       48643 andkylee
       48644 andkylee
       48644 andkylee
       48650 andkylee
       48650 andkylee
(10 rows affected)

如果不对ID列进行排序, 有下面的sql语句:

declare @id1 int
set rowcount 9000
select @id1 = id from testA where name='andkylee'
set rowcount 10
select *from testA where name='andkylee' and id >= @id1
set rowcount 0
go

相应的结果集为:

1> declare @id1 int
2> set rowcount 9000
3> select @id1 = id from testA where name='andkylee'
4> set rowcount 10
5> select *from testA where name='andkylee' and id >= @id1
6> set rowcount 0
7> go
(9000 rows affected)
 id          name
 ----------- ------------------------------
       74076 andkylee
       74514 andkylee
       74053 andkylee
       74385 andkylee
       74339 andkylee
       74792 andkylee
       74794 andkylee
       74984 andkylee
       75052 andkylee
       74138 andkylee
(10 rows affected)
1>

可以发现这个两句的结果是不同的。

我想既然都要求返回指定范围的结果集, 肯定是有排序的依据了, 否则怎么知道该返回哪个范围呢?

还有,我给出的第三种方法,在进行表扫描的时候,即使不指定排序,也是能够得到正确结果的。因为表扫描时很可能会按照表内数据在物理页面上的物理位置来返回结果。

就先介绍到这里吧, 后续可能会根据情况进行补充。

文件下载:

使用第二种方法在ASE实现分页的存储过程: sp_page.sql 包含top和set rowcount两种。

根据显示的当前页号进行优化处理、更通用些的存储过程:splitpage.sql

————————————————————————————————-
—- 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
—- 转载务必注明原始出处 : http://www.dbainfo.net
—- 关键字:ASE 分页  top  identity  set rowcount  temp table  自增列 伪列 临时表
————————————————————————————————-