数据库

本类阅读TOP10

·SQL语句导入导出大全
·SQL Server日期计算
·SQL语句导入导出大全
·SQL to Excel 的应用
·Oracle中password file的作用及说明
·MS SQLServer OLEDB分布式事务无法启动的一般解决方案
·sqlserver2000数据库置疑的解决方法
·一个比较实用的大数据量分页存储过程
·如何在正运行 SQL Server 7.0 的服务器之间传输登录和密码
·SQL中两台服务器间使用连接服务器

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
SQL Story摘录(八)————数据抽取

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

数据抽取

理论上的关系型数据库,数据是以关系的形式存在。通常我们都可以把它们视为一种集合。这样,数据一般是以无序的形式存在的。这种做法的好处自不用多加讨论了,不过我们也得承认,有时这样也会带给我们一些麻烦。我最近就遇到这么一件。

我在网上遇上我的一个老同学,他提出了这样一个问题。有一个表(假设就叫myTable),表中有三个整型字段(假设就叫A11,A12,A13),其上有一个唯一键约束。现在他想要在这个表的数据中取一些样品。他希望从中A13的各个取值中,各取一条记录。然后我问他,对A11和A12有什么要求吗?他说,没有,怎么取都可以,有没有规律都行。我想当然的说,简单,给我二十分钟。

有一个笑话不知你们听过没有。说很久以前,一个大数学家讲课,有学生问他能不能证明四色定理。他说,那容易,我现在就证给你们……然后他写啊写啊……想啊想啊……一直想到下课也没证出来,然后外面打了一个大大的响雷,他自嘲说,上帝也被我的狂妄激怒了……

什么,你问我刚才的问题怎么样了?我告诉你,二十分种,不不,四十分钟,不不,好像是一个小时……后来到半夜了,外面开始打雷……我对我的同学说,老兄,我错了,让我把这问题拿回去想想先……

以下是一个示例,我随便录了些数据进去

A11 A12 A13

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

0 0 0

0 0 1

0 1 1

1 1 1

1 1 2

1 2 2

2 2 2

2 2 1

2 2 3

2 1 3

2 3 3

3 3 1

3 3 2

3 2 3

3 2 1

3 2 2

3 1 1

3 1 2

3 1 3

一开始,我是想用一个SELECT MAX(A11), MAX(A12), A13 FROM myTable GROUP BY A13,后来用脚趾头想了想,发现不可能。因为 MAX(A11)和MAX(A12)都只依赖于分组子句 GROUP BY A13。显然这样MAX(A11)和MAX(A12) 不一定会是同一条记录中的数据。就像下面这样:

A13

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

0 0 0

3 3 1

3 3 2

3 3 3

注意,其实3, 3, 3这一行是不存在的。

然后我想,SELECT MAX(A11), MAX(A12), A13 FROM myTable GROUP BY A13, A12行不行?用SQL Server 试了试,也不对。 因为这样的话,它会先按 A13, A12来分组所返回的结果集,所以会比我们要的数据多的多。就像下面这样

A13

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

0 0 0

0 0 1

3 1 1

3 1 2

3 1 3

3 2 1

3 2 2

3 2 3

3 3 1

3 3 2

2 3 3

诸如此类的傻事我还干了很多,后来我终于想明白我要什么数据了:取A12,A13,使得在所有按A13的值分组后,取每组中最大的A12,然后取整记录,使得A11是A12和A13满足前述条件后的最大的一个值。这样,我写出了一个语句:

SELECT

(SELECT MAX(I.A11) FROM myTable I WHERE I.A13 = O.A13 AND I.A12 = MAX(O.A12)) A11

, MAX(O.A12) A12

, O.A13 A13

FROM myTable O

GROUP BY O.A13

这行语句返回值如下:

A11 A12 A13

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

0 0 0

3 3 1

3 3 2

2 3 3

同样的,我们可以解释它为最两个结果集,一个是 SELECT MAX(A11), MAX(A12), A13 FROM myTable GROUP BY A13,一个是 SELECT MAX(A12), A13 FROM myTable GROUP BY A13, A12,然所按A12和A13进行等值联接,这就是:

SELECT MAX(L.A11) A11

, MAX(L.A12) A12

, L.A13 A13

FROM myTable L

JOIN myTable R

ON L.A13 = R.A13

GROUP BY L.A13, L.A12

HAVING L.A12 = MAX(R.A12)

我个觉得这样子比较清爽,不知各位以为如何?

事实上,这一类的数据抽取,不可能用一个简单查询得到,因为其中有一个字段要同时参予分组和统计。只有(事实上是只要)把我们的问题用SQL语言的思考方式描述清楚,答案也就得到了,一切就这么简单。

对于一类完全按行随机抽取的问题,除了化为Top n问题解决外,还有一个好主意就是在支持物理行号的数据库系统中,用rowid 或标识列之类的技术来解决,这样比较简单,就不多说了。

补充一句,以前我说过InterBase不支持自动标识列,但实际上,它也可以间接的实现。在InterBase中,我们可以Create一种叫 generator的全局变量,然后用一个触发器,结合一个函数叫GEN_ID的,就可以做到。虽说有点麻烦,但并非不可能。详细情况,大家可以查询 InterBase有关技术文档。

欢迎来信和我讨论技术问题:lx1978@263.net。




相关文章

相关软件