VBA/ADODB Run-Time Error: 3704 - oracle

The following VBA subroutine will run most queries just fine. (ie: SELECT * FROM DUAL)
Sub DisplayQuery(QueryString As String)
Dim rs As New ADODB.Recordset
Dim connStr As String
connStr = _
"Provider=MSDAORA.1;" _
& "User ID=abc;Password=123;" _
& "Data Source=xxx/xxx;"
out QueryString
rs.Open QueryString, connStr, adOpenStatic, adLockOptimistic
Range("DataTable").Clear
Cells(1, 1).CopyFromRecordset rs
End Sub
However, when I run the query below, the following error message immediately pops up: Run-time error '3704':Operation is not allowed when the object is closed.
with all_hours as
( select to_date('2009-11-03 05:00 PM','yyyy-mm-dd hh:mi PM') + numtodsinterval(level-1,'hour') hour
from dual
connect by level <= 4 /*hours*/
)
select h.hour
, count(case when h.hour = trunc(s.sampled_on,'hh24') then 1 end) sampled
, count(case when h.hour = trunc(s.received_on,'hh24') then 1 end) received
, count(case when h.hour = trunc(s.completed_on,'hh24') then 1 end) completed
, count(case when h.hour = trunc(s.authorized_on,'hh24') then 1 end) authorized
from all_hours h cross join sample s
group by h.hour
Why?

If I recall correctly, the ADO Command object has a default timeout (30 seconds, I think) which may be causing your problem: there should be a setting like
cn.ConnectionTimeout = (your value here)
which you could extend.

I just restructured my query (link), so that I could put it into a view. I then created a connection in Excel to view name.

Related

Right way for passing parameters for IN-subquery (classic ASP, ADODB.Command)

good afternoon
i'm going crazy with passing parameters to a very simple query with a subquery; i wrote hundreds of complicated queries, i'm afraid my fault is just in passing parameters to the subquery or everything else seems very normally manageable
making things simpler i prepare my query this way:
Set myConn = Server.CreateObject("ADODB.Connection")
myConn.Mode = 3 '3 = adModeReadWrite
myConn.Open MM_DEFDB_STRING
Set myCmd = Server.CreateObject("ADODB.Command")
myCmd.ActiveConnection = myConn
myCmd.CommandType = 1 '1 = adCmdText
myCmd.CommandText = strQuery 'this is my query with ? placeholders
myCmd.Prepared = false 'i won't repeat it
Set myRs = Server.CreateObject("ADODB.Recordset")
myRs.CursorType = 1 '0 = adOpenForwardOnly, 1 = adOpenKeyset, ...
myRs.LockType = 3 '3 = adLockOptimistic, ...
(here i prepare query and parameters)
myRs.Open myCmd
this should be correct, it is always the same for a lot of queries
1st case:
strQuery = SELECT * FROM TableA WHERE TableA.ID IN (SELECT myIDs FROM TableB WHERE TableB.NumericField=?) AND StringField=?
then i use this command cycling on two arrays, one for parameter values, another for types:
myCmd.Parameters.Append myCmd.CreateParameter("#Par" & i, VTypes(i), 1, 0, VValues(i))
here VValues is [8975, "011M1005D"] and VTypes is [3, 8]
result is 12 records, it is correct, i see those records on my database
2nd case (i only changed order of my two AND clauses):
strQuery = SELECT * FROM TableA WHERE StringField=? AND TableA.ID IN (SELECT myIDs FROM TableB WHERE TableB.NumericField=?)
VValues is ["011M1005D", 8975] and VTypes is [8, 3]
result is ZERO records, not an error but simply no records
WHY in your opinion ??? i would expect the same 12 records as before, the AND logic operator is simmetric!
3rd case (i use values on 2nd case instead of parameters):
strQuery = SELECT * FROM TableA WHERE StringField='011M1005D' AND TableA.ID IN (SELECT myIDs FROM TableB WHERE TableB.NumericField=8975)
result is correct: 12 records
curious, with plain values the order seems not important anymore
i also tried to debug the parameters collection, printing for each parameter it's value and it's type in order to check them just a line before the Open commmand: they seems correct and in the correct order in both cases
you are last chance or i have to rearrange a lot of code using some JOIN (but i really would understand my mistake before!). thank you for patience

Classic ASP with Oracle

I have a select statement which is running fine in sqlplus but when i m trying to run in Classic ASP code I am getting below error
ORA-01843: not a valid month
My Select Query is as below
SELECT YEAR_MONTH, LAST_DAY(TO_DATE(TO_DATE('201106','YYYYMM'),'MM/DD/YYYY')) AS MAX_END_DT FROM MONTH_DIM WHERE '04-28-2016' BETWEEN MONTH_START_DATE AND MONTH_END_DATE
ASP Code as Below
Dim rs
cmd.CommandType = adCmdText
cmd.CommandText = "SELECT YEAR_MONTH, LAST_DAY(TO_DATE(TO_DATE('" & MAXYEARMONTH & "','YYYYMM'),'MM/DD/YYYY')) AS MAX_END_DT FROM MONTH_DIM WHERE '" & END_DT & "' BETWEEN MONTH_START_DATE AND MONTH_END_DATE"
set rs = cmd.execute --here is problem
use TO_DATE('" & END_DT & "','MM/DD/YYYY')

