从记录数组中选择记录字段的值-如何在Oracle DB中?

xmq68pz9  于 2023-05-16  发布在  Oracle
关注(0)|答案(2)|浏览(118)

假设我们有以下类型和变量定义:

type r_student_type is record(
    id    number,
    name  varchar2(32),
    class varchar2(32));

  type t_students_type is table of r_student_type;

  t_students t_students_type := t_students_type();

稍后,数组t_students被写入数据,让我们假设它看起来像这样:

+------+--------+-------+
| id   | name   | class |
+------+--------+-------+
| 4551 | Walter | A     |
+------+--------+-------+
| 4552 | Marie  | B     |
+------+--------+-------+
| 4553 | Hank   | B     |
+------+--------+-------+
| 4554 | Skyler | A     |
+------+--------+-------+

我正在寻找的是一种方法来查询数组t_students中所有记录的特定字段值。例如,我们想知道是否所有学生都在同一个class中。
我尝试过类似的东西:

select count(distinct class)
  into l_class_cnt
  from (select class
          from table(t_students));

但我得到了错误:PLS-00642: local collection types not allowed in SQL statements
我知道我可以使用for-loop访问t_students中的所有记录,并执行任何我想要的检查,但我想在单个SELECT语句中进行比较(不确定在Oracle中是否可能)。

xdnvmnnf

xdnvmnnf1#

您需要在包规范中声明类型以使用SQL中的变量:

create or replace package pkg as 
  type r_student_type is record(
    id    number,
    name  varchar2(32),
    class varchar2(32));

  type t_students_type is table of r_student_type;

  t_students t_students_type := t_students_type();
  l_class_cnt integer;
end;
/

declare
  t_students pkg.t_students_type := pkg.t_students_type();
  l_class_cnt integer;
begin
  select count(distinct class)
  into l_class_cnt
  from (select class
          from table(t_students));
          
  dbms_output.put_line ( 'Found ' || l_class_cnt );
end;
/
Found 0
nwsw7zdq

nwsw7zdq2#

RECORD是一种PL/SQL数据类型,不能在SQL作用域中使用,只能在PL/SQL作用域中使用,如果它是本地定义的类型,则不能传递到表集合表达式中。
您可以将类型更改为OBJECT,并在SQL范围(而不是PL/SQL范围)中定义它。

CREATE TYPE r_student_type IS OBJECT(
    id    number,
    name  varchar2(32),
    class varchar2(32)
);

CREATE TYPE t_students_type IS TABLE OF r_student_type;

然后:

SELECT COUNT(distinct class)
FROM   TABLE(
         t_students_type(
           r_student_type(1, 'Alice', 'Advanced'),
           r_student_type(2, 'Betty', 'Beginner'),
           r_student_type(3, 'Carol', 'Compiler Engineering')
         )
       );

以及:

DECLARE
  l_class_cnt PLS_INTEGER;
  t_students t_students_type := t_students_type(
    r_student_type(1, 'Alice', 'Advanced'),
    r_student_type(2, 'Betty', 'Beginner'),
    r_student_type(3, 'Carol', 'Compiler Engineering')
  );
BEGIN
  SELECT count(distinct class)
  INTO   l_class_cnt
  FROM   table(t_students);

  DBMS_OUTPUT.PUT_LINE(l_class_cnt);
END;
/

两个都行。
或者,您可以在包中全局定义记录及其集合类型(按照Chris Saxon's answer),而不是作为本地定义的类型,然后您只能在PL/SQL范围内使用记录和集合(而不是在SQL范围内)。
fiddle

相关问题