2001年8月8日 第三周
A.1997年度与公司有业务往来的客户
所谓有业务往来就是与企业有销售关系,是否有销售关系可以从Orders表中得到,于是大家很容易想到使用字查询的技术来解决问题。
我们可以通过如下查询得到有销售关系客户编号:
SELECT ORDERS.CUSTOMERID FROM ORDERS WHERE ORDERS.ORDERDATE BETWEEN '19970101' AND '19971231'
由于需要得到更详细的客户信息,所以必须使用到Customers表。于是在SQL Server中最终代码代码如下:
SELECT CUSTOMERS.CUSTOMERID,CUSTOMERS.COMPANYNAME,CUSTOMERS.CITY,CUSTOMERS.COUNTRY
FROM CUSTOMERS WHERE CUSTOMERS.CUSTOMERID IN
(SELECT ORDERS.CUSTOMERID FROM ORDERS WHERE ORDERS.ORDERDATE BETWEEN '19970101' AND '19971231')
在Visual FoxPro中实现起来代码也是一样的:
SELECT CUSTOMERS.CUSTOMERID,CUSTOMERS.COMPANYNAME,CUSTOMERS.CITY,CUSTOMERS.COUNTRY ;
FROM CUSTOMERS WHERE CUSTOMERS.CUSTOMERID IN;
(SELECT ORDERS.CUSTOMERID FROM ORDERS WHERE ORDERS.ORDERDATE BETWEEN {^1997-01-01} AND {^1997-12-31})
就本例来说还有更高效的方法解决问题,SQL Server中有这样一个说法:连接比子查询更有效率。那么这里我们是不是可以用表与表的连接来解决问题呢?可以的,在SQL Server中我们首先会写出这样的代码:
SELECT CUSTOMERS.CUSTOMERID,CUSTOMERS.COMPANYNAME,CUSTOMERS.CITY,CUSTOMERS.COUNTRY
FROM CUSTOMERS INNER JOIN ORDERS ON CUSTOMERS.CUSTOMERID=ORDERS.CUSTOMERID
WHERE ORDERS.ORDERDATE BETWEEN '19970101' AND '19971231'
这样是否完成了需要?没有,运行一下看看结果你就知道了:原来一个客户在97年度中可能与公司发生数次销售关系,这样在Orders表中就会产生多条销售信息,通过Oreders 表与Customers的连接,一个客户可能对应到数张订单,于是产生了客户信息的重复,这显然非我们所愿,这时就必须保证:客户标号相同的数据行只显示其中的一条,用关键字:DISTINCT可以实现。在SQL Server中实现如下:
SELECT DISTINCT CUSTOMERS.CUSTOMERID,CUSTOMERS.COMPANYNAME,CUSTOMERS.CITY,CUSTOMERS.COUNTRY
FROM CUSTOMERS INNER JOIN ORDERS ON CUSTOMERS.CUSTOMERID=ORDERS.CUSTOMERID
WHERE ORDERS.ORDERDATE BETWEEN '19970101' AND '19971231'
在Visual FoxPro中同样可以实现:
SELECT DISTINCT CUSTOMERS.CUSTOMERID,CUSTOMERS.COMPANYNAME,CUSTOMERS.CITY,CUSTOMERS.COUNTRY ;
FROM CUSTOMERS INNER JOIN ORDERS ON CUSTOMERS.CUSTOMERID=ORDERS.CUSTOMERID;
WHERE ORDERS.ORDERDATE BETWEEN {^1997-01-01} AND {^1997-12-31}
B.列出单价高于平均价的产品
这是一个必须使用子查询的例子,为什么不能用连接来实现呢?原来平均价格的产生必须通过“压缩”记录集来实现,既然记录集被压缩了,其他的表就不能连接到这个被压缩的记录集了,在SQL Server中平均价格是这样求得的:
SELECT AVG(UNITPRICE) FROM PRODUCTS
看这个记录集就只有一个字段、一条记录,其他的表与它连接是不可能的,在SQL Server中本例的最终实现如下:
SELECT PRODUCTS.PRODUCTNAME,PRODUCTS.UNITPRICE FROM PRODUCTS WHERE PRODUCTS.UNITPRICE>(SELECT AVG(UNITPRICE) FROM PRODUCTS)
在Visual FoxPro中的实现如下:
SELECT PRODUCTS.PRODUCTNAME,PRODUCTS.UNITPRICE FROM PRODUCTS WHERE PRODUCTS.UNITPRICE>;
(SELECT AVG(UNITPRICE) FROM PRODUCTS)
C.列出价格最高的10中产品
本例没有过多的技巧,这是一个定式,一定要记住。在SQL Server中可以这样实现:
SELECT TOP 10 PRODUCTNAME,UNITPRICE FROM PRODUCTS ORDER BY UNITPRICE DESC
整个过程其实是这样的:数据集先按照一定的顺序(本例是按单价降序排列),然后SQL Server检索最前面的10条记录给用户。在Visual FoxPro中这样实现:
SELECT TOP 10 PRODUCTNAME,UNITPRICE FROM PRODUCTS ORDER BY UNITPRICE DESC
D.列出价格最低的产品(希望得到的产品数量为总产品数量的5%)
在SQL Server中这样实现:
SELECT TOP 5 PERCENT PRODUCTNAME,UNITPRICE FROM PRODUCTS ORDER BY UNITPRICE
在Visual FoxPro中也一样实现:
SELECT TOP 5 PERCENT PRODUCTNAME,UNITPRICE FROM PRODUCTS ORDER BY UNITPRICE
E.列出员工间的隶属关系(一层关系即可)
这是一个自连接的典型,自连接是比较容易搞混脑袋的事情,其实我们完全可以把它想象成为两个表之间的连接,而不要把目光囿于一个表,情况或许会好些。在SQL Server中可以这样实现:
SELECT A.EMPLOYEEID AS 领导工号,A.FIRSTNAME+' '+A.LASTNAME AS 领导姓名,A.TITLE AS 领导头衔,B.EMPLOYEEID AS 下属工号,B.FIRSTNAME+' '+B.LASTNAME AS 下属姓名,B.TITLE AS 下属头衔 FROM EMPLOYEES A INNER JOIN EMPLOYEES B ON A.EMPLOYEEID=B.REPORTSTO ORDER BY A.EMPLOYEEID
在Visual FoxPro中用同样的代码实现:
SELECT A.EMPLOYEEID AS 领导工号,A.FIRSTNAME+' '+A.LASTNAME AS 领导姓名,A.TITLE AS 领导头衔,;
B.EMPLOYEEID AS 下属工号,B.FIRSTNAME+' '+B.LASTNAME AS 下属姓名,B.TITLE AS 下属头衔;
FROM EMPLOYEES A INNER JOIN EMPLOYEES B ON A.EMPLOYEEID=B.REPORTSTO ORDER BY A.EMPLOYEEID
这一周的实验做完了,不知您有什么体会?我的感觉就是学习SQL-Select一定要多加理解,有时死做死练是不起效果的,而一瞬间的开朗会使你踏破玄关!对于Visual FoxPro的程序员来说,对SQL-Select可能是又爱又恨:我们有很棒的数据操作语言、很棒的光标,所以我们不用写很长很烦的很难理解的SQL-Select也能解决问题,虽然Visual FoxPro对SQL-Select的支持也很棒(到现在为止只要SQL Server能实现的,Visual FoxPro基本上不用改变代码就能使用)。现在所有的开发工具、数据库都支持SQL-Select,特别是Visual FoxPro两层、三层构架的流行以后,SQL会越来越重要,所以不学不行!下周再见!