PLSQL 数组中的不同值

Distinct Values in Array in PLSQL

我想将 table 中列中的不同值存储到数组中。我收到以下错误。我怎样才能做到这一点?

select count(distinct(Name)) into n from table;      

create or replace type array_type is varray(100) of varchar2(20); 

for i in 1 .. n loop
    name_array.extend;
    select distinct(Name) into name_array(i) from table order by name asc;
end loop;   

Error :
 ORA-01422: exact fetch returns more than requested number of rows

Table :

您可以SELECT DISTINCT value BULK COLLECT INTO获取不同的值并将它们存储到一个集合中。

尝试:

CREATE TABLE test_table (
  name VARCHAR2(20),
  city VARCHAR2(250)
);

INSERT INTO test_table (name, city) VALUES ('A', 'X');
INSERT INTO test_table (name, city) VALUES ('B', 'Y');
INSERT INTO test_table (name, city) VALUES ('A', 'Z');
INSERT INTO test_table (name, city) VALUES ('C', 'K');
INSERT INTO test_table (name, city) VALUES ('D', 'P');
INSERT INTO test_table (name, city) VALUES ('A', 'Q');
INSERT INTO test_table (name, city) VALUES ('D', 'R');
INSERT INTO test_table (name, city) VALUES ('C', 'S');

COMMIT;

CREATE OR REPLACE TYPE array_type IS VARRAY(100) OF VARCHAR2(20);

DECLARE
  v_name_array array_type := array_type();
BEGIN
  SELECT DISTINCT NAME
    BULK COLLECT
    INTO v_name_array
    FROM test_table
   ORDER BY NAME ASC;
  -- Show resulting values in collection
  FOR i IN 1 .. v_name_array.count
  LOOP
    dbms_output.put_line(v_name_array(i));
  END LOOP;
END;
/

在你们讨论解决方案之前,我想在这里提几点

第 1 点:- 希望您理解错误 ORA-01422。

当您在其中使用 select 时,它总是期望获取一行,而您的示例显然不是这种情况

原因:exact fetch指定的数量小于返回的行数。

操作:重写查询或更改请求的行数

要点 2 :- 游标的用法

您一次使用同一个游标进行计数,第二次使用相同的游标进行抓取。为什么不能一次声明它而只使用它一次来循环和获取或使用 for 循环代替

例如 - for i in (select distinct(Name) from table order by name) loop

要点 3 :- 类型的用法

我建议在本地创建类型而不是在数据库中创建为对象,除非您想在许多地方重用它。忘记提请注意用于存储值的索引。我不质疑你为什么使用 "of varchar(20)" 但你可以考虑一下。

第 4 点:- 标准化

作为一个建议,考虑规范化数据库。如果您查看示例数据,您将意识到我们需要避免的冗余数据。

第 5 点:- 批量收集的用法

正如其中一个答案中提到的,最好将批量收集与集合一起使用,但是是的,如果您要处理的数据集不是很大,您可能不会进行批量收集,而只需使用简单的循环来放置数据放入其中。

最后,如果尝试使代码在您的情况下正确(假设我们在数据库中创建的类型),我将执行如下操作。

DECLARE
   n NUMBER;
   --local variable is also fine here for type in case you changed your mind not to create in db
   --type array_type is varray(100) of varchar2(20);
   name_array array_type := array_type();
   idx NUMBER := 1;
BEGIN
   -- default order is ASC , so we can omit the same in real query
   FOR i IN (SELECT DISTINCT(NAME) NAME FROM teststack ORDER BY NAME)
   LOOP
      name_array.extend;
      name_array(idx) := i.name;
      idx := idx + 1;
   END LOOP;
   FOR i IN 1..name_array.count LOOP
     dbms_output.put_line(name_array(i));
   END LOOP;
END;
/