Operation is not allowed when the object is closed (Object is not closed)

The following code, is generating that error.
Set getList = Server.CreateObject("ADODB.Command")
getList.ActiveConnection=EV_WikiConn
getList.Prepared = true
getList.commandtext= "declare #Lookup table(Id int identity(1, 1) , SongTitle nvarchar(512) )
insert into #Lookup(SongTitle)select * from ( values ('Deuce')) as x(a)
select A.AlbumName, S.SongTitle , S.Writers , S.Vocals , S.SID , S.TheTime
from Albums A inner join Songs S on A.AID = S.AID inner join #Lookup L on L.SongTitle = S.SongTitle order by L.Id"
set rsList = getList.execute
while not rsList.eof ' Error is on this line here.
I added this code here
Set getList = Server.CreateObject("ADODB.Command")
getList.ActiveConnection=EV_WikiConn
getList.Prepared = true
getList.commandtext= "declare #Lookup table(Id int identity(1, 1) , SongTitle nvarchar(512) )
insert into #Lookup(SongTitle)select * from ( values ('Deuce'),('Strutter'),('Parasite')) as x(a)
select A.AlbumName, S.SongTitle , S.Writers , S.Vocals , S.SID , S.TheTime
from Albums A inner join Songs S on A.AID = S.AID inner join #Lookup L on L.SongTitle = S.SongTitle order by L.Id"
set rsList = getList.execute
If rsList.State <> adStateOpen Then
While rsList.State <> adStateOpen
Set rsList = rsList.NextRecordset
rsList.movenext
wend
end if
This makes it run, however, I only get one record, instead of the 10 that is in the actual form. So, this is not going to work, but wanted to show what I have tried so far.
OK, got it all figured out. below is the code that was used, with a few notes in the code, to show what I did to make it work.
Set getList = Server.CreateObject("ADODB.Command")
getList.ActiveConnection=EV_WikiConn
getList.Prepared = true
getList.commandtext = _
"SET NOCOUNT ON " & _
"declare #Lookup table(Id int identity(1, 1) , " & _
"SongTitle nvarchar(512) ) " & _
"insert into #Lookup(SongTitle)select * from " & _
"( values ('Hotter_Than_Hell'), ('Firehouse'), ('She'), " & _
"('Parasite'), ('Nothin''_To_Lose')) as x(a) " & _
"select A.AlbumName, S.SongTitle , S.Writers , S.Vocals , " & _
"S.SID , S.TheTime from Albums A inner join " & _
"Songs S on A.AID = S.AID inner join " & _
"#Lookup L on L.SongTitle = S.SongTitle order by L.Id"
' the SET NOCOUNT ON, was added, but did not resolve the issue, I just left it in.
' The next 3 lines is what fixed the issue.
While rsList.State <> adStateOpen
Set rsList = rsList.NextRecordset
Wend
While Not rsList.EOF%>
<%=rsList("SongTitle")%>
<%rsList.movenext
wend
rsList.Close
set rsList = nothing
Regardless of what the OP believes this is a duplicate of
ADODB.Recordset error '800a0e78' Operation is not allowed when the object is closed
If we analyse the original code revision (ignoring the hard wrap which will cause an error in VBScript)
Set getList = Server.CreateObject("ADODB.Command")
getList.ActiveConnection=EV_WikiConn
getList.Prepared = true
getList.commandtext= "declare #Lookup table(Id int identity(1, 1) , SongTitle nvarchar(512) )
insert into #Lookup(SongTitle)select * from ( values ('Deuce')) as x(a)
select A.AlbumName, S.SongTitle , S.Writers , S.Vocals , S.SID , S.TheTime
from Albums A inner join Songs S on A.AID = S.AID inner join #Lookup L on L.SongTitle = S.SongTitle order by L.Id"
set rsList = getList.execute
while not rsList.eof ' Error is on this line here.
You can see that the original issue is the lack of
SET NOCOUNT ON;
to stop the closed ADODB.Recordset object being returned for the initial INSERT operation.
The subsequent edits the OP makes confuses the issue, before this adding SET NOCOUNT ON; would have fix the problem without needing further changes.
The next revision is where the confusion begins (again, ignoring the hard wrap which will cause an error in VBScript)
Set getList = Server.CreateObject("ADODB.Command")
getList.ActiveConnection=EV_WikiConn
getList.Prepared = true
getList.commandtext= "declare #Lookup table(Id int identity(1, 1) , SongTitle nvarchar(512) )
insert into #Lookup(SongTitle)select * from ( values ('Deuce'),('Strutter'),('Parasite')) as x(a)
select A.AlbumName, S.SongTitle , S.Writers , S.Vocals , S.SID , S.TheTime
from Albums A inner join Songs S on A.AID = S.AID inner join #Lookup L on L.SongTitle = S.SongTitle order by L.Id"
set rsList = getList.execute
If rsList.State <> adStateOpen Then
While rsList.State <> adStateOpen
Set rsList = rsList.NextRecordset
rsList.movenext
wend
end if
Let's just dissect this part
If rsList.State <> adStateOpen Then
While rsList.State <> adStateOpen
Set rsList = rsList.NextRecordset
rsList.movenext
wend
end if
First the If and While loop do the same thing accept the While does it repeatedly until the condition is met, making the If completely irrelevant.
The While loop checks for the current state of the ADODB.Recordset which without SET NOCOUNT ON; is returned as adStateClosed (due to the INSERT operation). This is fine but by changing the While loop from
while not rsList.eof
to
While rsList.State <> adStateOpen
the condition has been changed and the While is no longer checking for rsList.EOF which would be the case when we are enumerating the ADODB.Recordset object. However, now it is only checking for the .State of rsList which once .NextRecordset is called will exit the loop as a open ADODB.Recordset object has been returned. Because the condition has been met the loop will only run once calling .MoveNext once and only returning one record.
So to summaries using
SET NOCOUNT ON;
initially would have negated this whole scenario but hey "I don't understand the code" apparently.

