VBA+ADODB+Oracle中的参数化查询
我对使用Oracle11g还不熟悉,要使参数化查询顺利工作,我遇到了很多问题 此代码适用于:VBA+ADODB+Oracle中的参数化查询,vba,oracle11g,adodb,Vba,Oracle11g,Adodb,我对使用Oracle11g还不熟悉,要使参数化查询顺利工作,我遇到了很多问题 此代码适用于: Dim rs As ADODB.Recordset Dim con As ADODB.Connection Dim cmd As ADODB.Command Dim prm As ADODB.Parameter Set con = New ADODB.Connection With con .ConnectionString = GetC
Dim rs As ADODB.Recordset
Dim con As ADODB.Connection
Dim cmd As ADODB.Command
Dim prm As ADODB.Parameter
Set con = New ADODB.Connection
With con
.ConnectionString = GetConnection() '<-- the driver here is Driver={Oracle in OraClient11g_home1_32bit}
.Open
End With
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = con
.CommandType = adCmdText
.CommandText = "SELECT * FROM MPA_LINEPLAN.REF_BRAND_SEASON_DROP WHERE DROP_ID = ?"
Set prm = .CreateParameter("dropID", adVarChar, adParamInput, 50, "P_SP19_5")
.Parameters.Append prm
Set rs = .Execute
End With
但是当我尝试执行到rs时,它遇到了未指定的错误
另外,对于我的特殊情况,假设存储过程不是最佳选项,即使它应该是最佳选项:-/
编辑:
实际的查询非常长,为了不让您查找所有的:dropID引用,我在这里减少了它,但留下了足够的空间来显示多个引用
WITH
--...
DropDim AS (
SELECT DROP_ID
, DROP_NAME
, SEASON_ID
, SEASON_NAME
, BRAND_ID
, SEASON_YEAR
, 'DROP_' || substr(DROP_ID, LENGTH(DROP_ID),1) AS LP_Join_Drop
, SEASON_NAME || '_' || SEASON_YEAR AS LP_Join_Season
FROM MPA_LINEPLAN.REF_BRAND_SEASON_DROP
WHERE DROP_ID = :dropID),
--...
LYMap AS
(SELECT DC.DROP_ID
, DC.CHANNEL_ID
, BSD.SEASON_YEAR
, BSD.SEASON_NAME
, BSD.DROP_NAME
, FW.WEEKENDINGDATE AS LY_WEEKENDING_DATE
, FW.YEARWEEK AS LY_YEARWEEK
FROM MPA_LINEPLAN.REF_DROP_CHANNEL DC
INNER JOIN MPA_MASTER.FISCALWEEK FW
ON FW.YEARWEEK BETWEEN DC.LY_START_DT AND DC.LY_END_DT
INNER JOIN MPA_LINEPLAN.REF_BRAND_SEASON_DROP BSD ON BSD.DROP_ID = dc.DROP_ID
WHERE DC.DROP_ID = :dropID),
LLYMap AS
(SELECT DC.DROP_ID
, DC.CHANNEL_ID
, BSD.SEASON_YEAR
, BSD.SEASON_NAME
, BSD.DROP_NAME
, FW.WEEKENDINGDATE AS LLY_WEEKENDING_DATE
, FW.YEARWEEK AS LLY_YEARWEEK
FROM MPA_LINEPLAN.REF_DROP_CHANNEL DC
INNER JOIN MPA_MASTER.FISCALWEEK FW
ON FW.YEARWEEK BETWEEN DC.LLY_START_DT AND DC.LLY_END_DT
INNER JOIN MPA_LINEPLAN.REF_BRAND_SEASON_DROP BSD ON BSD.DROP_ID = dc.DROP_ID
WHERE DC.DROP_ID = :dropID ),
--....
继续使用qmarks占位符,只需使用for循环来附加相同的参数对象。具体来说,qmark对应于查询中放置的位置。假设下面的查询
sql = "SELECT * FROM MPA_LINEPLAN.REF_BRAND_SEASON_DROP" _
& " WHERE DROP_ID = ? AND DROP_ID2 = ? AND DROP_ID3 = ?"
With cmd
Set .ActiveConnection = con
.CommandType = adCmdText
.CommandText = sql
For i = 1 To 3 ' ADJUST TO NUMBER OF PARAMS
Set prm = .CreateParameter("prm" & i, adVarChar, adParamInput, 50, "P_SP19_5")
.Parameters.Append prm
Next i
Set rs = .Execute
End With
或者,将查询转换为在VBA中读取的非常大的SQL字符串或文本文件,然后定义一个参数
神谕
创建或替换过程VARCHAR2中的my_PROCEDURE_namedropID为
开始
…使用dropID进行长查询,不带任何符号。。。
终止
/
VBA
使用cmd
Set.ActiveConnection=con
.propertieslsqlrset=TRUE
.CommandType=adCmdText
.CommandText={调用我的\u过程\u名称}
设置prm=.createParameterTM,adVarChar,adParamInput,50,P_SP19_5
.Parameters.Append prm
设置rs=.Execute
以
最好的解决办法就是停止使用Oracle的ODBC驱动程序,转而使用Oracle的OLEDB作为提供程序 旧连接字符串: .ConnectionString=Driver={OraClient11g_home1_32bit}中的Oracle;UID=MyUname;PWD=MyPW;DBQ=MyDB 新连接字符串: .ConnectionString=Provider=OraOLEDB.Oracle;数据源=MyDB;用户ID=MyUname;密码=MyPW OraOLEDB支持命名参数,这正是我一开始想要得到的。现在,我可以使用:prefix引用SQL语句中的参数名称
现在可以了 另一种方法是使用CTE获取所有标量参数,然后连接回您感兴趣的表: -由于VBA中ODBC驱动程序的限制,外部选择* 挑选* 从…起 以卢为首 选择作为投递id 来自双重 选择t1* 来自mpa_lineplan.ref_brand_season_drop t1 交叉连接lu-可以是内部连接,也可以是您感兴趣的任何类型 其中t1.drop\u id=lu.drop\u id
声明一个变量?设置@foo=?然后在脚本中使用@foo?IDK关于Oracle,但这可能是我在SQL Server上所做的。@MathieuGuindon我也会这么想,但我尝试的Oracle等价物似乎都不起作用。我得到了各种各样的变量绑定错误。令人惊讶的是,我在网上找不到任何有效的例子:-我不理解这个问题。其中,我们反复使用相同的参数。为什么qmarks不起作用?在两个准备好的语句中,只使用一个参数。你是说一个包含多个qmark的SQL语句吗?@Parfait为了简单起见,我只放了一个简单的SQL语句。实际语句引用dropID或qmark变量10次以上。关键是,我不想添加相同的参数10次以上,以使qmark版本工作。在同一个SQL查询中多次?请使用不止一个dropID引用来显示实际值。这是可行的,但如果/当您开始需要另一个参数时,会很快变得混乱。我想我从未使用过它们,但ADODB不支持命名参数吗?@MathieuGuindon,不幸的是不支持。但是我添加了一个OP可以考虑的存储过程版本哈!删除我的草稿然后-将与推荐一个存储过程一起。。。用VBA或任何语言编写SQL时,哪一种应该是首选的方法?真的吗?谢谢你的建议。我公司的DBA使开发存储过程变得很困难,我必须经历一个官僚过程才能完成简单的DDL,即使对于开发人员也是如此。事实上,我找到了另一个更好的解决方案。我将发布它,以防其他人偶然发现同样的问题,但我只是想感谢你花时间回答我的问题!使用cmd.NamedParameters=True重新尝试不带循环但带有:dropID的ODBC版本。有趣!但再一次,您的示例只使用了一个参数。这是否适用于包含多个:dropID的较大查询?请在回答中提及。是的,这适用于对同一参数变量的多个引用。我将用一个更好的例子来更新我的答案。你的例子实际上与大约10年前OraOleDB只支持位置绑定而不支持命名参数的说法背道而驰。不过,这可能是OLEDB提供程序的版本问题。@Parfait好吧,您是对的,先生。我跳枪了——oraOLEDB即使在这种情况下也在使用位置绑定。头撞在桌子上
sql = "SELECT * FROM MPA_LINEPLAN.REF_BRAND_SEASON_DROP" _
& " WHERE DROP_ID = ? AND DROP_ID2 = ? AND DROP_ID3 = ?"
With cmd
Set .ActiveConnection = con
.CommandType = adCmdText
.CommandText = sql
For i = 1 To 3 ' ADJUST TO NUMBER OF PARAMS
Set prm = .CreateParameter("prm" & i, adVarChar, adParamInput, 50, "P_SP19_5")
.Parameters.Append prm
Next i
Set rs = .Execute
End With
With cmd
Set .ActiveConnection = con
.CommandType = adCmdText
.CommandText = "SELECT * FROM MPA_LINEPLAN.REF_BRAND_SEASON_DROP WHERE DROP_ID =:dropID"
Set prm = .CreateParameter("dropID", adVarChar, adParamInput, 50, "P_SP19_5")
.Parameters.Append prm
Set rs = .Execute
End With