《2022年SQL多层查询 .pdf》由会员分享,可在线阅读,更多相关《2022年SQL多层查询 .pdf(7页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、多层 SQL 查询基础举例讲解顾名思义,多层的 SQL 查询的便在于:“在一个 SQL 语句中可以包含另一个SQL 查询语句,形成内部嵌套的查询类型。”comparisonANY|ALL|SOME(sqlstatement)expressionNOTIN(sqlstatement)NOTEXISTS(sqlstatement)comparison 将表达式与内层查询的结果比较的操作。expression 对内层查询的结果作搜索的表达式。sqlstatement 为 Select 语句构成的SQL 查询,必须用()将该语句括起来。例如:我们先从订单表格当中,查询出所有的单位,再将产品表格中的单位
2、与的一一对比,查询出所有高于订单表格的单位价格的记录。Select*FROM 产品表格Where 单位价格 ANY(Select 单位价格FROM 订单表格Where 折扣=.25);有些书上将内嵌的select 语句称为子查询,子查询形成的结果又成为父查询的条件。子查询可以嵌套多层,子查询操作的数据表可以是父查询不操作的数据表。子查询中不能有order by 分组语句。再例如:select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal=(select sal from scott.emp where ename=WA
3、RD);在这段代码中,子查询 select sal from scott.emp where ename=WARD 的含义是从emp 数据表中查询姓名为WARD 的员工的薪水,父查询的含义是要找出emp 数据表中薪水大于等于WARD 的薪水的员工。上面的查询过程等价于两步的执行过程。(1)执行“select sal from scott.emp where ename=WARD”,得出 sal=1250;(2)执行“select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal=1250;”带 in 的嵌套查询select
4、 emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal in(select sal from scott.emp where ename=WARD);上述语句完成的是查询薪水和WARD 相等的员工,也可以使用not in 来进行查询。带 any 的嵌套查询select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal any(select sal from scott.emp where job=MANAGER);带 any 的查询过程等价于两步的执行过程
5、。(1)执行“select sal from scott.emp where job=MANAGER”(2)查询到3 个薪水值2975、2850 和 2450,父查询执行下列语句:select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal 2975 or sal2850 or sal2450;带 some 的嵌套查询名师资料总结-精品资料欢迎下载-名师精心整理-第 1 页,共 7 页 -select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal
6、=some(select sal from scott.emp where job=MANAGER);(1)子查询,执行“select sal from scott.emp where job=MANAGER”。(2)父查询执行下列语句。select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal=2975 or sal=2850 or sal=2450;带【any】的嵌套查询和【some】的嵌套查询功能是一样的。早期的SQL 仅仅允许使用【any】,后来的版本为了和英语的【any】相区分,引入了【some】,同时还保留
7、了【any】关键词。带 all 的嵌套查询select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal all(select sal from scott.emp where job=MANAGER);带 all 的嵌套查询与【some】的步骤相同。(1)子查询。(2)父查询执行下列语句。select emp.empno,emp.ename,emp.job,emp.sal from scott.emp where sal 2975 and sal2850 and sal2450;带 exists 的嵌套查询select
8、emp.empno,emp.ename,emp.job,emp.sal from scott.emp,scott.dept where exists(select*from scott.emp where scott.emp.deptno=scott.dept.deptno);并操作的嵌套查询并操作就是集合中并集的概念。属于集合A 或集合 B 的元素总和就是并集。(select deptno from scott.emp)union(select deptno from scott.dept);交操作的嵌套查询交操作就是集合中交集的概念。属于集合A 且属于集合B 的元素总和就是交集。(sele
9、ct deptno from scott.emp)intersect(select deptno from scott.dept);差操作的嵌套查询差操作就是集合中差集的概念。属于集合A 且不属于集合B 的元素总和就是差集。select deptno from scott.dept)minus(select deptno from scott.emp;并、交和差操作的嵌套查询要求属性具有相同的定义,包括类型和取值范围。第九章查询数据库这一章介绍如何用TQuery 构件查询数据库,如何通过SQL 语句检索、插入、更新和删除数据。SQL 是符合工业标准的关系数据库语言,既可以用于远程的基于服务器的
10、数据库,如 Sybase、Oracle、InterBase 和 Microsoft SQL Server,也可以用于本地数据库如Paradox、dBASE、FoxPro 和 Access 以及符合ODBC 的数据库。9.1 有效地使用查询要有效地使用查询,必须熟悉标准的SQL 语言以及所使用的服务器对SQL-92 的限制和扩展,同时还要熟悉BDE。9.1.1 查询桌面数据库作为一个桌面开发者,应对表格、记录和字段的概念有所了解,又能熟练地使用TTable 构件访问数据集中的每一条记录和每一个字段。还可以使用TTable 的范围和过滤功能在数据集中选择一部分记录,前者用于选择一块连续的记录,这些
11、记录的值在一个特定的范围内;后者用于选择非连续的记录,这些记录符合特定的条件。所谓查询,非常类似于过滤,不同的是,查询要用到TQuery 构件和 SQL 属性,有时候可能还要用到Params 属性。名师资料总结-精品资料欢迎下载-名师精心整理-第 2 页,共 7 页 -从功能上讲,查询要比过滤复杂和强大些,这主要体现在:.可以同时查询几个表格.可以让查询结果中只包含部分字段,而过滤将返回所有字段。查询也可以带参数,此时称为参数化查询。所谓参数,类似于变量,它的实际的值由BDE 在执行SQL 语句之前赋值。参数化查询的好处是,不需要修改SQL 语句,只要修改参数的值,就能执行不同的查询功能。大部
12、分情况下,使用TQuery 构件是为了在数据集中选择一部分字段和记录,但也可以使用SQL 语句实现更新、插入和删除记录的功能,这是与TTable 构件的一个区别。9.1.2 查询远程数据库要查询远程数据库,必须熟悉SQL 语句以及服务器对标准SQL 的限制和扩展。TQuery 构件的 SQL 属性用于指定要执行的SQL 语句,Params属性用于提供参数。TQuery 构件的功能并不只限于 SQL 语句和参数,它还是BDE 与应用程序之间的接口。应用程序可以通过TQuery 构件的属性和方法来操纵SQL 语句和参数。TQuery 构件最终还是通过SQL Links 与远程服务器进行通讯的,远程
13、服务器把查询结果返回给BDE,再由 BDE 返回给应用程序。9.2 可以查询哪些数据库使用 TQuery 构件可以查询下列数据库:一是 Paradox 或 dBASE,这是通过BDE 内置的 Local SQL 实现的。Local SQL 是 SQL-92 标准的一个子集,支持大部分 DML 和 DDL。二是 Local InterBase Server,这是通过InterBase 引擎实现的。三是远程数据库,如 Oracle、Sybase、MS-SQL Server、InFormix、DB2 和 InterBase,不过,必须安装了相应的SQL Links 驱动程序。不同的服务器对标准SQL
14、 都有不同的限制和扩展,要查询远程数据库之前,务必要查阅它的有关文档。Delphi 4 还支持异构查询,也就是说,可以同时查询几个不同类型的数据库。9.3 使用 TQuery 构件的一般步骤第一步是把一个TQuery 构件放到数据模块上,设置它的DatabaseName 属性指定要访问的数据库。对于Paradox和 dBASE 来说,DatabaseName 属性可以设为BDE 别名如 DBEMOS、DefaultDD、IBLOCAL等,也可以是自定义的别名或者表所在的路径。对于 SQL 表来说,DatabaseName 属性只能设为BDE 别名。如果应用程序使用TDatabase 构件来连接
15、数据库,DatabaseName属性也可以设为应用程序专用的别名。第二步是设置SQL 属性指定要执行的SQL 语句,有必要的话还可以设置Params属性为 SQL 语句设置参数。第三步是把TDataSource 构件放到数据模块上,设置它的DataSet 属性指定TQuery 构件。再把TDBGrid 构件放到窗体上,设置它的DataSource 属性指定TDataSource 构件。第四步是执行SQL 语句。要执行SQL 语句有两种方式,一是在设计期把Active 属性设为True,程序启动时将自动执行 SQL 语句。另一种方式是在运行期调用Open 或 ExecSQL 执行 SQL 语句。
16、如果希望返回查询结果,调用 Open,如果不需要返回查询结果,调用ExecSQL。在调用 Open 或 ExecSQL 之前,最好先调用Prepare 通知服务器作好准备。执行 SQL 语句所返回的查询结果实际上是数据集中满足特定条件的记录所组成的子集,数据库栅格中只显示符合特定条件的记录。9.4 指定要执行的SQL 语句可以设置SQL 属性以指定要执行的SQL 语句。在设计期,只要把 Active 属性设为True,就会自动执行SQL 语句。在运行期,首先要调用Prepare 通知服务器准备好,然后调用Open 或 ExecSQL 执行 SQL 函数语句。9.4.1 概述SQL 属性是一个典
17、型的TStrings 对象。SQL 属性一般只包含一条完整的SQL 语句,但可以分成几行写,TQuery构件会自动把几行字符串合并成一条SQL 语句。把 SQL 语句分成几行写的好处是,SQL 语句的逻辑结构比较清楚,有利于今后维护和调试。所以,SQL 语句的SELECT 部分和 WHERE 部分一般都不在同一行上。SQL 语句可以不带参数,把字段名称和值固定在SQL 语句中,例如,下面这个SQL 语句就是硬写(Hard-Coded)的:SELECT*FROM Customer WHERE CustNo=1231 注意:如果要查询的是本地数据库,如果SQL 语句中的字段名包含空格或其他特殊符号
18、,必须用引号括起来,前面还要加上表格名和小圆点。如果用参数的话,查询就灵活得多,应用程序不需要改写SQL 语句本身,只要修改参数的值,就能使 SQL 语句执名师资料总结-精品资料欢迎下载-名师精心整理-第 3 页,共 7 页 -行不同的查询功能。在执行SQL 语句之前,TQuery 构件会自动把实际的值替换SQL 语句中的参数,即使并没有显式地调用 Prepare函数。下面这条SQL 语句是典型的参数化查询:SELECT*FROM Customer WHERE CustNo=:Number 其中,Number 就是一个参数,它的前面必须加冒号。在运行期,应用程序必须提供Number 参数的值,
19、每次执行SQL 语句时,Number 参数的值可以不同。参数的值是通过TQuery 的 Params 属性提供的。9.4.2 在设计期指定SQL 语句在设计期,要指定 SQL 语句,可以在对象观察器中单击SQL 属性边上的省略号按钮,弹出一个字符串列表编辑器,如图 9.1 所示。图 9.1 在设计期指定SQL 语句SQL 语句可以分成几行写,但同一单词不能分开。一般情况下,SQL 属性只能包含一条完整的SQL 语句,但有些服务器允许同时执行几条SQL 语句,这种情况下,可以输入多条SQL 语句。如果使用 Delphi 4 的 Client/Server 版本或 Enterprise 版本,也可
20、以用SQLBuilder 这个实用工具来建立SQL 语句。要使用 SQL Builder,在 TQuery 构件上单击鼠标右键,在弹出的菜单中选择“SQL Builder”命令。9.4.3 在运行期指定SQL 语句在运行期,要指定SQL 属性有三种方式,一是直接设置SQL 属性,二是调用LoadFromFile 从文件中读取SQL 语句,或者从另一个TStrings 对象中获得SQL 语句。在直接设置SQL 属性之前,首先要调用Close 函数。如果SQL 属性中本来已经有了SQL 语句,还要调用Clear把原来的 SQL 语句清除。下面的代码演示了怎样在运行期直接设置SQL 属性:With
21、CustomerQuery Do Begin Close;With SQL Do Begin Clear;Add(SELECT*FROM Customer);Add(WHERE Company=Light Diver);End;Open;End;有时候,可能想在原来的SQL 语句的基础上修改或增加一行,这时候就不能调用Clear 把原来的SQL 语句清掉,例如:CustomerQuery.SQL1:=WHERE Company=Light Diver;也可以调用LoadFromFile 从文件中获取SQL 语句,这主要是因为TStrings 对象支持文件操作。LoadFromFile 会自动把
22、原来的SQL 语句清掉。下面的代码是调用LoadFromFile 的例子:CustomerQuery.Close;CustomerQuery.SQL.LoadFromFile(c:orders.txt);CustomerQuery.Open;还可以从另一个TStrings 对象中获取SQL 语句,这就要调用TStrings 的 Assign 函数。Assign 会自动把原来的SQL语句清空。下面的代码是调用Assign 的例子:CustomerQuery.Close;CustomerQuery.SQL.Assign(Memo1.Lines);CustomerQuery.Open;9.5 参 数
23、要使用参数化查询,必须在SQL 语句中加入参数,例如:INSERT INTO Country(Name,Capital,Population)名师资料总结-精品资料欢迎下载-名师精心整理-第 4 页,共 7 页 -VALUES(:Name,:Capital,:Population)其中,Name、Capital 和 Population 是三个参数。在执行上述SQL 语句之前,应用程序应当调用Prepare函数通知BDE 和服务器预先分配好资源,以加快查询速度。程序示例如下:With Query1 Do Begin Close;Unprepare;ParamByName(Name).AsStr
24、ing:=China;ParamByName(Capital).AsString:=Beijing;ParamByName(Population).AsInteger:=120000;Prepare;Open;End;9.5.1 在设计期提供参数要在设计期提供参数,单击Params属性边上的省略号按钮,弹出如图9.2 所示的编辑器。图 9.2 在设计期设置Params属性如果 SQL 语句中没有包含任何参数,图9.2 所示的编辑器就是空白的。这个编辑器的工具栏总是禁止的,这意味着只能在 SQL 语句中加入参数。选择其中一个参数(TParam 对象),就可以在对象观察器中设置它的属性,或者建立事
25、件句柄。TParam 的主要属性有:DataType 属性用于指定参数的数据类型,它的初始值总是ftUnknown,必须设置每个参数的数据类型。ParamType 属性用于指定参数的使用类型,它的初始值也是ptUnknown。Value 属性用于给出参数的值。当然,也可以在运行期给出参数的值。9.5.2 在运行期提供参数要在运行期访问参数,有三种方式:一是通过 ParamByName 函数按名称访问参数。二是通过 Params属性按序号访问参数。三是通过 TParams 对象的 ParamValues属性按名称访问参数。假设一条SQL 语句有三个参数:INSERT INTO COUNTRY.D
26、B(Name,Capital,Continent)VALUES(:Name,:Capital,:Continent)下面这行代码通过ParamByName 函数来访问其中的Capital 参数:Query1.ParamByName(Capital).AsString:=Edit1.Text;下面这行代码通过Params 属性来访问其中的Name 参数:Query1.Params0.AsString:=Edit1.Text;下面这行代码通过TParams 对象的 ParamValues属性来同时访问三个参数:Query1.Params.ParamValuesCountry;Capital;Con
27、tinent:=VarArrayOf(Edit1.Text,Edit2.Text,Edit3.Text);9.5.3 从另一个数据集获得参数TQuery 构件的 DataSource 属性用于指定一个数据源(TDataSource 构件),如果应用程序既没有在设计期也没有在运行期给参数赋值,它就在这个数据源中查找与参数名匹配的字段,然后用这个字段的值作为参数的值。假设一个数据模块叫LinkModule,上面有一个TQuery 构件叫 OrdersQuery,它的 SQL 语句如下:SELECT CustNo,OrderNo,SaleDate FROM OrdersWHERE CustNo=:C
28、ustNo 另外,数据模块上还有下列构件:.一个 TTable 构件叫 CustomersTable,它的 TableName 属性设为CUSTOMER.DB。.一个 TDataSource 构件叫 OrdersSource,它的 DataSet属性设为OrdersQuery。.一个 TDataSource 构件叫 CustomersSource,它的 DataSet 属性设为CustomersTable。.OrdersQuery 的 DataSource属性也设为CustomersSource。名师资料总结-精品资料欢迎下载-名师精心整理-第 5 页,共 7 页 -假设应用程序有一个窗体叫L
29、inkedQuery,窗体上有两个TDBGrid构件,它们的DataSource 属性分别指定CustomersSource和 OrdersSource。如果编译和运行这个应用程序,将看到如图9.3 所示的效果:图 9.3 从另一个数据集获得参数这里简单解释一下图9.3。如果没有对SQL 语句中的:CustNo 参数赋值,OrdersQuery 将试图从CustomersSource指定的数据集中查找匹配的字段。由于 CustomersSource是从 CUSTOMER.DB中获取数据的,而 CUSTOMER.DB中恰好有一个 CustNo 字段,所以,:CustNo 参数的值就是CustNo
30、 字段的值。如果您在显示CUSTOMER.DB的栅格中选择了另一条记录,将导致:CustNo 参数的值跟着变化。9.6 执 行 查 询当指定了SQL 语句并且提供了参数后,就可以执行查询了。如果是第一次执行查询,最好调用Prepare通知 BDE或服务器做好准备,这样能加快查询的速度。既可以在设计期执行查询,也可以在运行期执行查询。要在设计期执行查询,只要把Active 属性设为True。不过,在设计期能执行的SQL 语句,仅限于SELECT 语句,不能是 INSERT、UPDATE 或 DELETE 语句。要在运行期执行查询,可以调用Open 或 ExecSQL 函数,其中,Open 适合于
31、执行SELECT 语句,而ExecSQL 适合于执行 INSERT、UPDATE 或 DELETE 语句,后者不返回结果。在调用 Open 或 ExecSQL 之前,首先要调用Close。程序示例如下:CustomerQuery.Close;CustomerQuery.Open;如果在编程的时候无法确定是否要返回查询结果,可以用Try.Except 结构把这两个过程都写进去,一般Open 在Try 部分调用,而ExecSQL 在 Except 部分调用,这样,即使Open 调用失败,也能执行到ExecSQL。程序示例如下:Try Query2.Open;Except On E:Exceptio
32、n Do If not(E is ENoResultSet)then Raise;End;前面多次提到,在执行查询前最好先调用Prepare,尽管这并不是必须的。预先调用Prepare 能够改善应用程序的性能。程序示例如下:CustomerQuery.Close;If not(CustomerQuery.Prepared)then CustomerQuery.Prepare;CustomerQuery.Open;上述程序首先调用Close,然后检查Prepared属性,如果这个属性返回True,表示已经准备好,如果这个属性返回False,表示没有准备好,此时就要调用Prepare。9.7 异
33、构 查 询所谓异构查询,就是同时查询几个不同的数据库。这些数据库的类型可以不同。例如,可以同时查询Oracle 数据库、Sybase数据库和本地的dBASE 表。当程序执行异构查询的时候,BDE 通过 Local SQL 来分析和处理这个查询,而不是用与服务器相关的特定的SQL 语法。建立一个异构查询的一般步骤是这样的:第一步,把一个TQuery 构件放到窗体或数据模块上,让DatabaseName 属性空着。第二步,为要查询的每一个数据库建立一个单独的BDE 别名。第三步,设置SQL 属性以指定要执行的SQL 语句。在SQL 语句中,表的名字前要加别名和冒号,并且用双引号括起来。字段名前要加
34、表名和小圆点。例如:SELECT Customer.CustNo,Orders.OrderNo FROM Oracle1:CUSTOMER JOIN Sybase1:ORDERS ON(Customer.CustNo=Orders.CustNo)WHERE(Customer.CustNo=1503)第四步,设置Params属性提供参数。名师资料总结-精品资料欢迎下载-名师精心整理-第 6 页,共 7 页 -第五步,调用 Prepare通知 BDE 或服务器做好准备,然后调用 Open或 ExecSQL 执行查询。如果显式地使用TDatabase构件连接数据库,并且设置了它的DatabaseNa
35、me属性定义了应用程序专用的别名,在SQL 语句中可以用专用的别名代替 BDE 别名。9.8 查 询 结 果默认情况下,查询结果是只读的。应用程序可以用数据控件去显示查询结果,但用户不能编辑数据。怎样才能使用户能够编辑数据呢?要使用户能够编辑数据,必须把TQuery 构件的RequestLive 属性设为True。不过,把RequestLive 属性设为True并不能保证查询结果一定是可以修改的,因为这还取决于查询使用的是Local SQL 还是与服务器相关的SQL。像查询 Paradox 或 dBASE 以及异构查询都是使用Local SQL,而查询远程服务器则使用与服务器相关的SQL。即使 RequestLive 属性设为True,而且查询的是本地数据库,但由于SELECT 语句的文法不合适,BDE 也将返回只读的查询结果。因此,在编辑数据之前,先要访问CanModify 属性。只有当这个属性返回True 时,才表示查询结果是可编辑的。名师资料总结-精品资料欢迎下载-名师精心整理-第 7 页,共 7 页 -