首页 > phper

一个有关DISTINCT的问题解答

经常会有朋友问到类似于这样的问题,
表中的数据如下
ID AA BB
1 123 456
1 4535 54
1 60 6564
1 60 656
2 50 664
2 60 6
3 89 89
4 40 4242
希望得到的结果是
ID AA BB
1 123 456
2 50 664
3 89 89
4 40 4242
当然了,环境是SQL Server
解答及分析如下:
1, 不少朋友希望用distinct就解决问题,但不可能,disctinct将重复的记录忽略,
但它忽略的是完全一致的重复记录,而不是其中某个字段重复的记录,所以也只有
这样的语法
select distinct ID,AA,BB from tName
其它诸如select distinct(ID),AA,BB from tName 或
select ID,distinct AA,BB的写法都是无效的
2, 使用group by和聚合函数
select ID,MAX(AA) AS AA,MAX(BB) AS BB from tName group by ID
可以得到如下结果
ID AA BB
1 4535 6564
2 60 664
3 89 89
4 40 4242
ID是唯一了,但不一定后面的字段是同一条记录的
3, 使用临时表
select IDENTITY(INT,1,1) as TID,ID,AA,BB into #Tmp from tName
select t1.ID,t1.AA,t1.BB from #Tmp t1 where t1.TID in
(select min(T2.TID) from #Tmp t2 group by t2.ID)
这样可以得到符合要求的结果
不过用了两个T-SQL语句,
而且如果是大数据量的话,性能问题将很突出
到目前为止,我还没找到用一个T-SQL语句实现同样功能的方法,
如果谁有,希望补充

阅读全文

MySQL修改密码方法总结

MySQL修改密码方法总结

首先要声明一点,大部分情况下,修改MySQL是需要有mysql里的root权限的,所以一般用户无法更改密码,除非请求管理员。
方法一
使用phpmyadmin,这是最简单的了,修改mysql库的user表,
不过别忘了使用PASSWORD函数。
方法二
使用mysqladmin,这是前面声明的一个特例。
mysqladmin -u root -p password mypasswd
输入这个命令后,需要输入root的原密码,然后root的密码将改为mypasswd。
把命令里的root改为你的用户名,你就可以改你自己的密码了。
当然如果你的mysqladmin连接不上mysql server,或者你没有办法执行mysqladmin,
那么这种方法就是无效的。
而且mysqladmin无法把密码清空。
下面的方法都在mysql提示符下使用,且必须有mysql的root权限:
方法三
mysql> INSERT INTO mysql.user (Host,User,Password)
VALUES(%,jeffrey,PASSWORD(iscuit));
mysql> FLUSH PRIVILEGES
确切地说这是在增加一个用户,用户名为jeffrey,密码为biscuit。
在《mysql中文参考手册》里有这个例子,所以我也就写出来了。
注意要使用PASSWORD函数,然后还要使用FLUSH PRIVILEGES。
方法四
和方法三一样,只是使用了REPLACE语句
mysql> REPLACE INTO mysql.user (Host,User,Password)
VALUES(%,jeffrey,PASSWORD(iscuit));
mysql> FLUSH PRIVILEGES
方法五
使用SET PASSWORD语句,
mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD(iscuit);
你也必须使用PASSWORD()函数,
但是不需要使用FLUSH PRIVILEGES。
方法六
使用GRANT ... IDENTIFIED BY语句
mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY iscuit;
这里PASSWORD()函数是不必要的,也不需要使用FLUSH PRIVILEGES。
注意: PASSWORD() [不是]以在Unix口令加密的同样方法施行口令加密。

阅读全文

如何随机选取n条记录或者对记录作随机排序?

Q. 如何得到随机排序结果?
A. 要得到随机排序的列,或者返回x条随机选择的列,你可以使用随机数。但是RAND函数在一个查询中只能返回一个结果。你可以在NOWID函数返回的列上做ORDER BY。请看示例:
SELECT *
FROM Northwind..Orders
ORDER BY NEWID()
SELECT TOP 10 *
FROM Northwind..Orders
ORDER BY NEWID()
这段话翻译得真是费劲,干脆不管原文,直接意译了。
不过提醒大家注意,这种方法是要对整个表扫描,然后产生一个计算列再排序的,最好不要对大的表作这样的操作,否则会很慢的。
Q. How can I randomly sort query results?
A. To randomly order rows, or to return x number of randomly chosen rows, you can use the RAND function inside the SELECT statement. But the RAND function is resolved only once for the entire query, so every row will get same value. You can use an ORDER BY clause to sort the rows by the result from the NEWID function, as the following code shows:
SELECT *
FROM Northwind..Orders
ORDER BY NEWID()
SELECT TOP 10 *
FROM Northwind..Orders
ORDER BY NEWID()
—SQL Server MVPs

阅读全文

金额阿拉伯数字转换为中文的存储过程

Create Procedure AtoC
@ChangeMoney Money
as
Set Nocount ON
Declare @String1 char(20)
Declare @String2 char(30)
Declare @String4 Varchar(100)
Declare @String3 Varchar(100) --从原A值中取出的值
Declare @i int --循环变量
Declare @J Int --A的值乘以100的字符串长度
Declare @Ch1 Varchar(100) --数字的汉语读法
Declare @Ch2 Varchar(100) --数字位的汉字读法
Declare @Zero Int --用来计算连续有几个零
Declare @ReturnValue VarChar(100)
Select @ReturnValue = ''
Select @String1 = '零壹贰叁肆伍陆柒捌玖'
Select @String2 = '万仟佰拾亿仟佰拾万仟佰拾元角分'
Select @String4 = Cast(@ChangeMoney*100 as int)
select @J=len(cast((@ChangeMoney*100) as int))
Select @String2=Right(@String2,@J)
Select @i = 1
while @i<= @j Begin
Select @String3 = Substring(@String4,@i,1)
if @String3<>'0' Begin
Select @Ch1 = Substring(@String1, Cast(@String3 as Int) 1, 1)
Select @Ch2 = Substring(@String2, @i, 1)
Select @Zero = 0 --表示本位不为零
end
else Begin
If (@Zero = 0) Or (@i = @J - 9) Or (@i = @J - 5) Or (@i = @J - 1)
Select @Ch1 = '零'
Else
Select @Ch1 = ''
Select @Zero = @Zero 1 --表示本位为0

--如果转换的数值需要扩大,那么需改动以下表达式 I 的值。
Select Ch2 = ''
If @i = @J - 10 Begin
Select @Ch2 = '亿'
Select @Zero = 0
end

If @i = @J - 6 Begin

阅读全文

如何使Microsoft SQL Server的日志文件不会增大?

如何缩小MSSQL的日志文件已经是一个经常性的问题了,不过这个问题在精华区已经有不少答案了,我这里也不再赘述。
现在我们讨论一下治本的问题,即如何使日志文件不再增大?
先介绍一个简单的方法。
就是把数据库的故障还原模型设置为“简单”(SQL2K)。这样它就会在Checkpoint的时候截断日志。
具体操作方法是:
1、在Enterprise Manager中右键点数据库,“属性|选项|故障还原”,选择“简单”就可以了,如果是SQL7,在“属性|选项”中有一个“trunc. log on chkpt. ”,选中就可以了。
2、如果不想用Enterprise Manager,在Query Analyser或者isql里面执行
EXEC sp_dboption 'your_dbname', 'trunc. log on chkpt.', 'TRUE'
就可以了
但是,要注意的是,这样做了之后,虽然日志不会增大,但是也意味着你一旦出现误操作,将不会有利用日志恢复的机会。(如何利用日志来恢复请参见精华区的FAQ)
所以,绝对不建议在生产数据库上截断日志,除非你有充足的理由和足够的把握,或者……
承担责任的不是你。
既然这种方法不安全,下面我将介绍一种安全的方法。
大家都知道,SQL Server 在完成事务日志备份时将自动截断事务日志中的不活动部分。这些不活动的部分包含已完成的事务,因此在恢复过程中不再使用。相反,事务日志的活动部分包含仍在运行但尚未完成的事务。SQL Server 将重新使用事务日志中这些截断的非活动空间,而不是任由事务日志继续增大并占用更多的空间。
所以,我们备份事务日志就可以使日志文件不再增大了。
但是呢,日志文件一直放着也不是个办法,删除呢,又会失去恢复的可能性。
我们可以结合完全备份来做。做过完全备份之前的事务日志就可以删除了。
比如说,一个备份计划,每天一次完全备份,保留7天内的,每15分钟一次事务日志备份,保留2天的。
用数据库维护计划向导可以很方便的建立备份计划,不过一定要记得设置保留多久的备份哦,否则硬盘空间被备份给占满了就坏事了。
Wrotten by Lucky@Dev-club
March 8, 2002

阅读全文

金额阿拉伯数字转换为中文的自定义函数

CREATE FUNCTION ChangeBigSmall
(@ChangeMoney money)
RETURNS VarChar(100) AS
BEGIN
Declare @String1 char(20)
Declare @String2 char(30)
Declare @String4 Varchar(100)
Declare @String3 Varchar(100) --从原A值中取出的值
Declare @i int --循环变量
Declare @J Int --A的值乘以100的字符串长度
Declare @Ch1 Varchar(100) --数字的汉语读法
Declare @Ch2 Varchar(100) --数字位的汉字读法
Declare @Zero Int --用来计算连续有几个零
Declare @ReturnValue VarChar(100)
Select @ReturnValue = ''
Select @String1 = '零壹贰叁肆伍陆柒捌玖'
Select @String2 = '万仟佰拾亿仟佰拾万仟佰拾元角分'
Select @String4 = Cast(@ChangeMoney*100 as int)
select @J=len(cast((@ChangeMoney*100) as int))
Select @String2=Right(@String2,@J)
Select @i = 1
while @i<= @j Begin
Select @String3 = Substring(@String4,@i,1)
if @String3<>'0' Begin
Select @Ch1 = Substring(@String1, Cast(@String3 as Int) 1, 1)
Select @Ch2 = Substring(@String2, @i, 1)
Select @Zero = 0 --表示本位不为零
end
else Begin
If (@Zero = 0) Or (@i = @J - 9) Or (@i = @J - 5) Or (@i = @J - 1)
Select @Ch1 = '零'
Else
Select @Ch1 = ''
Select @Zero = @Zero 1 --表示本位为0

--如果转换的数值需要扩大,那么需改动以下表达式 I 的值。
Select @Ch2 = ''
If @i = @J - 10 Begin
Select @Ch2 = '亿'
Select @Zero = 0
end

If @i = @J - 6 Begin

阅读全文

如何将Access和Excel导入到Mysql中之二

一。Mysql数据库的安装、建库和ODBC的安装设置
  Mysql和ODBC驱动可以在其主页(http://www.mysql.com/)下载,在右边的Latest Versions点击进去,下载相应的版本就行了。这里我们要下载Intel版本的Mysql(最新版本为3.23.40),ODBC驱动则是MyODBC 2.50.37 for NT/2000 (full setup),如果使用Win95/98,其驱动是不同的,请注意区分。
  然后就可以安装了,Mysql的安装是非常简单的,将它解压到一个目录(C:mysql),在Win2000中,Mysql可以作为Windows的一个服务运行,在命令行中运行"C:mysqlinmysqld-nt --install",然后在Win2000管理工具的服务中我们就可以发现有Mysql这个服务运行,不过我发现直接运行winmysqladmin.exe也是可以的,这时会要求输入一个密码,这是Mysql的连接密码,请记好,默认的连接是没有密码的(用户为root)。
  其后是建立数据库和表,由于要将Access和Excel中的数据都导过来,因此表格中要包括两者的全部字段,这里为简单起见,只选择了其中的一些字段来说明,运行cmd进入到命令行方式,切换到c:mysqlin目录,执行"mysqladmin create build",这个命令是创建数据库,build是数据库的名称,成功后,执行“mysql”,进入"Mysql>"的命令行方式下,执行以下的命令:
mysql>use build;
mysql>CREATE TABLE loupan (
id int(10) unsigned NOT NULL auto_increment,
loupantype varchar(6),
inputdate date,
at_whatsection varchar(6),
buildname varchar(50),
buildaddress varchar(50),
room tinyint(4),
hall tinyint(4),
areasize decimal(10,2),
exp_sellprice decimal(13,2),
ownername varchar(20),
contactway varchar(50),
memo varchar(255),
updatestatus char(1),
goodloupan char(1),
PRIMARY KEY (id)
);
  接着就会出现Query OK, 0 rows affected (0.04 sec)的成功提示,上文中use build表示切换当前的数据库为build,接着的语句是建表的命令,字段由上至下表示的是id号(自动加1,而且是该表的主键)、楼盘的类型、输入的日期、所在的区域、楼盘的名字、地址、房间的数目、厅的数目、面积、期望售价、业主的名字、联系方式、备注、更新状态、笋盘标志。
  接着就是安装Mysql的ODBC驱动了,MyODBC的安装也是傻瓜式的,运行setup,一步步确认。结束后,就可以在控制面板的ODBC数据源中进行设置了,点“系统DSN”,选择“添加”,在驱动程序的列表中选择“mysql”,就会弹出一个配置页面,在Windows DSN Name中输入数据源的名称,这里输入build(还可以输入其它的名称,不一定跟数据库的名字相同),在“MySQL host(name or IP)”中,输入“localhost”,表示Mysql运行在本机上,在Mysql Database Name中输入数据库的名字“build”,User中输入“root”,PassWord中输入刚才设置的密码,如果刚才没有设置的话,留空,按“OK”后,就会在系统数据源中多了一项“build”,这样Mysql的ODBC数据源就设置成功了。

阅读全文

MySQL以速度为目标

MySQL以速度为目标
--------------------------------------------------------------------------------
MySQL和PostgreSQL都是非常著名的数据库开放源码项目,而且都有取代商用数据库系统的趋势,但两者有着不同的设计目标。一般而言,如果需要更快的速度,可以优先考虑MySQL,而如果需要一些新的特色,那可以选择PostgreSQL。
目前MySQL由MySQL AB公司维护,其最新稳定版本为3.23,支持事务处理的3.23Max版也进入了Beta测试阶段,而它的最新开发版本4.0已经进入了Alpha测试阶段。它略显不寻常的许可费用,很容易让用户对它印象深刻。它的价格随平台和安装方式的不同而改变,其Windows版本在任何情况下都不免费,而对任何Unix/Linux版本,如果用户或系统管理员自己安装是免费的,第三方安装则必须支付许可费用。
MySQL是基于C/S体系结构的网络数据库管理系统。它的设计以速度为主要目标,可以快速处理多个用户的查询请求,在处理客户端连接时的速度也非常快,很适合用做Web站点的后台数据库。相对而言,PostgreSQL的执行速度比较慢,它对每个连接都生成一个子进程,而生成子进程、建立后台服务进程的步骤减慢了它的执行速度。MySQL的服务器功能很紧凑,各种复杂的功能处理(比如XML支持)完全被放到客户端进行,这使得增加功能时不会牺牲数据库服务器的速度和可靠性。而且它已被商业内存检测程序证明不存在内存泄露,连续中断和程序崩溃的现象也很罕见,在稳定性上比PostgreSQL要强一些。
在最初的设计阶段,MySQL主要面向中等规模的数据库,也就是说,数据库的规模大约有几千万行,每个表大约100MB。随着MySQL项目的发展,它的使用领域也逐渐扩展到TB规模的大型数据库和小型的手持或嵌入式设备领域。但是在短期内,MySQL不会支持实时数据库或大规模集群数据库。虽然在其3.23版本中,它通过MyISAM表,可以使系统在理论上能够支持8000PB的表。但由于操作系统的限制,在大部分Linux系统下,它仅能处理最大为2GB或4GB的表。在3.23版本中,还加入了支持大型服务器集群的复制、InnoDB的事务表处理器、Berkerley DB事务表处理器接口、全文本搜索、MyODBC 2.5接口、MyISAM表的自动检查和修复、批量插入等新模块。
InnoDB和BDB事务表处理器的引入使MySQL中使用这些方式存储的数据表具有很好的事务处理能力。不过对于其他方式存储的表,使用原子操作维护完整性和一致性通常会损失一些性能。在完整性非常重要时,可以使用LOCK TABLES进行表锁定。从3.23.44开始,InnoDB表支持外码限制检查,不过它的使用,特别是误用外码可能会导致较严重的问题。

阅读全文

MySQL数据库格式轻松转

在Linux界享有很高声誉的MySQL数据库,以其小巧玲珑、功能强大、全免费而著称。但对于很多用户来说,有时候必须要在Windows浏览、分析其中的数据,而在Windows下,MySQL数据库文件是无法被其他程序读取的。所以有人编写了这个格式转换程序---MySQL-to-Access。它可以把MySQL格式数据库文件转换为普通Access数据库文件,方便我们在Windows下轻松编辑、浏览其中的数据了。它适用于所有操作系统版本的MySQL数据库转换。
  大家可以到http://crctimes.onlinedown.net/down/sql2accd.exe下载这一程序。

阅读全文

MYSQL到ORACLE程序迁移的注意事项

MYSQL到ORACLE程序迁移的注意事项
2001-09
有很多应用项目, 刚起步的时候用MYSQL数据库基本上能实现各种功能需求,随着应用用户的增多,
数据量的增加,MYSQL渐渐地出现不堪重负的情况:连接很慢甚至宕机,于是就有把数据从MYSQL迁到
ORACLE的需求,应用程序也要相应做一些修改。本人总结出以下几点注意事项,希望对大家有所帮助。
1. 自动增长的数据类型处理
MYSQL有自动增长的数据类型,插入记录时不用操作此字段,会自动获得数据值。
ORACLE没有自动增长的数据类型,需要建立一个自动增长的序列号,插入记录时要把序列号的下一个
值赋于此字段。
CREATE SEQUENCE 序列号的名称 (最好是表名 序列号标记) INCREMENT BY 1 START WITH 1
MAXVALUE 99999 CYCLE NOCACHE;
其中最大的值按字段的长度来定, 如果定义的自动增长的序列号 NUMBER(6) , 最大值为999999
INSERT 语句插入这个字段值为: 序列号的名称.NEXTVAL
2. 单引号的处理
MYSQL里可以用双引号包起字符串,ORACLE里只可以用单引号包起字符串。在插入和修改字符串
前必须做单引号的替换:把所有出现的一个单引号替换成两个单引号。
3. 翻页的SQL语句的处理
MYSQL处理翻页的SQL语句比较简单,用LIMIT 开始位置, 记录个数;PHP里还可以用SEEK定位到结果
集的位置。
ORACLE处理翻页的SQL语句就比较繁琐了。每个结果集只有一个ROWNUM字段标明它的位置, 并且只能
用ROWNUM<100, 不能用ROWNUM>80。
以下是经过分析后较好的两种ORACLE翻页SQL语句( ID是唯一关键字的字段名 ):
语句一:
SELECT ID, [FIELD_NAME,...] FROM TABLE_NAME WHERE ID IN ( SELECT ID FROM (SELECT
ROWNUM AS NUMROW, ID FROM TABLE_NAME WHERE 条件1 ORDER BY 条件2) WHERE NUMROW > 80 AND
NUMROW < 100 ) ORDER BY 条件3;

语句二:
SELECT * FROM (( SELECT ROWNUM AS NUMROW, c.* from (select [FIELD_NAME,...] FROM
TABLE_NAME WHERE 条件1 ORDER BY 条件2) c) WHERE NUMROW > 80 AND NUMROW < 100 ) ORDER BY 条件3;
4. 长字符串的处理
长字符串的处理ORACLE也有它特殊的地方。INSERT和UPDATE时最大可操作的字符串长度小于等于

阅读全文

设计数据库之经验谈

数据库设计经验谈
数据库模型的设计是否合理会极大影响系统的使用性能。笔者依据多年来设计和使用数据库的经验,提出以下一些设计原则,供同仁们参考。
慎用游标(Cursor)
游标提供了对特定集合中逐行扫描的手段,一般使用游标来逐行遍历数据,根据取出数据条件的不同进行不同的操作。而对于多表和大表中定义的游标(大的数据集合)循环很容易使程序进入一个漫长的等待甚至死机,笔者在某市“住房公积金管理系统”进行日终账户滚积数计息处理时,对一个10万个账户的游标处理时导致程序进入了一个无限期的等待(后经测算需48小时才能完成)(硬件环境:Alpha/4000 128MB RAM ,SCO Unix ,Sybase 11.0)。经修改程序并改用UPDATE语句后,该处理过程得以在20分钟之内完成。示例如下:
Declare Mycursor cursor for select count—no from COUNT  
Open Mycursor
Fetch Mycursor into @vcount—no
While (@@sqlstatus=0)
Begin
If @vcount—no=′ ′ 条件1
操作1
If @vcount—no=′ ′ 条件2
操作2
...
Fetch Mycursor into @vcount—no
End
 ...
改为
Update COUNT set 操作1 for 条件1
Update COUNT set 操作2 for 条件2
...
在某些必须使用游标的场合,可考虑将符合条件的数据行转入临时表中,再对临时表定义游标进行操作,这样,可使性能得到明显提高。笔者在某地市“电信收费系统”数据库后台程序设计中,对一个表(3万行中符合条件的30多行数据)进行游标操作(硬件环境:PC服务器,PⅡ266 64MB RAM ,Windows NT4.0 MS SQL Server 6.5)。
示例如下:
Create #tmp /* 定义临时表 */
 ( 字段1
  字段2
   ... )
Insert into #tmp select * from TOTAL where 条件
Declare Mycursor cursor for select * from #tmp /*对临时表定义游标*/
 ...
索引(Index)的使用技巧
创建索引一般有两个目的:维护被索引列的惟一性和提供快速访问表中数据的策略。大型数据库有两种索引,即簇索引和非簇索引,一个没有簇索引的表是按堆结构存储数据,所有的数据均添加在表的尾部;而建立了簇索引的表,其数据在物理上会按照簇索引键的顺序存储,一个表只允许有一个簇索引,因此,根据B树结构,可以理解添加任何一种索引均能提高按索引列查询的速度,但与此同时会降低插入、更新、删除操作的性能,尤其是当填充因子(Fill Factor)较大时。所以对索引较多的表进行频繁的插入、更新、删除操作时,建表和索引时应设置较小的填充因子,以便在各数据页中留下较多的自由空间,减少页分割及重新组织的工作。

阅读全文

SQL技巧:创建用来按小时报告的查询

要创建一个可以每个小时报告的查询,首先要创建一个表格。该表格一列记录日期,而没有时间信息;另一列记录钟点。下面的表格有一列记录了不同的处理类型。例如,我们可以按小时找出处理类型的总数。
CREATE TABLE test
(StartTime DATETIME NOT NULL
DEFAULT CURRENT_TIMESTAMP,
StartDate DATETIME NOT NULL
DEFAULT CONVERT(DATETIME, CONVERT(CHAR(10),CURRENT_TIMESTAMP, 110)),
StartHour INT NOT NULL
DEFAULT DATEPART(hh,CURRENT_TIMESTAMP),
TranType INT NOT NULL
CONSTRAINT ck_TranType CHECK ( TranType IN
(
1, -- insert
2, -- update
3, -- delete
)
DEFAULT 1
)
GO
接下来,插入test的数据来模拟一个可能的样本。
INSERT test (StartTime, TranType) VALUES (CURRENT_TIMESTAMP, 3)
INSERT test (StartTime, TranType) VALUES (CURRENT_TIMESTAMP, 2)
INSERT test (StartTime, TranType) VALUES (CURRENT_TIMESTAMP, 3)
GO
DECLARE @hr int
SET @hr = DATEPART(hh, DATEADD(hh,-1,CURRENT_TIMESTAMP) )
INSERT test (StartTime, TranType, StartHour) _
VALUES (DATEADD(hh,-1,CURRENT_TIMESTAMP), 3, @hr)
INSERT test (StartTime, TranType, StartHour) _
VALUES (DATEADD(hh,-1,CURRENT_TIMESTAMP), 1, @hr)
INSERT test (StartTime, TranType, StartHour) _
VALUES (DATEADD(hh,-1,CURRENT_TIMESTAMP), 2, @hr)
GO
然后用一个查询来找出按日和小时的处理总数。
SELECT StartDate tran_day,
StartHour tran_hour
, CASE trantype WHEN 1 THEN 'insert'
WHEN 2 THEN 'update'
WHEN 3 THEN 'delete'
ELSE 'unknown'
END trantype,
COUNT(*) tran_total
FROM
Test
GROUP BY
StartDate,
StartHour
,trantype
ORDER BY StartDate, StartHour
COMPUTE SUM(COUNT(*)) BY StartDate, StartHour
GO

去掉test可以清空test表格。
DROP TABLE test
GO

阅读全文