【问题标题】:Unable to return stored procedure results to Excel无法将存储过程结果返回到 Excel
【发布时间】:2016-06-27 15:05:12
【问题描述】:

我在 SQL Server 中有一个从 Excel 调用的存储过程,每次都传递一些动态参数。

我知道存储过程与 SQL Server 中的参数一起使用(已经对此进行了广泛测试),但是当我通过 Excel 调用该过程时,我没有返回任何结果。

我的连接在 Data==>Connections 中设置并且正在工作 - 它会直接拉回列名。它从一个命令按钮运行,vba 如下:

Private Sub CommandButton1_Click()
Dim HOT As String, RM As String, Season As String, SSD As Date, SED As Date

HOT = Sheets("Sheet1").Range("C2").Value
RM = Sheets("Sheet1").Range("C3").Value
Season = Sheets("Sheet1").Range("C4").Value

If Season = "S16" Then
    SSD = "01/05/2016"
    SED = "31/10/2016"
ElseIf Season = "W16" Then
    SSD = "01/11/2016"
    SED = "30/04/2016"
ElseIf Season = "S17" Then
    SSD = "01/05/2017"
    SED = "31/10/2017"
Else
End If

With ActiveWorkbook.Connections("TRRC").OLEDBConnection
    .CommandText = "EXEC RatesCalculation '" & Season & "','" & HOT & "','" & RM & "'"
    ActiveWorkbook.Connections("TRRC").Refresh
End With
End Sub

季节信息不相关,因为在 IF 语句中的所有内容中,我的存储过程中有一个语句来定义带有季节的日期。

我在存储过程中也有SET NOCOUNT ON

下面是我的存储过程:

    @Season Char(3), @RM Char(6), @HOT Char(6)

AS

BEGIN


    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    DECLARE @SSD as Datetime
    DECLARE @SED as Datetime

    IF @Season = 'S16'
        SET @SSD = '01/05/2016'
    IF @Season = 'S16'
        SET @SED = '31/10/2016'
    IF @Season = 'W16'
        SET @SSD = '01/11/2016'
    IF @Season = 'W16'
        SET @SED = '30/04/2017'

