【问题标题】:T-SQL: cannot get the data of the row from the OLE DB provider "OraOLEDB.Oracle" for linked serverT-SQL:无法从链接服务器的 OLE DB 提供程序“OraOLEDB.Oracle”获取行的数据
【发布时间】:2018-04-06 18:40:31
【问题描述】:

错误是:

无法从链接服务器的 OLE DB 提供程序“OraOLEDB.Oracle”获取行的数据

我正在尝试将 Oracle SQL 查询转换为 T-SQL。运行此版本的查询时出现错误:

SELECT B.SAAS_ACTIVITY, A.LAST_NAME, A.FIRST_NAME, A.MIDDLE_NAME,  
        B.DIVISION_CODE, B.GRANT_YEAR, B.ACTIVITY_CODE, B.ACT_ACTIVITY_CODE,
        B.COST_CENTER, B.HOURS_BEG, B.LEAVE_ADJ_HOURS, B.CURRENT_MONTH,
        B.HOURS_BEG + B.LEAVE_ADJ_HOURS TOTAL_HOURS, B.PERCENT_WORK, 
        B.DIV_MONTHLY_SALARY, C.DIV_DESCRIPTION,
        B.DIV_SALARY_PLUS_FRINGE - B.DIV_MONTHLY_SALARY FRINGE, 
        B.DIV_SALARY_PLUS_FRINGE
  FROM ORCL_RIVENDELL..BP2K.EMT_EMPLOYEE A, 
ORCL_RIVENDELL..BP2K.LABOR_DISTRIB_MASTER_DETAIL B, 
    ORCL_RIVENDELL..BP2K.ACT_DIVISION C
  WHERE A.ID = B.ID
       AND B.FISCAL_YEAR = :P_SFY
       AND B.DIVISION_CODE = C.DIVISION_CODE
       AND C.DIV_SFY = :P_SFY
       AND B.CURRENT_MONTH >= CASE WHEN :P_FROM_MONTH is null THEN 2 
            ELSE :P_FROM_MONTH
            END
       AND B.CURRENT_MONTH <= CASE WHEN :P_TO_MONTH is null THEN 13 
           ELSE :P_TO_MONTH
           END
       AND B.SAAS_ACTIVITY >= CASE WHEN :P__FROM_OFFICE  is null THEN '4701' 
           ELSE :P_FROM_OFFICE
           END
       AND B.SAAS_ACTIVITY <= CASE WHEN :P__TO_OFFICE  is null THEN '4705' 
           ELSE :P_TO_OFFICE
           END
       AND B.DIVISION_CODE >= CASE WHEN :P__FROM_DIV  is null THEN '0011' 
           ELSE :P_FROM_DIV
           END
      AND B.DIVISION_CODE <= CASE WHEN :P__TO_DIV  is null THEN '9999' 
           ELSE :P_TO_DIV
           END
      AND B.DIVISION_CODE <> '1050'
ORDER BY B.DIVISION_CODE, A.LAST_NAME, B.CURRENT_MONTH

但如果删除连接以获取 DIV_DESCRIPTION,并且只使用 DIV_CODE,则查询运行正常:

