1

我们需要创建几个 SQL 报表,每个报表都依赖于上一个报表的结果。所有查询都采用以下形式:Select 1, Report 1, Select 2 from Select 1, Report 2, Select 3 from Select 2, Report 3, ...依此类推到... Report N。

现在“N”个单独的 SQL 查询用于生成完整的报告集。每个查询都包含所有先前查询的 SQL 代码 - 这导致报告 1 被执行“N”次,报告 2 被执行“N - 1”次等。导致在多个报告中重复相同的选择语句导致性能问题。

我们如何导出中间报告,最好是 .csv 文件,因为它们是由报告“N”生成的,从而消除了对所有其他报告的需要?


一些特定于我们案例的复杂因素:

  • 必须使用交钥匙方法,使任何使用任何形式的人工干预的方法都不可接受。需要纯文本输出。
  • OBDC(特别是 Python 的 pyobdc 包)用于将 SQL 查询传递给 SQL Server(作为游标)。Python 使用结果将报告创建为 .csv 文件。
  • 存储 SQL 过程被禁止,但现有 SQL 代码确实使用临时表。
  • 结果必须写入我的(客户端)机器。我们的 IM 部门可能允许我们使用他们服务器上的临时文件夹。
  • 似乎 pyobdc 只能接受一个结果集(因此需要“N”个查询)。确保正确的结果集被传回要求 SQL 查询以“SET NOCOUNT ON”开头(如 pyobdc 邮件列表所建议的那样)。我知道没有其他方法可以从 SQL 返回的多个结果集中返回/选择正确的结果集。我尝试了一种 pyobdc 方法(cursor.nextset)来跳过结果集,但没有返回任何内容。
  • 我考虑将报告“n - 1”的结果传递给报告“N”——但所涉及的数据量可能使这不切实际。
  • Python (3.2.2) 和 SQL 代码是经过充分验证的生产代码。更改语言不是一个实际的选择。更改 OBDC 包是可能的,但不太可能(必须提出一个非常有力的案例,并且其他 OBDC 包必须易于跨平台移植,并且还能够连接到 Microsoft SQL Server 2008 Management Studio)。
  • 带有 pydev 插件的 Eclipse (Helios) 用于启动 Python 应用程序,该应用程序启动 SQL 查询。
  • 客户端O/S是XP Pro Sp 3,服务器相信是一样的。该公司正计划“很快”将我们的机器迁移到 Windows 7/8,因此该操作系统的可移植性是一个因素。
4

1 回答 1

2

以下是我自己的问题的完整解决方案(最好将其命名为“需要从 SQL 查询脚本导出多个结果”)。

另请参阅使用相同通用方法的这个问题,除了它使用硬编码的 SQL 字符串 - 和 fetchall() 而不是 fetchone() - 也是那个问题


仔细查看多行(继承的)SQL 代码,发现中间报告没有被保存。只有最后一个 SQL 选择/报告的结果被返回(给 python)。

解决方案的 SQL 方面包括创建新表来保存结果集(报告),然后在 SQL 代码的最后返回所有结果集。
SQL 代码现在如下所示:

SET NOCOUNT ON    -- required by pyobdc (and other OBDC packages?) at start of code
SET @year  = ?    -- get OBDC (python) parameter 1
SET @month = ?    -- get parameter 2
SET @day   = ?    -- get parameter 3

DECLARE @ReportX TABLE  -- a new table, one of these for each report

--  Repeated for each report (1 to N):

INSERT INTO @ReportX    -- NEW LINE, it preserves the report
SELECT .....        -- the original report, uses the passed-in parameters

-- At the very bottom of the SQL code, add one of these lines for each report:

Select * from @ReportX   -- where X is 1 to N 

解决方案的 Python 3.x 端如下所示:

import pyodbc  # contains cursor.execute, the interface to SQL
import csv     # creates csv.writer, used to create the CSV file

    Textfile     = open( "FileContainingSqlCode", 'r' )  
    SQL_COMMANDS = Textfile.read();     #  Get SQL code for all reports

    cursor.execute( SQL_COMMANDS, Year, Month, Day )  # do all reports using 3 parameters 

    # Create first report from the first result set

    ReportID = 1

    filename = "D:\\Report" + str( ReportID ) + ".csv"
    OutFile  = open( filename, 'w', newline= '' ) 

    Results = csv.writer( OutFile, delimiter = ',', quotechar = '"', 
                          quoting = csv.QUOTE_MINIMAL )
    while True:            
        row = cursor.fetchone()
        if not row:
            break
        Results.writerow( row )
    OutFile.close()
    
    # Create the 2nd through Nth reports
   
    while ( cursor.nextset() ) :
        ReportID += 1
        
        filename = "D:\\Report" + str( ReportID ) + ".csv"
        OutFile =  open( filename, 'w', newline= '' ) 
    
        Results = csv.writer( OutFile, delimiter = ',', quotechar = '"', 
                          quoting   = csv.QUOTE_MINIMAL )
        while True:            
            row = cursor.fetchone()
            if not row:
                break
            Results.writerow( row )            
        OutFile.close() 
      
# end of Python 3.x code

消除第一个报告部分应该可以通过在第二个 while 循环中使用以下内容来实现:while ( ?? in cursor.nextset() )。

于 2012-06-27T15:21:32.790 回答