呓语的博客

不管前面的路有多艰辛多长,只要怀着一颗执着的心。成功就离你不远了!
posts - 43, comments - 2, trackbacks - 0, articles - 1

标量全查询

标量全查询是在括号中的全查询,该查询返回的一行只包含一个列值。标量全查询对从数据库中检索数据值供表达式使用是很有用的。

  • 下列示例列出其薪水超过全部雇员平均薪水的雇员的姓名:
     
         SELECT LASTNAME, FIRSTNME
            FROM EMPLOYEE
            WHERE  SALARY > (SELECT AVG(SALARY)
                               FROM EMPLOYEE)
    

  • 下列示例在两个不同的表中查寻雇员的平均薪水:
     
         SELECT AVG(SALARY) AS "Average_Employee",
                (SELECT AVG(SALARY) AS "Average_Staff" FROM STAFF)
                    FROM EMPLOYEE
    

转换数据类型

有时可能需要将一些值从一种数据类型转换成另一种数据类型,例如,从数字值转换成字符串。要将一个值转换成另一个不同的类型,使用 CAST 说明。

转换说明的另一个可能用途是截断很长的字符串。在 EMP_RESUME 表中,RESUME 列是 CLOB(5K)。您可能只想显示包含应聘者个人信息的前 370 个字符。要从 EMP_RESUME 表中显示简历的 ASCII 格式的前 370 个字符,发出下列请求:

 
     SELECT EMPNO, CAST(RESUME AS VARCHAR(370))
        FROM EMP_RESUME
        WHERE RESUME_FORMAT = 'ascii'

会发出一个警告,通知您超过 370 个字符的值被截断。

可将空值转换为更便于在查询中进行处理的其他数据类型。 公共表表达式是一个为此目的使用转换的示例。

条件表达式

可在 SQL 语句中使用 CASE 表达式以便于处理表的数据表示。这提供了一种功能强大的条件表达式能力,在概念上与某些程序设计语言中的 CASE 语句类似。

  • 要从 ORG 表中的 DEPTNAME 列将部门编号更改为有意义的词,输入下列查询:

         SELECT DEPTNAME,
            CASE DEPTNUMB
              WHEN 10 THEN 'Marketing'
              WHEN 15 THEN 'Research'
              WHEN 20 THEN 'Development'
              WHEN 38 THEN 'Accounting'
              ELSE 'Sales'
            END  AS FUNCTION
            FROM ORG
    

    结果为:

         DEPTNAME       FUNCTION
         -------------- -----------
         Head Office    Marketing
         New England    Research
         Mid Atlantic   Development
         South Atlantic Accounting
         Great Lakes    Sales
         Plains         Sales
         Pacific        Sales
         Mountain       Sales
    

  • 可使用 CASE 表达式来防止出现异常情况,如被零除等。在下列示例中,如果雇员没有奖金或佣金报酬,则语句条件通过避免除法运算来防止出错:

     
         SELECT LASTNAME, WORKDEPT FROM EMPLOYEE
            WHERE(CASE
                     WHEN BONUS+COMM=0 THEN NULL
                     ELSE SALARY/(BONUS+COMM)
                  END ) > 10
    

  • 可在单个语句中使用 CASE 表达式,根据一个列中值的子集的总和与该列中所有值的总和的比来产生一个比率。使用 CASE 表达式的语句只需要传送数据一次。在没有 CASE 表达式的情况下,执行同样的计算至少需要传送两次。

    下列示例使用 CASE 表达式计算部门 20 的薪水之和与全部薪水总额的比率:

         SELECT CAST(CAST (SUM(CASE
                                  WHEN DEPT = 20 THEN SALARY
                                  ELSE 0
                               END) AS DECIMAL(7,2))/
                           SUM(SALARY) AS DECIMAL (3,2))
            FROM STAFF
    

    结果为 0.11。注意:CAST 函数确保结果的精度得到保持。

  • 可使用 CASE 表达式来计算简单的函数,而不必调用函数本身,调用函数将需要额外开销。例如:

         CASE
            WHEN X<0 THEN -1
            WHEN X=0 THEN 0
            WHEN X>0 THEN 1
         END
    

    此表达式与 SYSFUN 模式中 SIGN 用户定义函数有相同的结果。