SELECT B.SAAS_ACTIVITY, A.LAST_NAME, A.FIRST_NAME, A.MIDDLE_NAME,  
        B.DIVISION_CODE, B.GRANT_YEAR, B.ACTIVITY_CODE, B.ACT_ACTIVITY_CODE,
        B.COST_CENTER, B.HOURS_BEG, B.LEAVE_ADJ_HOURS, B.CURRENT_MONTH,
        B.HOURS_BEG + B.LEAVE_ADJ_HOURS TOTAL_HOURS, B.PERCENT_WORK, 
        B.DIV_MONTHLY_SALARY, B.DIVISION_CODE,
        B.DIV_SALARY_PLUS_FRINGE - B.DIV_MONTHLY_SALARY FRINGE, 
        B.DIV_SALARY_PLUS_FRINGE
  FROM ORCL_RIVENDELL..BP2K.EMT_EMPLOYEE A, 
     ORCL_RIVENDELL..BP2K.LABOR_DISTRIB_MASTER_DETAIL B
  WHERE A.ID = B.ID
       AND B.FISCAL_YEAR = :P_SFY
       AND B.CURRENT_MONTH >= CASE WHEN :P_FROM_MONTH is null THEN 2 
            ELSE :P_FROM_MONTH
            END
       AND B.CURRENT_MONTH <= CASE WHEN :P_TO_MONTH is null THEN 13 
           ELSE :P_TO_MONTH
           END
       AND B.SAAS_ACTIVITY >= CASE WHEN :P__FROM_OFFICE  is null THEN '4701' 
           ELSE :P_FROM_OFFICE
           END
       AND B.SAAS_ACTIVITY <= CASE WHEN :P__TO_OFFICE  is null THEN '4705' 
           ELSE :P_TO_OFFICE
           END
       AND B.DIVISION_CODE >= CASE WHEN :P__FROM_DIV  is null THEN '0011' 
           ELSE :P_FROM_DIV
           END
      AND B.DIVISION_CODE <= CASE WHEN :P__TO_DIV  is null THEN '9999' 
           ELSE :P_TO_DIV
           END
      AND B.DIVISION_CODE <> '1050'
ORDER BY B.DIVISION_CODE, A.LAST_NAME, B.CURRENT_MONTH

获取 DIV_DESCRIPTION 并不是绝对关键,但我想了解错误发生的原因(我使用 Oracle SQL 的次数远多于 TSQL)。该列在 ACT_DIVISION 表和 LABOR_DISTRIB_MASTER_DETAIL 表中都定义为 VARCHAR2(12)。这是数据类型不匹配的问题,还是其他原因?

谢谢, 哈利

