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

2019-07-19 05:42发布

喜的StackOverflow社区:)

我来给大家分享一下我的问题之一......

我要提取的SQL Server实例的每个数据库中每个表的名单 ,我发现这个查询:

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

它完美的微软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:

我不知道那的JDBC驱动程序SQL Server支持我的查询,所以我会尽量让我以另一种方式的目标。

我想要得到的是对一个SQL Server实例的每个数据库中的所有表的列表 ,输出格式为以下几点:

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

所以,现在我问有人可以帮我去使用直通Java的JDBC SQL查询的SQL Server驱动程序的解决方案。

我还要感谢非常快速解答我从拿到添莱纳和马克Rotteveel 。

Answer 1:

如果一个语句可以返回没有或多个结果,你不应该使用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()?



Answer 2:

如果你没有得到一个错误,一个问题可能是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 bar ) 如你打算通过链接服务器可能无法正常工作 (它将只抢到最后一个记录)。 只是一个小的警告。



Answer 3:

UPDATE

我已经找到了解决方案!

看完后约注释sp_spaceused正在与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();
    }
}

它尝试过了,我的文件中有我想要的一切在里面。

感谢大家的帮助 ! :)



文章来源: Execute “sp_msforeachdb” in a Java application