表表达式

如果只需要单个查询的视图定义,可使用表表达式

表表达式是临时的,只在 SQL 语句的使用期限内有效;表表达式不能共享,但它们比视图更灵活。任何授权的用户都可共享视图定义。

本节描述如何在查询中使用公共表表达式和嵌套表表达式。

嵌套表表达式

嵌套表表达式是一个临时视图,其中的定义被嵌套(直接定义)在主查询的 FROM子 句中。

下列查询使用嵌套表表达式来寻找那些教育级别超过 16 的雇员的平均总收入、教育级别以及雇用年份:

 
     SELECT EDLEVEL, HIREYEAR, DECIMAL(AVG(TOTAL_PAY), 7,2)
        FROM (SELECT YEAR(HIREDATE) AS HIREYEAR, EDLEVEL,
                     SALARY+BONUS+COMM AS TOTAL_PAY
                 FROM EMPLOYEE
                 WHERE EDLEVEL > 16 )  AS PAY_LEVEL
        GROUP BY EDLEVEL, HIREYEAR
        ORDER BY EDLEVEL, HIREYEAR
 

结果如下:

     EDLEVEL HIREYEAR    3
     ------- ----------- ---------
          17        1967  28850.00
          17        1973  23547.00
          17        1977  24430.00
          17        1979  25896.50
          18        1965  57970.00
          18        1968  32827.00
          18        1973  45350.00
          18        1976  31294.00
          19        1958  51120.00
          20        1975  42110.00

此查询使用嵌套表表达式,首先从 HIREDATE 列中抽取雇用年份,以便可以在后续的 GROUP BY 子句中使用该雇用年份。您可能不想将此查询作为视图来创建,因为您打算用不同的 EDLEVEL 值来执行相似查询。

此示例中使用了标量内部函数 DECIMAL。 DECIMAL 返回数字或字符串的十进制表示。有关函数的更多详情,参考 SQL Reference

公共表表达式

公共表表达式是在全查询的开头使用 WITH 关键字定义的命名结果表。公共表表达式是您创建以在复杂查询之中使用的表表达式。在查询的开头使用 WITH 子句定义并命名公共表表达式。对公共表表达式的重复引用使用同一个结果集。相比之下,如果使用嵌套表表达式或视图,则每次都将重新生成结果集,其结果可能各不相同。

下列示例列出公司中教育级别大于 16、平均工资比那些同时雇用的且有同样教育级别的人低的所有人。在该查询后面会更详细地描述查询的各个部分。

(1)

     WITH
           PAYLEVEL AS
              (SELECT EMPNO, YEAR(HIREDATE) AS HIREYEAR, EDLEVEL,
                      SALARY+BONUS+COMM AS TOTAL_PAY
                  FROM EMPLOYEE
                  WHERE EDLEVEL > 16),
(2)
           PAYBYED (EDUC_LEVEL, YEAR_OF_HIRE, AVG_TOTAL_PAY) AS
              (SELECT EDLEVEL, HIREYEAR, AVG(TOTAL_PAY)
                  FROM PAYLEVEL
                  GROUP BY EDLEVEL, HIREYEAR)

(3)

     SELECT EMPNO, EDLEVEL, YEAR_OF_HIRE, TOTAL_PAY, DECIMAL(AVG_TOTAL_PAY,7,2)
        FROM PAYLEVEL, PAYBYED
        WHERE EDLEVEL=EDUC_LEVEL
          AND HIREYEAR = YEAR_OF_HIRE
          AND TOTAL_PAY < AVG_TOTAL_PAY                        

(1)
这是名为 PAYLEVEL 的公共表表达式。此结果表包括雇用某个人的年份、该雇员的总收入以及他(或她)的教育级别。只包括雇员的教育级别大于 16 的那些行。

(2)
这是名为 PAYBYED(或 PAY by education)的公共表表达式。该表达式使用在前一个公共表表达式中创建的 PAYLEVEL 表来确定每个教育级别同一年雇用的雇员的教育级别、雇用年份以及平均收入。此表返回的列被赋予的名称与选择列表中所使用的列名不同(如 EDUC_LEVEL)。这会生成命名为 PAYBYED 的结果集,与嵌套表表达式示例中产生的结果相同。