【问题讨论】:

    标签: sql-server oracle tsql linked-server


    【解决方案1】:

    我建议让 Oracle 通过 OPENQUERY 传递查询来为您完成所有繁重的工作,这对您来说更容易(因为您知道 Oracle 语法)并且速度更快,因为 Oracle 将自己完成自己的工作具有自己的索引的表,并且只将结果集传回 SQL Server。

    请注意,由于查询包含在 ' ' 中,因此您必须将其中的单个 ' 加倍。

    在执行此操作时,OLEDB 驱动程序应该为您处理所有不稳定的数据类型映射。

    语法:

    SELECT *
    FROM OPENQUERY([ORCL_RIVENDELL],'SELECT B.SAAS_ACTIVITY, A.LAST_NAME, A.FIRST_NAME, A.MIDDLE_NAME,  
            B.DIVISION_CODE, B.GRANT_YEAR, B.ACTIVITY_CODE, B.ACT_ACTIVITY_CODE,
            B.COST_CENTER, B.HOURS_BEG, B.LEAVE_ADJ_HOURS, B.CURRENT_MONTH,
            B.HOURS_BEG + B.LEAVE_ADJ_HOURS TOTAL_HOURS, B.PERCENT_WORK, 
            B.DIV_MONTHLY_SALARY, C.DIV_DESCRIPTION,
            B.DIV_SALARY_PLUS_FRINGE - B.DIV_MONTHLY_SALARY FRINGE, 
            B.DIV_SALARY_PLUS_FRINGE
      FROM BP2K.EMT_EMPLOYEE A, 
           BP2K.LABOR_DISTRIB_MASTER_DETAIL B, 
           BP2K.ACT_DIVISION C
      WHERE A.ID = B.ID
           AND B.FISCAL_YEAR = :P_SFY
           AND B.DIVISION_CODE = C.DIVISION_CODE
           AND C.DIV_SFY = :P_SFY
           AND B.CURRENT_MONTH >= CASE WHEN :P_FROM_MONTH is null THEN 2 
                ELSE :P_FROM_MONTH
                END
           AND B.CURRENT_MONTH <= CASE WHEN :P_TO_MONTH is null THEN 13 
               ELSE :P_TO_MONTH
               END
           AND B.SAAS_ACTIVITY >= CASE WHEN :P__FROM_OFFICE  is null THEN ''4701'' 
               ELSE :P_FROM_OFFICE
               END
           AND B.SAAS_ACTIVITY <= CASE WHEN :P__TO_OFFICE  is null THEN ''4705'' 
               ELSE :P_TO_OFFICE
               END
           AND B.DIVISION_CODE >= CASE WHEN :P__FROM_DIV  is null THEN ''0011'' 
               ELSE :P_FROM_DIV
               END
          AND B.DIVISION_CODE <= CASE WHEN :P__TO_DIV  is null THEN ''9999'' 
               ELSE :P_TO_DIV
               END
          AND B.DIVISION_CODE <> ''1050''
    ORDER BY B.DIVISION_CODE, A.LAST_NAME, B.CURRENT_MONTH')
    

    如果需要传参数,语法如下:

    假设您需要传递一个名为 @myDate 的参数。

    DECLARE @myDate DATETIME=GETDATE()
    
    DECLARE @SQL NVARCHAR(MAX)
    
    SET @SQL = 'SELECT *
                FROM OPENQUERY([ORCL_RIVENDELL],''SELECT *
                                                    FROM  BP2K.SOME_TABLE
                                                    WHERE ACTIVITYDATE = '''''+CONVERT(VARCHAR,@myDate,120)+''''' '')'
    
    PRINT @SQL
    --EXEC SP_EXECUTESQL @SQL
    

    话虽如此,您在使用动态 SQL 时需要非常小心,如果您不控制这些参数的输入,这是很危险的。您以这种方式向 SQL 注入攻击敞开心扉。有更好/更安全的方法可以将参数传递给sp_executesql,但在使用OPENQUERY 时它不起作用。如果您可以更好地使用ISDATE()ISNUMERIC() 验证输入,如果它们没有通过验证,请不要执行。但你最安全的选择是永远不要让除你以外的任何人传入这些参数。

    【讨论】:

    • 我了解到您不能将参数传递给 OPENQUERY - 对吗?我不知道这是否是一项要求,但我想确定任何一种方式。
    • 你可以用动态查询...我会更新答案。
    • 谢谢!不过,我很好奇 - 我将 Oracle 表 ORCL_RIVENDELL..BP2K.ACT_DIVISION 复制到 SQL Server(2014)并重写查询以再次连接 B 和 C(将 Oracle 表连接到 SQL Server 表)并得到同样的错误再次。所以也许是我编写查询的方式导致了错误,而不是与数据相关的东西?
    • 我不确定我是否遵循。您将表复制到sql server?如果错误是由于数据类型映射引起的,则可以想象它仍然可能出错。我不太了解 oracle,所以我无法对所有语法发表评论,除了旧式连接和 :P_ 看起来一切正常。我的直觉告诉我驱动程序处理不好的数据类型。
    • 是的 - 一旦我通过加入 ORCL_RIVENDELL..BP2K.EMT_EMPLOYEE 和 ORCL_RIVENDELL..BP2K.LABOR_DISTRIB_MASTER_DETAIL 使查询正常工作,只需使用 DIVISION_CODE 而不是加入 ORCL_RIVENDELL..BP2K.ACT_DIVISION 即可DIV_DESCRIPTION,我将 ACT_DIVISION 表复制到 SQL Server(从 ORCL_RIVENDELL..BP2K.ACT_DIVISION 中选择 * 到 BP2K_ACT_DIVISION)并将 ORCL_RIVENDELL..BP2K.LABOR_DISTRIB_MASTER_DETAIL 表加入其中。在 Oracle 中,DIVISION_CODE 定义为 varchar2(12);在 SQL Server 中,DIVISION_CODE 定义为 varchar(12)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    • 2012-08-22
    • 2016-10-06
    • 1970-01-01
    • 2014-05-25
    • 2018-03-17
    相关资源
    最近更新 更多