前言
本文将以若干实例讨论 SELECT-SQL 在Visual FoxPro 与SQL Server 中的应用。我们将采用SQL Server 2000 英语版的示例数据库 Northwind 作为蓝本,笔者已经将此数据库转换为Visual FoxPro的数据,您可以下载使用。笔者的采用的实验环境是:SQL Server 2000(E)、Visual FoxPro 7.0(E)。当然你使用SQL Server 7以及Visual FoxPro 6也同样可以得到效果,毕竟SELECT-SQL是最基本的数据库语句之一……
2001年7月28日 第一周
怎样实验
在Visual FoxPro 中我们直接在命令窗口中输入SQL语句,在SQL Server中我们使用 SQL Query Analyzer。SQL Query Analyzer的启动方法是:开始-》程序-》Microsoft SQL Server-》Query Analyzer 。如下图:
开启程序后如下:
注意:在DataBase栏目中选择NorthWind数据库。
现在就让我们正式开始!
A.在销产品
数据库中有一个产品表-Products,存储着企业历史上所有的销售过的产品,当然包括现在可供销售的产品。之所以不将那些曾经经销过的但现在不销售的产品从数据表中删除,是因为这些数据仍然被其他数据关联着,比如历史的销售记录统计时就要用到它们。Products 表使用DISCONTINUED字段表示某产品经销状况,0-在销、1-不销。所以对于SQL Server来说这句SELECT应该这样写:
SELECT PRODUCTS.PRODUCTID,PRODUCTS.PRODUCTNAME FROM PRODUCTS WHERE PRODUCTS.DISCONTINUED=0
在Visual FoxPro 中这句语句基本与SQL Server一致,只是DISCONTINUED字段在SQL Server是bit型的,也就是Visual FoxPro中的逻辑型。由于笔者使用SQL Server的DST转换NorthWind数据到Visual FoxPro数据的,它自动把bit型转换为逻辑型,所以这句SELECT在Visual FoxPro中应这样写:
SELECT PRODUCTS.PRODUCTID,PRODUCTS.PRODUCTNAME FROM PRODUCTS WHERE PRODUCTS.DISCONTINUED=.F.
B.在销产品并显示它的类别名称
这个问题延续了上一个问题,只是要得到每一种产品类别的名称。Products 表中只有CategoryID字段,CategoryName则在Categories表中。对于这种多表问题,我么们就要连接表了,在SQL Server实现如下:
SELECT PRODUCTS.*,CATEGORIES.CATEGORYNAME FROM PRODUCTS INNER JOIN CATEGORIES ON PRODUCTS.CATEGORYID=CATEGORIES.CATEGORYID
WHERE PRODUCTS.DISCONTINUED=0
PRODUCTS INNER JOIN CATEGORIES ON PRODUCTS.CATEGORYID=CATEGORIES.CATEGORYID的意思是:产生一个集合,条件是两个来源表的CATEGORYID相等。
那么SQL Server怎样产生这个集合呢?
其实计算机做了一件很傻的事情:将第个表的每一行与第二个表的每一行连接,这样就会形成N*M行数据(N表示第一个表的行数,M表示第二个表的行数,就本例而言是77*8)。
例如:第一个表如下:
col_a | col_b |
1 | a |
2 | b |
第二个表如下:
col_c | col_d |
1 | 1 |
2 | 2 |
3 | 1 |
4 | 2 |
5 | 2 |
TABLE1 INNER JOIN TABLE2 ON TABLE1.COL_A=TABLE2.COL_D
中间集合如下:(2*5=10)
col_a | col_b | col_c | col_d |
1 | a | 1 | 1 |
1 | a | 2 | 2 |
1 | a | 3 | 1 |
1 | a | 4 | 2 |
1 | a | 5 | 2 |
2 | b | 1 | 1 |
2 | b | 2 | 2 |
2 | b | 3 | 1 |
2 | b | 4 | 2 |
2 | b | 5 | 2 |
计算机做的第二件事就是:用连接条件参选结果集的数据。本例中就是ON TABLE1.COL_A=TABLE2.COL_D,在偌大的集合中砍掉连接字段不合要求的记录,下表中没有突出显示的数据就是被砍去的数据。
col_a | col_b | col_c | col_d |
1 | a | 1 | 1 |
1 | a | 2 | 2 |
1 | a | 3 | 1 |
1 | a | 4 | 2 |
1 | a | 5 | 2 |
2 | b | 1 | 1 |
2 | b | 2 | 2 |
2 | b | 3 | 1 |
2 | b | 4 | 2 |
2 | b | 5 | 2 |
于是就形成了下面的中间集合:
col_a | col_b | col_c | col_d |
1 | a | 1 | 1 |
1 | a | 3 | 1 |
2 | b | 2 | 2 |
2 | b | 4 | 2 |
2 | b | 5 | 2 |
接着这个简单的例子,补完整SQL语句:SELECT TABLE2.COL_C,TABLE1.COL_B FROM TABLE1 INNER JOIN TABLE2 ON TABLE1.COL_A=TABLE2.COL_D WHERE TABLE2.COL_C>3
计算机会根据Where字句的内容在中间集合中过滤去不合条件的数据,这里的结果是:
col_a | col_b | col_c | col_d |
1 | a | 1 | 1 |
1 | a | 3 | 1 |
2 | b | 2 | 2 |
2 | b | 4 | 2 |
2 | b | 5 | 2 |
进行到这里,计算机就会选择合适的列将最终结果列示给用户:
col_c | col_b |
4 | b |
5 | b |
对于本例的SQL,SQL Server处理的思路基本与我们这个简单的例子一样,我们就不详细说明了。在Visual FoxPro中的SELECT 的写法是:
SELECT PRODUCTS.*,CATEGORIES.CATEGORYNAME FROM PRODUCTS INNER JOIN ;
CATEGORIES ON PRODUCTS.CATEGORYID=CATEGORIES.CATEGORYID WHERE PRODUCTS.DISCONTINUED=.T.
C.列示供应商与客户
供应商信息来源于Suppliers表,客户信息来源于Customers表,只要将两个表接在一起答案就有了。在SQL Server中可以这样写:
SELECT CITY,COMPANYNAME,CONTACTNAME,'CUSTOMERS' AS RELATIONSHIP FROM CUSTOMERS
UNION ALL
SELECT CITY,COMPANYNAME,CONTACTNAME,'SUPPLIERS' FROM SUPPLIERS
在Visual FoxPro中几乎可以复制这条语句,然而事实上在这里你不能执行它。这是因为:相关字段的长度不一样,即使字段类型一致,即c(40)与c(41)是不可以连接的。在SQL Server中就没有这样苛刻的限制。笔者已经调整了Suppliers表中的相关字段的长度,所以您可以方便的使用以下语句:
SELECT CITY,COMPANYNAME,CONTACTNAME,'CUSTOMERS' AS RELATIONSHIP FROM CUSTOMERS ;
UNION ALL SELECT CITY,COMPANYNAME,CONTACTNAME,'SUPPLIERS' FROM SUPPLIERS
D.为打印详细销售情况做准备
这是一个比较复杂的SELECT语句,但它那度不高,只是参与连接的表多了一些,共有6个。作为一张完整的销售单据必须要有:销售基本情况(Orders)、销售明细(Order Details)、产品情况(Products)、销售人员(Employees)、客户情况(Customers)、运输情况(Shippers)。连接这些表的思路与前面的例子中的想法一致:先连接两个表得到中间结果集,这个数据集再与第三个表连接,得到一个数据集合……如此这样就得到了一个庞大的数据集合,于是根据Select 语句的要求提交若干字段。从中我们可以看到:数据集的拼凑才是最主要的工作、最先做的工作!
在SQL Server中的实现如下,值得注意的是表Order details 在Select 语句中用[]扩起来,以便SQL Server 识别。
SELECT ORDERS.SHIPNAME,ORDERS.SHIPADDRESS,ORDERS.SHIPCITY,ORDERS.SHIPREGION,ORDERS.SHIPPOSTALCODE,
ORDERS.SHIPCOUNTRY,ORDERS.CUSTOMERID,CUSTOMERS.COMPANYNAME AS CUSTOMERNAM,
EMPLOYEES.FIRSTNAME+' '+EMPLOYEES.LASTNAME AS SALESPERSON,
ORDERS.ORDERID,ORDERS.ORDERDATE,ORDERS.REQUIREDDATE,
ORDERS.SHIPPEDDATE,SHIPPERS.COMPANYNAME AS SHIPPERNAME,
[ORDER DETAILS].PRODUCTID,PRODUCTS.PRODUCTNAME,[ORDER DETAILS].UNITPRICE,[ORDER DETAILS].QUANTITY,[ORDER DETAILS].DISCOUNT,
[ORDER DETAILS].UNITPRICE*[ORDER DETAILS].QUANTITY*(1-[ORDER DETAILS].DISCOUNT) AS EXTENDEDPRICE, ORDERS.FREIGHT
FROM ((((EMPLOYEES INNER JOIN ORDERS ON EMPLOYEES.EMPLOYEEID=ORDERS.EMPLOYEEID)
INNER JOIN CUSTOMERS ON ORDERS.CUSTOMERID=CUSTOMERS.CUSTOMERID)
INNER JOIN SHIPPERS ON ORDERS.SHIPVIA=SHIPPERS.SHIPPERID)
INNER JOIN [ORDER DETAILS] ON ORDERS.ORDERID=[ORDER DETAILS].ORDERID)
INNER JOIN PRODUCTS ON [ORDER DETAILS].PRODUCTID=PRODUCTS.PRODUCTID
这条语句在Visual FoxPro中几乎不加修改就可以执行了。要注意的仍然是Order Details的表名问题,为方便起见笔者已经把Order Details该为了Order_details,于是语句如下:
SELECT ORDERS.SHIPNAME,ORDERS.SHIPADDRESS,ORDERS.SHIPCITY,ORDERS.SHIPREGION,ORDERS.SHIPPOSTALCODE,;
ORDERS.SHIPCOUNTRY,ORDERS.CUSTOMERID,CUSTOMERS.COMPANYNAME AS CUSTOMERNAM,;
EMPLOYEES.FIRSTNAME+' '+EMPLOYEES.LASTNAME AS SALESPERSON,;
ORDERS.ORDERID,ORDERS.ORDERDATE,ORDERS.REQUIREDDATE,;
ORDERS.SHIPPEDDATE,SHIPPERS.COMPANYNAME AS SHIPPERNAME,;
ORDER_DETAILS.PRODUCTID,PRODUCTS.PRODUCTNAME,ORDER_DETAILS.UNITPRICE,ORDER_DETAILS.QUANTITY,ORDER_DETAILS.DISCOUNT,;
ORDER_DETAILS.UNITPRICE*ORDER_DETAILS.QUANTITY*(1-ORDER_DETAILS.DISCOUNT) AS EXTENDEDPRICE, ORDERS.FREIGHT;
FROM ((((EMPLOYEES INNER JOIN ORDERS ON EMPLOYEES.EMPLOYEEID=ORDERS.EMPLOYEEID) ;
INNER JOIN CUSTOMERS ON ORDERS.CUSTOMERID=CUSTOMERS.CUSTOMERID);
INNER JOIN SHIPPERS ON ORDERS.SHIPVIA=SHIPPERS.SHIPPERID);
INNER JOIN ORDER_DETAILS ON ORDERS.ORDERID=ORDER_DETAILS.ORDERID);
INNER JOIN PRODUCTS ON ORDER_DETAILS.PRODUCTID=PRODUCTS.PRODUCTID
本周就到这里,总结一下:我们发现Visual FoxPro的SELECT 语句与SQL Server的SELECT语句很是相似,有时可以不做修改就能使用。不过每一种语言都有自己的规范,在比较时要注意各自的特点,把握住各自的特色。