(3)
最后,我们获得能产生期望结果的实际查询。连接这两个表(PAYLEVEL,PAYBYED)以确定总收入比同年雇用的人的平均收入低的那些人。注意:PAYBYED 是以 PAYLEVEL 为基础。所以在完整语句中有效地存取了 PAYLEVEL 两次。两次都使用同一组行来计算查询。

最终结果如下:

     EMPNO  EDLEVEL YEAR_OF_HIRE TOTAL_PAY     5
     ------ ------- ------------ ------------- ---------
     000210      17         1979      20132.00  25896.50

相关名

相关名是用于识别一个对象的多种用途的标识符。可在查询的 FROM 子句中和 UPDATE 或 DELETE 语句的第一个子句中定义相关名。相关名可与表、视图或嵌套表表达式关联,但只限于定义相关名的上下文中。

例如,子句 FROM STAFF S、ORG O 分别指定 S 和 O 作为 STAFF 和 ORG 的相关名。

      SELECT NAME, DEPTNAME
         FROM STAFF S, ORG O
         WHERE O.MANAGER = S.ID

一旦定义了相关名,则只可以使用相关名来限定对象。例如,上例中如果写成 ORG.MANAGER=STAFF.ID 的话,则该语句就会失效。

也可以使用相关名作为表示数据库对象的简称。只输入 S 比输入 STAFF 更容易。

通过使用相关名,可复制对象。这在需要将表中各项与自己本身作比较时很有用。在下列示例中,EMPLOYEE 表与它自己的另一个实例比较以寻找所有雇员的经理。该示例显示非设计员的雇员的姓名、这些雇员的经理的姓名以及部门编号。

     SELECT E2.FIRSTNME, E2.LASTNAME,
            E2.JOB, E1.FIRSTNME, E1.LASTNAME, E1.WORKDEPT
        FROM EMPLOYEE E1, EMPLOYEE E2
        WHERE E1.WORKDEPT = E2.WORKDEPT
          AND E1.JOB = 'MANAGER'
          AND E2.JOB <> 'MANAGER'
          AND E2.JOB <> 'DESIGNER'
 

此语句产生下列结果:

     FIRSTNME     LASTNAME        JOB      FIRSTNME     LASTNAME        WORKDEPT
     ------------ --------------- -------- ------------ --------------- --------
     DOLORES      QUINTANA        ANALYST  SALLY        KWAN            C01
     HEATHER      NICHOLLS        ANALYST  SALLY        KWAN            C01
     JAMES        JEFFERSON       CLERK    EVA          PULASKI         D21
     MARIA        PEREZ           CLERK    EVA          PULASKI         D21
     SYBIL        JOHNSON         CLERK    EVA          PULASKI         D21
     DANIEL       SMITH           CLERK    EVA          PULASKI         D21
     SALVATORE    MARINO          CLERK    EVA          PULASKI         D21
     ETHEL        SCHNEIDER       OPERATOR EILEEN       HENDERSON       E11
     MAUDE        SETRIGHT        OPERATOR EILEEN       HENDERSON       E11
     PHILIP       SMITH           OPERATOR EILEEN       HENDERSON       E11
     JOHN         PARKER          OPERATOR EILEEN       HENDERSON       E11
     RAMLAL       MEHTA           FIELDREP THEODORE     SPENSER         E21
     JASON        GOUNOT          FIELDREP THEODORE     SPENSER         E21
     WING         LEE             FIELDREP THEODORE     SPENSER         E21

相关子查询

允许引用先前提到的任何表的子查询称为相关子查询。我们也说该子查询具有对主查询中表的相关引用

下列示例是一个不相关子查询,该子查询列出部门 'A00' 中薪水超过该部门平均薪水的雇员的雇员编号和姓名:

 
     SELECT EMPNO, LASTNAME
        FROM EMPLOYEE
        WHERE WORKDEPT = 'A00'
          AND SALARY > (SELECT AVG(SALARY)
                           FROM EMPLOYEE
                           WHERE WORKDEPT = 'A00')

