【问题标题】:Execute "sp_msforeachdb" in a Java application在 Java 应用程序中执行“sp_msforeachdb”
【发布时间】:2013-01-19 08:41:52
【问题描述】:

你好 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 的快速答复。

【问题讨论】:

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


    【解决方案1】:

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

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

    如果结果为true,则使用getResultSet() 检索ResultSet,否则使用getUpdateCount() 检索更新计数。如果更新计数为-1,则表示没有更多结果。请注意,当当前结果为ResultSet 时,更新计数也将为-1。如果没有更多结果或结果是更新计数,知道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()?的回答

    【讨论】:

    • 你的帖子很完整,教会了我很多关于一些方法的知识,但还没有掌握。问题是我实现了您的解决方案,但我无法让它与我的查询一起工作......我认为驱动程序不支持它。
    • @VincentKelleher 很不幸,我看看能不能找到替代解决方案。
    • 非常感谢!我花了几天时间到处搜索,似乎没有人尝试过......
    【解决方案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) may not work as you intend through a linked server(它只会抓取最后一条记录)。只是一个小警告。

    【讨论】:

    • 哇,答案很快!我可以将它包含在我的 Java 程序中吗?
    • 我对 JDBC 不太熟悉,所以我只是猜测您可以将整个内容放在您的 executeQuery() 命令中。如果这不起作用,您可以尝试基本的exec sp_who 或其他东西,以确保您可以通过这种方式从 proc 中获得结果集。使用与您的应用相同的用户/密码登录 SSMS 也不会受到伤害。
    • 我明天会尝试,并会随时通知您我的进展情况。无论如何,谢谢你的帮助!
    【解决方案3】:

    更新

    我找到了解决办法!

    读完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();
        }
    }
    

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

    感谢大家的帮助! :)

    【讨论】:

      猜你喜欢
      • 2011-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 2023-03-25
      • 2012-04-11
      • 1970-01-01
      相关资源
      最近更新 更多