oracle inner join

来源:互联网 发布:java调用存储函数 编辑:程序博客网 时间:2024/05/20 13:40
用 INNER JOIN语法联接多个表建记录集

作者:2出处:互联网
[ 2006-11-02 00:07 ]
摘要:

    本教程是把五个表联在一起,如果愿意,您可以将更多的表联在一起,方法大同小异啦~
   
    步骤一:用Access软件建立一个名为Member的数据库,在其中建五个表,分别为:会员信息数据表member、会员身份表MemberIdentity、会员权限表MemberLevel、会员类别表MemberSort和会员婚姻状况表Wedlock。
   
    ●会员信息数据表member:
    MemberID:自动编号,主键(ID号)
    MemberSort:数字(会员类别)
    MemberName:文本,会员姓名
    Password:文本(会员密码)
    MemberLevel:数字(会员权限)
    MemberIdentity:数字(会员身份)
    Wedlock:数字(婚姻状况)
    MemberQQ:文本(QQ号码)
    MemberEmail:文本(会员邮箱)
    MemberDate:日期/时间(会员注册日期)
   
    ●会员身份表MemberIdentity:
    MemberIdentity:自动编号,主键(ID号)
    IdentityName:文本(会员身份名称)
   
    ●会员权限表MemberLevel:
    MemberLevel:自动编号,主键(ID号)
    LevelName:文本(会员权限名称)
   
    ●会员类别表MemberSort:
    MemberSort:自动编号,主键(ID号)
    SortName:文本(会员类别名称)
   
    ●会员婚姻状况表Wedlock
    Wedlock:自动编号,主键(ID号)
    WedlockName:文本(会员婚姻状况类别)
    说明:五个表建好后,您可以自行设置您想要的类别,如会员权限,您可以设置两个类别--“未付费会员”和“已付费会员”,编号分别为“1”、“2”,如您设置了三个选项,那么第三个选项的编号当然就是“3”了。
    下面我们所要作的工作就是把“1”、“2”之类的编号显示为“未付费会员”和“已付费会员”,否则,大家谁会知道“1”代表的是“未付费会员”,“2”代表的是“已付费会员”?
   
    步骤二:建DSN数据源,建记录集
    ●运行Dreamweaver MX软件,在会员注册信息显示页面建一个名为ConnMember(您也可以起其它的名称)的DSN数据源。
   
    ●点击服务器行为面板中的“绑定”,建一个名为MemberShow的数据集,“连接”选择ConnMember,“表格”选择Member,“列”全选,“排序”选择MemberDate,降序。点击“高级”按钮,修改SQL框中自动生成的代码:
    原代码为:
    SELECT *
    FROM Member
    ORDER BY MemberDate DESC
   
    将代码修改为:
    SELECT *
    FROM (((Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel) INNER JOIN MemberIdentity ON Member.MemberIdentity=MemberIdentity.MemberIdentity) INNER JOIN Wedlock ON Member.Wedlock=Wedlock.Wedlock
    ORDER BY MemberDate DESC
    修改完代码后,点击“确定”,大功告成!
    现在,您可以打开记录集看一下,五个表中的字段全部集成在MemberShow记录集中,您只要将相应的字段绑定在该字段想显示的单元格中即可。这下好了,所有的数字编号全部变成了相应的名称,如会员权限,不再是“1”和“2”的数字形式了,而是变成了相应的名称“未付费会员”和“已付费会员”。其它的数字编号也变成了显示的文本名称,是不是很开心呢?
   
    注意事项:
    ●在输入字母过程中,一定要用英文半角标点符号,单词之间留一半角空格;
    ●在建立数据表时,如果一个表与多个表联接,那么这一个表中的字段必须是“数字”数据类型,而多个表中的相同字段必须是主键,而且是“自动编号”数据类型。否则,很难联接成功。
    ●代码嵌套快速方法:如,想连接五个表,则只要在连接四个表的代码上加一个前后括号(前括号加在FROM的后面,后括号加在代码的末尾即可),然后在后括号后面继续添加“INNER JOIN 表名X ON 表1.字段号=表X.字段号”代码即可,这样就可以无限联接数据表了:)
   
    语法格式:
    其实 INNER JOIN ……ON的语法格式可以概括为:
    FROM (((表1 INNER JOIN 表2 ON 表1.字段号=表2.字段号) INNER JOIN 表3 ON 表1.字段号=表3.字段号) INNER JOIN 表4 ON Member.字段号=表4.字段号) INNER JOIN 表X ON Member.字段号=表X.字段号
    您只要套用该格式就可以了。
   
    现成格式范例:
    虽然我说得已经比较明白了,但为照顾初学者,我还是以本会员注册系统为例,提供一些现成的语法格式范例,大家只要修改其中的数据表名称和字段名称即可。
   
    连接两个数据表的用法:
    FROM Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort
    语法格式可以概括为:
    FROM 表1 INNER JOIN 表2 ON 表1.字段号=表2.字段号
   
    连接三个数据表的用法:
    FROM (Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel
    语法格式可以概括为:
    FROM (表1 INNER JOIN 表2 ON 表1.字段号=表2.字段号) INNER JOIN 表3 ON 表1.字段号=表3.字段号
   
    连接四个数据表的用法:
    FROM ((Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel) INNER JOIN MemberIdentity ON Member.MemberIdentity=MemberIdentity.MemberIdentity
    语法格式可以概括为:
    FROM ((表1 INNER JOIN 表2 ON 表1.字段号=表2.字段号) INNER JOIN 表3 ON 表1.字段号=表3.字段号) INNER JOIN 表4 ON Member.字段号=表4.字段号
   
    连接五个数据表的用法:
    FROM (((Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel) INNER JOIN MemberIdentity ON Member.MemberIdentity=MemberIdentity.MemberIdentity) INNER JOIN Wedlock ON Member.Wedlock=Wedlock.Wedlock
    语法格式可以概括为:
    FROM (((表1 INNER JOIN 表2 ON 表1.字段号=表2.字段号) INNER JOIN 表3 ON 表1.字段号=表3.字段号) INNER JOIN 表4 ON Member.字段号=表4.字段号) INNER JOIN 表5 ON Member.字段号=表5.字段号
   
    连接六个数据表的用法:略,与上述联接方法类似,大家举一反三吧:)  
[转载]公用表表达式的典型应用
===========================================================

转载自ASA SQL用户指南

公用表表达式(CTE):Common Table Expression

使用 SELECT 语句的 WITH 前缀,您可以定义公用表表达式。您可以像使用临时视图一样在查询中使用这些公用表表达式。

===============================================================

NinGoo:本文虽然是基于Sybase的,但是公用表表达式在Oracle中的使用和语法基本相同,但是Oracle中的公用表表达式不支持列别名,也就是如下的语法在Sybase中是合法的,在oracle中会报错:

with test_table(col1,col2)
as (select col1,col2 from test)
select * from test_table;

ORA-32033: 不支持列别名

所以,在oracle中,语法如下:

with test_table
as (select col1,col2 from test)
select * from test;

MS SQL Server2005也支持CTE:http://msdn2.microsoft.com/zh-cn/library/ms190766.aspx

==============================================================


公用表表达式是使用 WITH 子句定义的,该子句在 SELECT 语句中的 SELECT 关键字前面。子句的内容定义了之后可能会在语句中的其它位置引用的一个或多个临时视图。此子句的语法模拟 CREATE VIEW 语句的语法。您可以使用公用表表达式来表达上一个查询,如下所示。

WITH CountEmployees(dept_id, n) AS  ( SELECT dept_id, count(*) AS n    FROM employee GROUP BY dept_id )SELECT dept_id, nFROM CountEmployeesWHERE n = ( SELECT max(n)            FROM CountEmployees )

改为搜索雇员最少的部门说明这种查询可以返回多个行。

WITH CountEmployees(dept_id, n) AS  ( SELECT dept_id, count(*) AS n    FROM employee GROUP BY dept_id )SELECT dept_id, nFROM CountEmployeesWHERE n = ( SELECT min(n)            FROM CountEmployees )

在示例数据库中,两个部门共享着最少数量(即 9 名)的雇员。

一般而言,只要表的表达式必须在一个查询中出现多次,公用表表达式就很有用。下面的典型情况适合于公用表表达式。

  • 涉及多个集合函数的查询。

  • 过程中必须包含对程序变量的引用的视图。

  • 使用临时视图存储一组值的查询。

此列表并不完整。您可能会遇到许多其它要使用公用表表达式的情况。

多个集合函数

只要必须在一个查询中显示多个级别的集合,公用表表达式就很有用。这是上一部分使用的示例中的情况。任务是检索雇员数量最多的部门的部门 ID。为此,要使用 count 集合函数来计算每个部门的雇员数量,并使用 max 函数选择最大的部门。

在编写查询来确定哪个部门的工资额最多时,会出现类似的情况。sum 集合函数用于计算每个部门的工资额,而 max 函数用于确定哪个部门最大。查询中同时出现这两个函数表明公用表表达式可能有用。

WITH DeptPayroll( dept_id, amt ) AS    ( SELECT dept_id, sum(salary) AS amt      FROM employee GROUP BY dept_id )SELECT dept_id, amtFROM DeptPayrollWHERE amt = ( SELECT max(amt)              FROM DeptPayroll )
引用程序变量的视图

有时,公用表表达式对创建包含对程序变量的引用的视图可能会很方便。例如,您可以定义过程中标识特定客户的变量。您要查询该客户的购买历史记录,并且如果您要多次访问类似信息或者可能会使用多个集合函数,则您需要创建一个包含有关该特定客户的信息的视图。

您无法创建引用程序变量的视图,因为无法将视图范围限制为您的过程的范围。一旦创建了视图,就可以在其它环境中使用它。但是,您可以在您的过程中的查询内使用公用表表达式。因为公用表表达式的范围限制到语句,所以变量引用不会造成任何多义性,因此可以使用变量引用。

下面的语句在示例数据库中选择各位不同销售代表的销售总额。

SELECT emp_fname || ' ' || emp_lname AS sales_rep_name,       sales_rep AS sales_rep_id,       sum( p.unit_price * i.quantity ) AS total_salesFROM employee LEFT OUTER JOIN sales_order AS o              INNER JOIN sales_order_items AS i              INNER JOIN product AS pWHERE '2000-01-01' <= order_date                  AND order_date < '2001-01-01'GROUP BY sales_rep, emp_fname, emp_lname

上面的查询是出现在下面过程中的公用表表达式的基础。销售代表的 ID 号和所讨论的年份是即将使用的参数。如此过程所示,可在 WITH 子句中引用过程参数和任何已声明的局部变量。

CREATE PROCEDURE sales_rep_total (  IN rep  INTEGER,  IN yyyy INTEGER )BEGIN  DECLARE start_date DATE;  DECLARE end_date   DATE;  SET start_date = YMD( yyyy,  1,  1 );  SET   end_date = YMD( yyyy, 12, 31 );  WITH total_sales_by_rep ( sales_rep_name,                            sales_rep_id,                            month,                            order_year,                            total_sales ) AS  ( SELECT emp_fname || ' ' || emp_lname AS sales_rep_name,           sales_rep AS sales_rep_id, month( order_date),           year(order_date),           sum( p.unit_price * i.quantity ) AS total_sales    FROM employee LEFT OUTER JOIN sales_order o                       INNER JOIN sales_order_items i                       INNER JOIN product p    WHERE start_date <= order_date AND                        order_date <= end_date AND          sales_rep = rep    GROUP BY year(order_date), month(order_date),             emp_fname, emp_lname, sales_rep )  SELECT sales_rep_name,            monthname( YMD(yyyy, month, 1) ) AS month_name,            order_year,            total_sales  FROM total_sales_by_rep  WHERE total_sales =    ( SELECT max( total_sales) FROM total_sales_by_rep )  ORDER BY order_year ASC, month ASC;END;

下面的语句说明了如何调用上面的过程。

CALL sales_rep_total(129, 2000);
存储值的视图

有时,公用表表达式在某个 SELECT 语句或某个过程中存储一组特定的值会很有用。例如,假定一家公司要按三分之一年度而不是按季度分析它的销售人员的结果。由于没有代表三分之一的内置日期部分(虽然有代表季度的内置日期部分),所以有必要将这些日期存储在过程中。

WITH thirds (q_name, q_start, q_end) AS( SELECT 'T1', '2000-01-01', '2000-04-30' UNION  SELECT 'T2', '2000-05-01', '2000-08-31' UNION  SELECT 'T3', '2000-09-01', '2000-12-31' )SELECT q_name,       sales_rep,       count(*) AS num_orders,       sum( p.unit_price * i.quantity ) AS total_salesFROM thirds LEFT OUTER JOIN sales_order AS o    ON q_start <= order_date AND order_date <= q_end                   INNER JOIN sales_order_items AS i                   INNER JOIN product AS p GROUP BY q_name, sales_rep ORDER BY q_name, sales_rep

使用此方法时应该小心,因为值可能需要定期维护。例如,如果要为任何其它年度使用上面的语句,则必须对它进行修改。

您还可以在过程中应用此技术。下面的示例声明了一个过程,该过程将所讨论的年份作为参数。

CREATE PROCEDURE sales_by_third ( IN y INTEGER )BEGIN  WITH thirds (q_name, q_start, q_end) AS  ( SELECT 'T1', YMD( y, 01, 01), YMD( y, 04, 30) UNION    SELECT 'T2', YMD( y, 05, 01), YMD( y, 08, 31) UNION    SELECT 'T3', YMD( y, 09, 01), YMD( y, 12, 31) )  SELECT q_name,         sales_rep,         count(*) AS num_orders,         sum(p.unit_price * i.quantity) AS total_sales  FROM thirds JOIN sales_order AS o    ON q_start <= order_date AND order_date <= q_end            KEY JOIN sales_order_items AS i            KEY JOIN product AS p  GROUP BY q_name, sales_rep  ORDER BY q_name, sales_rep;END;
CALL sales_by_third (2000);

(需要引用, 请注明出处: http://ningoo.itpub.net)

 

Oracle 9i表连接

0

原文地址:http://blog.csdn.net/xuanxingmin/archive/2006/10/31/1358159.aspx

本文Tag:oracle 9i, 表连接, 连接, ... 作者:轩兴民 来源:csdn.net 发表于29天以前

 一般的相等连接(内连接): select a.*,b.* from a, b where a.id = b.id; 或 select * from a, b where a.id = b.id; 以上这两个是等价的。一般的相等连接也可以写成这样: select * from a inner join b on a.id = b.id 外连接: Oracle中可以使用“(+) ”来表示,9i可以使用LEFT/RIGHT/FULL OUTER JOIN    LEFT OUTER JOIN:左外关联  SELECT e.last_name, e.department_id, d.department_name  FROM employees e  LEFT OUTER JOIN departments d  ON (e.department_id = d.department_id);  等价于  SELECT e.last_name, e.department_id, d.department_name  FROM employees e, departments d  WHERE

点击数量:6

 

以下的SQL语句在服务器需要运行长达30分钟才能完成:
SELECT     dbo.ComFlow.ComFlowCode, dbo.ComFlow.ComCode, dbo.ComFlow.CustCode, dbo.ComFlow.DepartCode, dbo.ComFlow.SaleCode,
                      dbo.ComFlow.EmpCode, dbo.ComFlow.Quantity * dbo.Commodity.ConvertRate AS Quantity, CONVERT(datetime, DATENAME(yyyy,
                      dbo.ComFlow.FlowDate) + '-' + DATENAME(mm, dbo.ComFlow.FlowDate) + '-' + DATENAME(dd, dbo.ComFlow.FlowDate)) AS FlowDate,
                      dbo.ComFlow.SalType, dbo.Employee.DepartCode AS DepartIn, dbo.Sale.DepartCode AS DepartOut,
                      dbo.ComFlow.Quantity * dbo.Commodity.TradePrice * dbo.Commodity.Discount / 100 AS Total, dbo.Department.GrpCode AS GrpCodeIn,
                      Department1.GrpCode AS GrpCodeOut
FROM         dbo.ComFlow INNER JOIN
                      dbo.Customer ON
                dbo.ComFlow.SalType IN (N'促销', N'流向退货', N'多级流向') AND dbo.ComFlow.CustCode = dbo.Customer.CustCode
                Or ComFlow_1.SalType IN (N'自然流向', N'自然流向退货') AND ComFlow_1.OutCustCode = Customer_1.CustCode
            INNER JOIN
                      dbo.CustomerRelation ON dbo.ComFlow.ComCode = dbo.CustomerRelation.ComCode AND
                      dbo.CustomerRelation.CustCode = dbo.Customer.CustCode INNER JOIN
                      dbo.Employee ON dbo.CustomerRelation.EmpCode = dbo.Employee.EmpCode INNER JOIN
                      dbo.Sale ON dbo.ComFlow.SaleCode = dbo.Sale.SaleCode INNER JOIN
                      dbo.Department ON dbo.Department.DepartCode = dbo.Employee.DepartCode INNER JOIN
                      dbo.Department AS Department1 ON Department1.DepartCode = dbo.Sale.DepartCode AND
                      dbo.Department.GrpCode <> Department1.GrpCode INNER JOIN
                      dbo.Commodity ON dbo.ComFlow.ComCode = dbo.Commodity.ComCode
WHERE     (NOT (dbo.ComFlow.SalType = N'流向退货')) OR
                      (NOT (dbo.Customer.Type = N'医药公司'))
虽然说,我们使用这个语句的应用是一个BI应用,实时性要求不高,但是,我觉得没有道理会运行这么久,应该有办法优化。

第一步,我看了看索引,好像没有问题,都有
第二步,检查关系,有没有错,没有错,和应用要求是一致的,尤其计算出来的结果和同事使用另外一种方法的计算结果是一致的(同事使用多个视图分步累加)。
第三步,看看这个语句有没有什么特别之处?
      我注意到特别之处就是使用Pink底色标出的部分:
dbo.ComFlow.SalType IN (N'促销', N'流向退货', N'多级流向') AND dbo.ComFlow.CustCode = dbo.Customer.CustCode               
 Or ComFlow_1.SalType IN (N'自然流向', N'自然流向退货') AND ComFlow_1.OutCustCode = Customer_1.CustCode

这是一个Or关系的关联?就是这个问题?
分析这个语句可以看出,这个Or语句其实是可以分解成Union语句的,所以把它变成下面的:

SELECT     dbo.ComFlow.ComFlowCode, dbo.ComFlow.ComCode, dbo.ComFlow.CustCode, dbo.ComFlow.DepartCode, dbo.ComFlow.SaleCode,
                      dbo.ComFlow.EmpCode, dbo.ComFlow.Quantity * dbo.Commodity.ConvertRate AS Quantity, CONVERT(datetime, DATENAME(yyyy,
                      dbo.ComFlow.FlowDate) + '-' + DATENAME(mm, dbo.ComFlow.FlowDate) + '-' + DATENAME(dd, dbo.ComFlow.FlowDate)) AS FlowDate,
                      dbo.ComFlow.SalType, dbo.Employee.DepartCode AS DepartIn, dbo.Sale.DepartCode AS DepartOut,
                      dbo.ComFlow.Quantity * dbo.Commodity.TradePrice * dbo.Commodity.Discount / 100 AS Total, dbo.Department.GrpCode AS GrpCodeIn,
                      Department1.GrpCode AS GrpCodeOut
FROM         dbo.ComFlow INNER JOIN
                      dbo.Customer ON dbo.ComFlow.SalType IN (N'促销', N'流向退货', N'多级流向') AND dbo.ComFlow.CustCode = dbo.Customer.CustCode INNER JOIN
                      dbo.CustomerRelation ON dbo.ComFlow.ComCode = dbo.CustomerRelation.ComCode AND
                      dbo.CustomerRelation.CustCode = dbo.Customer.CustCode INNER JOIN
                      dbo.Employee ON dbo.CustomerRelation.EmpCode = dbo.Employee.EmpCode INNER JOIN
                      dbo.Sale ON dbo.ComFlow.SaleCode = dbo.Sale.SaleCode INNER JOIN
                      dbo.Department ON dbo.Department.DepartCode = dbo.Employee.DepartCode INNER JOIN
                      dbo.Department AS Department1 ON Department1.DepartCode = dbo.Sale.DepartCode AND
                      dbo.Department.GrpCode <> Department1.GrpCode INNER JOIN
                      dbo.Commodity ON dbo.ComFlow.ComCode = dbo.Commodity.ComCode
WHERE     (NOT (dbo.ComFlow.SalType = N'流向退货')) OR
                      (NOT (dbo.Customer.Type = N'医药公司'))
UNION ALL
SELECT     ComFlow_1.ComFlowCode, ComFlow_1.ComCode, ComFlow_1.CustCode, ComFlow_1.DepartCode, ComFlow_1.SaleCode, ComFlow_1.EmpCode,
                      ComFlow_1.Quantity * Commodity_1.ConvertRate AS Quantity, CONVERT(datetime, DATENAME(yyyy, ComFlow_1.FlowDate) + '-' + DATENAME(mm,
                      ComFlow_1.FlowDate) + '-' + DATENAME(dd, ComFlow_1.FlowDate)) AS FlowDate, ComFlow_1.SalType, Employee_1.DepartCode AS DepartIn,
                      Sale_1.DepartCode AS DepartOut, ComFlow_1.Quantity * Commodity_1.TradePrice * Commodity_1.Discount / 100 AS Total,
                      Department_1.GrpCode AS GrpCodeIn, Department1.GrpCode AS GrpCodeOut
FROM         dbo.ComFlow AS ComFlow_1 INNER JOIN
                      dbo.Customer AS Customer_1 ON ComFlow_1.SalType IN (N'自然流向', N'自然流向退货') AND
                      ComFlow_1.OutCustCode = Customer_1.CustCode INNER JOIN
                      dbo.CustomerRelation AS CustomerRelation_1 ON ComFlow_1.ComCode = CustomerRelation_1.ComCode AND
                      CustomerRelation_1.CustCode = Customer_1.CustCode INNER JOIN
                      dbo.Employee AS Employee_1 ON CustomerRelation_1.EmpCode = Employee_1.EmpCode INNER JOIN
                      dbo.Sale AS Sale_1 ON ComFlow_1.SaleCode = Sale_1.SaleCode INNER JOIN
                      dbo.Department AS Department_1 ON Department_1.DepartCode = Employee_1.DepartCode INNER JOIN
                      dbo.Department AS Department1 ON Department1.DepartCode = Sale_1.DepartCode AND Department_1.GrpCode <> Department1.GrpCode INNER JOIN
                      dbo.Commodity AS Commodity_1 ON ComFlow_1.ComCode = Commodity_1.ComCode
WHERE     (NOT (ComFlow_1.SalType = N'流向退货')) OR
                      (NOT (Customer_1.Type = N'医药公司'))
没有想到,效果太明显了,之前需要30分钟才能运行完毕的语句只要30几秒就完成了。

这里可以看出,Or的语句可能破坏了索引的作用。使用Or进行关联虽然逻辑非常清楚,但是效率低。
使用Union虽然冗长,但是用在这里效率要高。
http://www.cnblogs.com/cleo/archive/2006/11/01/547079.html

 

 

原创粉丝点击