首页 > 解决方案 > PL/SQL 遍历选择结果 - 将结果连接到可返回类型

问题描述

我在一个过程中有这个循环:

FOR foundU IN (SELECT id, uName FROM USERS)
LOOP
-- do something--
END LOOP;

我的目标是将 Select-Statement 中找到的每个用户(id 和 uName)添加到循环中这些用户的可返回“列表”中。循环完成后,我想返回结果,因此我可以在 Java 中使用它(通过 CallableStatement)。我知道 SQL 中没有列表,我猜 Cursor 应该能够做到这一点,但我只是不知道我应该如何继续。

如果很难理解我想说什么,也许我的循环中的这个片段可以更好地解释:

FOR foundU IN (SELECT id, uName FROM USERS)
    LOOP
    -- ListofFoundUsers.add(foundU.id, foundU.uName);
    END LOOP;
 -- return ListofFoundUsers;

标签: sqlloopsplsqlcursororacle-sqldeveloper

解决方案


你可以通过两种方式做到这一点。

光标

此方法从 PL/SQL 返回一个游标,我们将其转换(转换)为 ResultSet,然后像往常一样迭代。您会注意到我使用了 OracleTypes.CURSOR,这使得它特定于 Oracle JDBC 驱动程序。

PL/SQL

CREATE OR REPLACE PROCEDURE ret_sys_refcursor(o_cursor OUT SYS_REFCURSOR) IS
BEGIN
  OPEN o_cursor FOR
    SELECT o.object_name
      FROM all_objects o
     WHERE o.owner = 'SYS'
       AND rownum < 10;
END ret_sys_refcursor;
/

爪哇

import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import oracle.jdbc.OracleTypes;

public class so64913833 {
    public static void main(String[] args)
            throws ClassNotFoundException, SQLException, IOException {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        List<String> objects = new ArrayList<String>();

        try (Connection connection = DriverManager.getConnection(
                "jdbc:oracle:thin:@//<db.host.name:port/sid>", "<user>",
                "<password>")) {

            try (CallableStatement cs = connection
                    .prepareCall("{  call ret_sys_refcursor(?) }")) {

                cs.registerOutParameter(1, OracleTypes.CURSOR);
                cs.execute();

                try (ResultSet rs = (ResultSet) cs.getObject(1)) {
                    while (rs.next()) {
                        objects.add(rs.getString("OBJECT_NAME"));
                    }
                }
            }
        }

        for (String object : objects) {
            System.out.println(object);
        }
    }
}

印刷:

.xdk_version_10.2.0.3.0_production
.xdk_version_10.2.0.5.0_production
.xdk_version_11.2.0.3.0_production
.xdk_version_12.2.0.1.0_production
ACCESS$
ACLMV$
ACLMV$_BASE_VIEW
ACLMV$_MVINFO
ACLMV$_REFLOG

收藏

此方法使用自定义 DB 类型。它的局限性在于需要一种与每个可能的记录结构相匹配的类型,但对于字符串或数字的基本列表,您可以将它们设为通用。这在此处有大量记录。您会注意到此示例不需要使用 OracleTypes。

PL/SQL

CREATE OR REPLACE TYPE t_string_tab AS TABLE OF VARCHAR2(4000);

CREATE OR REPLACE PROCEDURE ret_string_tab(o_string_tab OUT t_string_tab) IS
BEGIN
  SELECT o.object_name
    BULK COLLECT
    INTO o_string_tab
    FROM all_objects o
   WHERE o.owner = 'SYS'
     AND rownum < 10;
END ret_string_tab;
/

爪哇

import java.io.IOException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;
import java.util.List;

public class so64913833 {
    public static void main(String[] args)
            throws ClassNotFoundException, SQLException, IOException {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        List<String> objects = null;

        try (Connection connection = DriverManager.getConnection(
                "jdbc:oracle:thin:@//<db.host.name:port/sid>", "<user>",
                "<password>")) {

            try (CallableStatement cs = connection
                    .prepareCall("{  call ret_string_tab(?) }")) {

                cs.registerOutParameter(1, Types.ARRAY, "T_STRING_TAB");
                cs.execute();
                objects = Arrays.asList((String[]) cs.getArray(1).getArray());
            }
        }

        for (String object : objects) {
            System.out.println(object);
        }
    }
}

印刷:

.xdk_version_10.2.0.3.0_production
.xdk_version_10.2.0.5.0_production
.xdk_version_11.2.0.3.0_production
.xdk_version_12.2.0.1.0_production
ACCESS$
ACLMV$
ACLMV$_BASE_VIEW
ACLMV$_MVINFO
ACLMV$_REFLOG

推荐阅读