简体   繁体   中英

PL/SQL Iterate through Select result - connect results to returnable type

I have this LOOP inside a Procedure:

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

My goal is to add each found User(id and uName) from the Select-Statement to a returnable "List" of these Users within the Loop. Once the Loop is finished i want to return the Result, so i can use it in Java (via CallableStatement). I know there are no Lists in SQL, and I guess a Cursor should be able to do exactly that, but i just cant figure out how I should go on.

If its hard to understand what im trying to say maybe this snippet within my LOOP can explain better:

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

You can do this two ways.

Cursor

This method returns a cursor from PL/SQL which we convert (cast) into a ResultSet and then iterate like normal. You will notice I use OracleTypes.CURSOR which makes this specific to the Oracle JDBC driver.

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;
/

Java

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);
        }
    }
}

Prints:

.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

Collection

This method uses custom DB types. It has the limitation of needing a type that matches each possible record structure, but for basic lists of strings or numbers you can make them generic. This is documented pretty heavily here . You will notice that this example does not require the use of 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;
/

Java

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);
        }
    }
}

Prints:

.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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM