Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Как да върнете *всичко* от съхранена процедура с помощта на JDBC

Когато изпълним съхранена процедура в JDBC, ние връщаме поредица от нула или повече "резултати". След това можем да обработим тези „резултати“ последователно, като извикаме CallableStatement#getMoreResults() . Всеки "резултат" може да съдържа

  • нула или повече редове данни, които можем да извлечем с ResultSet обект,
  • брой за актуализация за DML израз (INSERT, UPDATE, DELETE), който можем да извлечем с CallableStatement#getUpdateCount() , или
  • Грешка, която хвърля SQLServerException.

За „Проблем 1“ проблемът често е, че съхранената процедура не започва с SET NOCOUNT ON; и изпълнява DML оператор, преди да направи SELECT, за да произведе набор от резултати. Броят на актуализациите за DML се връща като първия "резултат", а редовете с данни са "заседнали зад него", докато не извикаме getMoreResults .

"Проблем 2" по същество е същият проблем. Съхранената процедура произвежда "резултат" (обикновено SELECT или евентуално брой на актуализацията), преди да възникне грешката. Грешката се връща в следващ "резултат" и не причинява изключение, докато не го "извлечем" с помощта на getMoreResults .

В много случаи проблемът може да бъде избегнат чрез просто добавяне на SET NOCOUNT ON; като първия изпълним оператор в съхранената процедура. Промяната на съхранената процедура обаче не винаги е възможна и остава фактът, че за да получите всичко обратно от съхранената процедура трябва да продължим да извикваме getMoreResults докато, както казва Javadoc:

There are no more results when the following is true: 

     // stmt is a Statement object
     ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))

Това звучи достатъчно просто, но както обикновено, „дяволът е в детайлите“, както е илюстрирано от следния пример. За съхранена процедура на SQL Server ...

ALTER PROCEDURE dbo.TroublesomeSP AS
BEGIN
    -- note: no `SET NOCOUNT ON;`
    DECLARE @tbl TABLE (id VARCHAR(3) PRIMARY KEY);

    DROP TABLE NonExistent;
    INSERT INTO @tbl (id) VALUES ('001');
    SELECT id FROM @tbl;
    INSERT INTO @tbl (id) VALUES ('001');  -- duplicate key error
    SELECT 1/0;  -- error _inside_ ResultSet
    INSERT INTO @tbl (id) VALUES ('101');
    INSERT INTO @tbl (id) VALUES ('201'),('202');
    SELECT id FROM @tbl;
END

... следният Java код ще върне всичко ...

try (CallableStatement cs = conn.prepareCall("{call dbo.TroublesomeSP}")) {
    boolean resultSetAvailable = false;
    int numberOfResultsProcessed = 0;
    try {
        resultSetAvailable = cs.execute();
    } catch (SQLServerException sse) {
        System.out.printf("Exception thrown on execute: %s%n%n", sse.getMessage());
        numberOfResultsProcessed++;
    }
    int updateCount = -2;  // initialize to impossible(?) value
    while (true) {
        boolean exceptionOccurred = true; 
        do {
            try {
                if (numberOfResultsProcessed > 0) {
                    resultSetAvailable = cs.getMoreResults();
                }
                exceptionOccurred = false;
                updateCount = cs.getUpdateCount();
            } catch (SQLServerException sse) {
                System.out.printf("Current result is an exception: %s%n%n", sse.getMessage());
            }
            numberOfResultsProcessed++;
        } while (exceptionOccurred);

        if ((!resultSetAvailable) && (updateCount == -1)) {
            break;  // we're done
        }

        if (resultSetAvailable) {
            System.out.println("Current result is a ResultSet:");
            try (ResultSet rs = cs.getResultSet()) {
                try {
                    while (rs.next()) {
                        System.out.println(rs.getString(1));
                    }
                } catch (SQLServerException sse) {
                    System.out.printf("Exception while processing ResultSet: %s%n", sse.getMessage());
                }
            }
        } else {
            System.out.printf("Current result is an update count: %d %s affected%n",
                    updateCount,
                    updateCount == 1 ? "row was" : "rows were");
        }
        System.out.println();
    }
    System.out.println("[end of results]");
}

... произвежда следния конзолен изход:

Exception thrown on execute: Cannot drop the table 'NonExistent', because it does not exist or you do not have permission.

Current result is an update count: 1 row was affected

Current result is a ResultSet:
001

Current result is an exception: Violation of PRIMARY KEY constraint 'PK__#314D4EA__3213E83F3335971A'. Cannot insert duplicate key in object '[email protected]'. The duplicate key value is (001).

Current result is a ResultSet:
Exception while processing ResultSet: Divide by zero error encountered.

Current result is an update count: 1 row was affected

Current result is an update count: 2 rows were affected

Current result is a ResultSet:
001
101
201
202

[end of results]



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да инсталирате sqlcmd &bcp на Ubuntu

  2. Нови промени в колони само за метаданни в SQL Server 2016

  3. Как да премахнете заглавките на колоните при изпращане по имейл на резултатите от заявката в SQL Server (T-SQL)

  4. Извикване на съхранена процедура с върната стойност

  5. Брой пъти, когато даден знак се появява в низ