如果想要知道每个部门的平均薪水,则需要对每个部门计算一次子查询。对在外层查询中标识的表的每一行,各使用一次 SQL 的相关功能(该能力允许您编写重复执行的子查询),就可做到这一点。此类型的相关子查询用来计算外层表的每一行的某个特性,该特性是在子查询中计算谓词所需要的。

此示例显示薪水高于部门平均薪水的所有雇员:

 
     SELECT E1.EMPNO, E1.LASTNAME, E1.WORKDEPT
        FROM EMPLOYEE E1
        WHERE SALARY > (SELECT AVG(SALARY)
                           FROM EMPLOYEE E2
                           WHERE E2.WORKDEPT = E1.WORKDEPT)
        ORDER BY E1.WORKDEPT

在此查询中,对每个部门计算一次子查询。结果为:

     EMPNO  LASTNAME        WORKDEPT
     ------ --------------- --------
     000010 HAAS            A00
     000110 LUCCHESSI       A00
     000030 KWAN            C01
     000060 STERN           D11
     000220 LUTZ            D11
     000200 BROWN           D11
     000170 YOSHIMURA       D11
     000150 ADAMSON         D11
     000070 PULASKI         D21
     000270 PEREZ           D21
     000240 MARINO          D21
     000090 HENDERSON       E11
     000280 SCHNEIDER       E11
     000100 SPENSER         E21
     000340 GOUNOT          E21
     000330 LEE             E21

要编写带有相关子查询的查询,使用与带有子查询的普通外部查询相同的基本格式。然而,在外部查询的 FROM 子句中,只是在表名后面放置一个相关名。于是子查询可能包含由该相关名限定的列引用。例如,如果 E1 是相关名,则 E1.WORKDEPT 表示外部查询中表的当前行的工作部门值。在外部查询中对表的每一行(概念上)重新计算子查询。

通过使用相关子查询,可以使系统为您工作并减少需要在应用程序中编写的代码量。

DB2 中允许非限定相关引用。例如,表 EMPLOYEE 有一个命名为 LASTNAME 的列,表 SALES 有一个命名为 SALES_PERSON 的列,但没有命名为 LASTNAME 的列。

 
     SELECT LASTNAME, FIRSTNME, COMM
        FROM EMPLOYEE
        WHERE 3 > (SELECT AVG(SALES)
                      FROM SALES
                      WHERE LASTNAME = SALES_PERSON)

在此示例中,系统检查最内层的 FROM 子句,以获取 LASTNAME 列。如果未找到 LASTNAME 列,则系统检查次最内层的 FROM 子句(此情况下为外部 FROM 子句)。虽然不总是必要的,还是建议限定相关引用以改进查询的可读性并确保获取想要的结果。

实现相关子查询

想何时使用相关子查询?列函数的使用有时是一条线索。

假定您想要列出教育级别高于部门平均值的雇员。

首先,您必须确定选择列表项。问题为 "List the employees"。这隐含着来自 EMPLOYEE 表中的 EMPNO 应该足以唯一标识雇员。该问题也将 EDLEVEL 和雇员的部门 WORKDEPT 说明为条件。当问题未明确要求显示列时,在选择列表中包括这些列将会有助于说明解法。现在可构造查询的一部分:

     SELECT LASTNAME, WORKDEPT, EDLEVEL
        FROM EMPLOYEE

接着需要搜索条件(WHERE子句)。问题语句为 "...whose level of education is higher than the average for that employee's department"。这意味着对于表中每个雇员,必须计算该雇员所在部门的平均教育级别。此语句适合相关子查询的说明。正在对每行计算某个特性(当前雇员所在部门的平均教育级别)。 EMPLOYEE 表需要相关名:

     SELECT LASTNAME, WORKDEPT, EDLEVEL
        FROM EMPLOYEE E1

需要的子查询较简单。该子查询计算每个部门的平均教育级别。完整的 SQL 语句为:

     SELECT LASTNAME, WORKDEPT, EDLEVEL
        FROM EMPLOYEE E1
        WHERE EDLEVEL > (SELECT AVG(EDLEVEL)
                            FROM EMPLOYEE  E2
                            WHERE E2.WORKDEPT = E1.WORKDEPT)

