2

嗨 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 driver 使用 SQL 查询来获得该解决方案。

我还要感谢Tim LehnerMark Rotteveel给我的快速答复。

4

3 回答 3

4

如果一个语句不能返回或返回多个结果,则不应使用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 中所述)

本质上,这意味着如果您想正确处理所有结果,您需要执行以下操作:

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()?

于 2013-02-04T19:37:11.233 回答
1

更新

我找到了解决方案!

在阅读了一篇关于 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();
    }
}

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

谢谢大家的帮助 !:)

于 2013-02-05T09:47:32.827 回答
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 bar)可能无法通过链接服务器按您的预期工作(它只会抓取最后一条记录)。只是一个小警告。

于 2013-02-04T16:19:19.277 回答