--gathering room data (rates, dates) (#tblroomrates)
SELECT DISTINCT holhot.hot, prxcontract.ssnver, prxcontract.conid, atchotroom.atcCode, prxconrate.room, prxconrate.dateid, prxcondate.dateStart, prxcondate.dateEnd, prxconrate.type, prxconrate.rate1, prxconrate.rate2
INTO            #tblroomrates
FROM            atchotroom INNER JOIN
                         prxconroom ON atchotroom.room = prxconroom.atchotroom INNER JOIN
                         prxconrate INNER JOIN
                         prxcondate ON prxconrate.ssnver = prxcondate.ssnver AND prxconrate.conId = prxcondate.conId 
                         AND prxconrate.dateId = prxcondate.dateId ON 
                         prxconroom.ssnver = prxconrate.ssnver AND prxconroom.conId = prxconrate.conId 
                         AND prxconroom.room = prxconrate.room INNER JOIN
                         holhot INNER JOIN
                         name ON holhot.hot = name.tosCode INNER JOIN
                         prxcon ON name.code = prxcon.hot INNER JOIN
                         prxcontract ON prxcon.ssnver = prxcontract.ssnver 
                         AND prxcon.conId = prxcontract.conId ON prxconroom.ssnver = prxcontract.ssnver AND 
                         prxconroom.conId = prxcontract.conId AND atchotroom.code = prxcon.hot
WHERE        (holhot.holcode = @HOT) AND (prxcon.ssnver = '') AND 
                         (prxcontract.constart<=@SED) AND (prxcontract.conend>=@SSD)
                         order by datestart asc;

--updating any blank dates to season dates to represent an all season rate(only applies to type 3 and 4)
UPDATE #tblroomrates
SET #tblroomrates.datestart = prxcontract.constart,
    #tblroomrates.dateend = prxcontract.conend
FROM
    #tblroomrates INNER JOIN prxcontract ON #tblroomrates.ssnver = prxcontract.ssnver AND #tblroomrates.conid = prxcontract.conid
WHERE
    #tblroomrates.datestart is null AND #tblroomrates.dateend is null

--selects all type 3 and 4 rates for all season dates (#tblrates_alldates)
SELECT DISTINCT #tblroomrates.ssnver, #tblroomrates.conid, atcCode, room, dateid, dateStart, dateEnd, [type], rate1, rate2
INTO #tblrates_alldates
FROM #tblroomrates INNER JOIN prxcontract ON #tblroomrates.ssnver = prxcontract.ssnver AND #tblroomrates.conid = prxcontract.conid
WHERE #tblroomrates.dateStart = prxcontract.constart AND #tblroomrates.dateEnd = prxcontract.conend
AND #tblroomrates.[type] IN ('3','4')

--rate update
UPDATE #tblroomrates
SET 
    #tblroomrates.rate1 = #tblrates_alldates.rate1,
    #tblroomrates.rate2 = #tblrates_alldates.rate2
FROM
    #tblroomrates INNER JOIN #tblrates_alldates ON #tblroomrates.ssnver = #tblrates_alldates.ssnver AND #tblroomrates.conid = #tblrates_alldates.conid AND #tblroomrates.room = #tblrates_alldates.room
    INNER JOIN prxcontract ON #tblroomrates.ssnver = prxcontract.ssnver AND #tblroomrates.conid = prxcontract.conid
WHERE
    #tblroomrates.dateStart = prxcontract.constart AND #tblroomrates.dateEnd = prxcontract.conend AND #tblroomrates.dateid >'0'

--gathers rates where type is 1 (#tblrates_baserates)
SELECT DISTINCT * 
INTO #tblrates_baserates
FROM #tblroomrates
WHERE [type] = '1'

--update rate 2
UPDATE #tblroomrates
SET 
    #tblroomrates.rate1 = #tblrates_baserates.rate1
FROM 
    #tblroomrates INNER JOIN #tblrates_baserates ON #tblroomrates.ssnver = #tblrates_baserates.ssnver AND #tblroomrates.conid = #tblrates_baserates.conid 
    AND #tblroomrates.dateid = #tblrates_baserates.dateid
WHERE
    #tblroomrates.[type] = '2'

--Calculate the final rate here
SELECT #tblroomrates.hot AS [Accom Code], #tblroomrates.atcCode AS [Room], #tblroomrates.dateStart AS [Rate Start], #tblroomrates.dateEnd AS [Rate End], 
        CASE 
            WHEN #tblroomrates.rate2 <> 0 AND #tblroomrates.[type] = 3 THEN #tblrates_baserates.rate1 + #tblroomrates.rate2
            WHEN #tblroomrates.rate2 <> 0 AND #tblroomrates.[type] = 4 THEN #tblrates_baserates.rate1 - #tblroomrates.rate2 
            WHEN #tblroomrates.rate2 <> 0 AND #tblroomrates.[type] IN (0,1,2) THEN #tblroomrates.rate1
            ELSE 
                CASE
                    WHEN #tblroomrates.rate1 <> 0 AND #tblroomrates.[type] = 3 THEN #tblrates_baserates.rate1 + (#tblrates_baserates.rate1 * (#tblroomrates.rate1/100))
                    WHEN #tblroomrates.rate1 <> 0 AND #tblroomrates.[type] = 4 THEN #tblrates_baserates.rate1 - (#tblrates_baserates.rate1 * (#tblroomrates.rate1/100))
                    ELSE 
                        CASE
                            WHEN #tblroomrates.rate2 = 0 AND #tblroomrates.rate1 = 0 THEN #tblrates_baserates.rate1
                            ELSE #tblroomrates.rate1
                        END
                END
        END AS Calculated_Rates
FROM #tblroomrates LEFT JOIN #tblrates_baserates ON #tblroomrates.ssnver = #tblrates_baserates.ssnver AND 
    #tblroomrates.conid = #tblrates_baserates.conid AND #tblroomrates.dateid = #tblrates_baserates.dateid
WHERE #tblroomrates.dateid > 0
AND #TBLROOMRATES.ATCCODE = @RM

相当大的块,但需要收集最终计算所需的所有数据

【问题讨论】:

  • 您应该在.CommandText 中设置SET NOCOUNT ON;,如下所示:.CommandText = "set nocount on; EXEC RatesCalculation '" &amp; Season &amp; "','" &amp; HOT &amp; "','" &amp; RM &amp; "'"
  • @Ralph,没有区别,仍然没有返回任何结果
  • 您是否验证了结果 Debug.Print "EXEC RatesCalculation '" &amp; Season &amp; "','" &amp; HOT &amp; "','" &amp; RM &amp; "'" 以查看 T-SQL 命令是否正确并尝试在 SSMS 中运行此结果行?如果这仍然验证,则检查 SSMS 中使用的凭据与 Excel 相比。如果您仍然没有发现问题,那么您还需要将 T-SQL 代码添加到上面的帖子中。
  • 查看您的 SP 似乎它通常会返回多个结果。然而,Excel 无法检索多个结果集。 Set nocount on; 确保 Excel 只接受最后一次返回。在您的情况下,这将是--Calculate the final rate here。因此,如果 select 为空,则 Excel 将不会显示任何内容。您可能希望(在第一步中)从一个简单的 SP 开始,以验证 Excel 中的各种结果。
  • @Ralph, 'debug.print' 向我展示了要传递给存储过程的预期值

标签: sql-server excel stored-procedures vba


【解决方案1】:

确保与 Excel 工作表进行身份验证的用户具有数据库上的 EXECUTE 权限。 SELECT 是不够的。您无需担心执行 SP 内部发生的任何操作的权限,因为 SP 的操作权限与对象所有者相同(与视图等不同)。

【讨论】:

  • 存储过程以管理员权限执行,与我每天在服务器上使用的权限相同
  • 您是否在连接属性中选中了“在全部刷新时刷新此连接”?
【解决方案2】:

根据上面的建议,我将存储过程拆分为 2 个单独的过程 - 第一个用于收集所有相关数据,第二个用于进行最终计算。我认为正如 Ralph 所建议的那样,Excel 不知道要拉回和显示哪个结果集。所以问题解决了。然而,结果显示错误的数字,但这对我来说是一个数学问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-08
    • 2014-02-06
    • 1970-01-01
    • 2021-03-22
    • 2015-06-03
    • 2013-06-21
    相关资源
    最近更新 更多