结果为:

     LASTNAME        WORKDEPT EDLEVEL
     --------------- -------- -------
     HAAS            A00           18
     KWAN            C01           20
     PULASKI         D21           16
     HENDERSON       E11           16
     LUCCHESSI       A00           19
     PIANKA          D11           17
     SCOUTTEN        D11           17
     JONES           D11           17
     LUTZ            D11           18
     MARINO          D21           17
     JOHNSON         D21           16
     SCHNEIDER       E11           17
     MEHTA           E21           16
     GOUNOT          E21           16

假定不列出雇员的部门编号,则应列出部门名称。需要的信息(DEPTNAME)在独立表(DEPARTMENT)中。定义相关变量的外层查询也可以是连接查询(参见从多个表中选择数据以了解详情)。

当在外层查询中使用连接时,列出要在 FROM 子句中连接的表,并将相关名放在这些表名的任何一个表名旁边。

要修改查询以列出部门名称而不是部门编号,在选择列表中用 DEPTNAME 替换 WORKDEPT。 FROM 子句现在也必须包括 DEPARTMENT 表,并且 WHERE 子句必须表示适当的连接条件。

以下是修改的查询:

     SELECT LASTNAME, DEPTNAME, EDLEVEL
        FROM EMPLOYEE E1, DEPARTMENT
        WHERE E1.WORKDEPT = DEPARTMENT.DEPTNO
        AND EDLEVEL > (SELECT AVG(EDLEVEL)
                          FROM EMPLOYEE E2
                          WHERE E2.WORKDEPT = E1.WORKDEPT)

上例显示,必须在包含相关子查询的某个查询的 FROM 子句中定义用于子查询中的相关名。然而,这种包含可能涉及若干层嵌套。

假定某些部门只有几个雇员,因此这些部门的平均教育级别可能是错误的。可以决定,为了使平均教育级别在用于比较雇员时是有意义的数字,一个部门中必须至少有 5 个雇员。因此现在必须列出教育级别高于雇员所在部门平均值的雇员,并只考虑至少有 5 个雇员的部门。

该问题暗含另一个子查询,因为对于外层查询中每个雇员来说,必须计算该雇员所在部门的雇员总数:

     SELECT COUNT(*)
        FROM EMPLOYEE E3
        WHERE E3.WORKDEPT = E1.WORKDEPT

仅当计数大于或等于 5 时才计算平均值:

     SELECT AVG(EDLEVEL)
        FROM EMPLOYEE E2
        WHERE E2.WORKDEPT = E1.WORKDEPT
        AND 5 <= (SELECT COUNT(*)
                     FROM EMPLOYEE  E3
                     WHERE E3.WORKDEPT = E1.WORKDEPT)

最后,只包括其教育级别高于部门平均值的那些雇员:

     SELECT LASTNAME, DEPTNAME, EDLEVEL
        FROM EMPLOYEE E1, DEPARTMENT
        WHERE E1.WORKDEPT = DEPARTMENT.DEPTNO
        AND EDLEVEL >
        (SELECT AVG(EDLEVEL)
            FROM EMPLOYEE E2
            WHERE E2.WORKDEPT = E1.WORKDEPT
            AND 5 <=
            (SELECT COUNT(*)
                FROM EMPLOYEE E3
                WHERE E3.WORKDEPT = E1.WORKDEPT))

此语句产生下列结果:

     LASTNAME        DEPTNAME                      EDLEVEL
     --------------- ----------------------------- -------
     PIANKA          MANUFACTURING SYSTEMS              17
     LUTZ            MANUFACTURING SYSTEMS              18
     JONES           MANUFACTURING SYSTEMS              17
     SCOUTTEN        MANUFACTURING SYSTEMS              17
     PULASKI         ADMINISTRATION SYSTEMS             16
     JOHNSON         ADMINISTRATION SYSTEMS             16
     MARINO          ADMINISTRATION SYSTEMS             17
     HENDERSON       OPERATIONS                         16
     SCHNEIDER       OPERATIONS                         17

posted @ 2006-01-10 20:26 呓语的博客 阅读(316) | 评论 (0)编辑 收藏

仅列出标题
共43页: First 上一页 8 9 10 11 12 13 14 15 16 下一页 Last