在Java应用程序中执行“sp_msforeachdb”

时间:2013-02-04 15:49:53

标签: java sql-server stored-procedures jdbc sp-msforeachdb

您好StackOverflow社区:)

我来找你分享我的一个问题......

我必须提取SQL Server实例的每个数据库中每个表的列表,我找到了这个查询:

EXEC sp_msforeachdb 'Use ?; SELECT DB_NAME() AS DB, * FROM sys.tables'

它在Microsoft SQL Server Management Studio上完美运行但是当我尝试在我的Java程序中执行 (包括SQL Server的JDBC驱动程序)时,它表示没有返回任何结果

我的Java代码如下:

this.statement = this.connect.createStatement(); // Create the statement
this.resultats = this.statement.executeQuery("EXEC sp_msforeachdb 'Use ?; SELECT DB_NAME() AS DB, * FROM sys.tables'"); // Execute the query and store results in a ResultSet

this.sortie.ecrireResultats(this.statement.getResultSet()); // Write the ResultSet to a file

感谢任何想要帮助我的人, 祝您有个愉快的一天:)

编辑1:

我不确定SQL Server的JDBC驱动程序是否支持我的查询,所以我会尝试以另一种方式实现我的目标。

我想要获得的是SQL Server实例上每个数据库的所有表的列表,输出格式如下:

+-----------+--------+
| Databases | Tables |
+-----------+--------+

所以现在我问有人可以帮助我通过Java的JDBC for SQL Server驱动程序来使用SQL查询来解决这个问题。

我还要感谢我从Tim LehnerMark Rotteveel得到的快速答案。

3 个答案:

答案 0 :(得分:3)

如果语句可以返回no或多个结果,则不应使用executeQuery,而应使用execute(),此方法返回boolean表示类型第一个结果:

  • true:结果为ResultSet
  • false:结果是更新计数

如果结果为true,则您使用getResultSet()检索ResultSet,否则getUpdateCount()检索更新计数。如果更新计数为-1,则表示没有更多结果。请注意,当前结果为-1时,更新计数也为ResultSet。如果没有更多结果或者结果是更新计数,那么getResultSet()应该返回null也是一件好事。

现在,如果您想要检索更多结果,请致电getMoreResults()(或其兄弟接受int参数)。 boolean的返回值与execute()的返回值相同,因此false并不意味着没有更多结果!

如果getMoreResults()返回false并且getUpdateCount()返回-1(也在Javadoc中记录),则只会有更多结果

基本上这意味着如果您想要正确处理所有结果,您需要执行以下操作。请注意,我实际上没有尝试使用您的语句,也不确定SQL Server JDBC驱动程序是否正确实现了多个结果,因此它可能无法正常工作:

boolean result = stmt.execute(...);
while(true)
    if (result) {
        ResultSet rs = stmt.getResultSet();
        // Do something with resultset ...
    } else {
        int updateCount = stmt.getUpdateCount();
        if (updateCount == -1) {
            // no more results
            break;
        }
        // Do something with update count ...
    }
    result = stmt.getMoreResults();
}

注意:此答案的部分内容基于我对Java SQL: Statement.hasResultSet()?

的回答

答案 1 :(得分:1)

如果您没有收到错误,一个问题可能是sp_msforeachdb将为每个数据库返回一个单独的结果集,而不是一个包含所有记录的结果集。在这种情况下,您可以尝试使用一些动态SQL来合并所有行:

-- Use sys.tables
declare @sql nvarchar(max)
select @sql = coalesce(@sql + ' union all ', '') + 'select ''' + quotename(name) + ''' as database_name, * from ' + quotename(name) + '.sys.tables'
from sys.databases
select @sql = @sql + ' order by database_name, name'
exec sp_executesql @sql

我有时也会使用INFORMATION_SCHEMA视图,因为它更容易看到模式名称,其中包括:

-- Use INFORMATION_SCHEMA.TABLES to easily get schema name
declare @sql nvarchar(max)
select @sql = coalesce(@sql + ' union all ', '') + 'select * from ' + quotename(name) + '.INFORMATION_SCHEMA.TABLES where TABLE_TYPE = ''BASE TABLE'''
from sys.databases
select @sql = @sql + ' order by TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME'
exec sp_executesql @sql

请注意这种字符串连接方法(select @sql = foo from barmay not work as you intend through a linked server(它只会获取最后一条记录)。只是一个小小的警告。

答案 2 :(得分:1)

<强>更新

我找到了解决方案!

在阅读an article about sp_spaceused being used with Java之后,我发现我处于相同的情况。

我的最终代码如下:

this.instances = instances;
for(int i = 0 ; i < this.instances.size() ; i++)
{
    try
    {
        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        this.connect = DriverManager.getConnection("jdbc:sqlserver://" + this.instances.get(i), "tluser", "result");

        this.statement = this.connect.prepareCall("{call sp_msforeachdb(?)}");
        this.statement.setString(1, "Use ?; SELECT DB_NAME() AS DB, name FROM sys.tables WHERE DB_NAME() NOT IN('master', 'model', 'msdb', 'tempdb')");
        this.resultats = this.statement.execute();

        while(true)
        {
            int rowCount = this.statement.getUpdateCount();
            if(rowCount > 0)
            {
                this.statement.getMoreResults();
                continue;
            }
            if(rowCount == 0)
            {
                this.statement.getMoreResults();
                continue;
            }

            ResultSet rs = this.statement.getResultSet();
            if(rs != null)
            {
                while (rs.next())
                {
                     this.sortie.ecrireResultats(rs); // Write the results to a file
                }
                rs.close();
                this.statement.getMoreResults();
                continue;
            }
            break;
        }
        this.statement.close();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

它试了一下,我的文件里面有我想要的一切。

谢谢大家的帮助! :)