Error '80004005' only when SELECT DISTINCT with ASP Classic

I am developing in ASP VBScript at work and need to run a SELECT DISTINCT query but I am having some troubles.
I have other queries in my code that work perfectly fine, that do not use SELECT DISTINCT.
Here is what I am using:
Dim sections()
c = 1
set conn=Server.CreateObject("ADODB.Connection")
set rs=Server.CreateObject("ADODB.Recordset")
conn.Open "PROVIDER=Microsoft.Jet.OLEDB.4.0;Jet OLEDB:Database Password=******;User ID=Admin;" & _
"DATA SOURCE=" & Server.MapPath("modules.mdb")
rs.open "SELECT DISTINCT section FROM modules WHERE area='First' ORDER BY lvl ASC",conn
ReDim sections(10)
do while not rs.EOF
sections(c) = rs("section")
c = c + 1
rs.MoveNext
loop
rs.Close
conn.Close
set rs = nothing
set conn = nothing
Which gives me this error:
error '80004005'
on the line of the SQL query
The only way to fix this is to use "GROUP BY" instead of "DISTINCT"
SELECT DISTINCT section FROM modules WHERE area='First' ORDER BY lvl ASC
SELECT section FROM modules WHERE area='First' GROUP BY section ORDER BY lvl ASC

Update records details using Oracle 10g DB and VB.net

I am trying to figure out how to get some output as to what records were updated when running this query:
UPDATE CSR.TARGET ces
SET (STATUS_CODE, COMPLETE_DATE, DATA) =
(SELECT 'ERROR', '', REPLACE(c.Data, ' x</csr', '</csr')
FROM CSR.TARGET C
WHERE (c.EID = ces.EID)
AND c.STATUS_CODE = 'ERROR')
WHERE EXISTS (SELECT 1
FROM CSR.TARGET C
WHERE (c.EID = ces.EID)
AND c.STATUS_CODE = 'ERROR')
If there are 3 records that were updated by that above query then i would like to know what they were (record ID, etc). How would i go about doing that?
Currently it just tells me 3 records were updated and thats it. No other details.
Any help would be great! Thanks :o)
UPDATE
I am needing this for a query using VB.net so i do not think i can do PL/SQL type of thing?
Dim OracleCommand As New OracleCommand()
Dim ra As Integer
OracleCommand = New OracleCommand("UPDATE CSR.TARGET ces " & _
"SET (STATUS_CODE, COMPLETE_DATE, DATA) = " & _
"(SELECT 'ERROR', '', REPLACE(c.Data, ' x</csr', '</csr') " & _
"FROM CSR.TARGET C " & _
"WHERE (c.EID = ces.EID) " & _
"AND c.STATUS_CODE = 'ERROR') " & _
"WHERE EXISTS (SELECT 1 " & _
"FROM CSR.TARGET C " & _
"WHERE (c.EID = ces.EID) " & _
"AND c.STATUS_CODE = 'ERROR')", OracleConnection)
Try
ra = OracleCommand.ExecuteNonQuery()
OracleConnection.Close()
....
David
You should be able to use the RETURNING clause. Assuming that the EID column is the "record ID" you're referring to and that it is numeric
CREATE OR REPLACE TYPE num_tbl
IS
TABLE OF NUMBER;
DECLARE
l_modified_eids num_tbl;
BEGIN
UPDATE csr.target ces
SET <<omitted>>
WHERE <<omitted>>
RETURNING eid
BULK COLLECT INTO l_modified_eids;
<<Iterate through l_modified_eids to see which rows are modified>>
END;
Based on my reading of that query, all records that have an EID that matches the EID of a record who's status_code is 'ERROR' will be udpated. So if you have a table like this:
ID EID STATUS_CODE
-- --- -----------
1 1 ERROR
2 1 OKAY
3 2 OKAY
both records with ID 1 and 2 would be updated, because 2's EID field matches 1's EID field, and 1's EID field shows error. When it updates, it always uses the data from the row with the 'ERROR'.

Resources