SqlDataReader and select don't work properly - sql-server

VB.NET and SQL Server 2014. This piece of code produce a weird error. HasRows is TRUE but the selection is empty and, more the this, the selection shouldn't be empty because there are many records into the table that satisfy the where conditions.
If I make the same select directly in SQL Server, all works fine. The anno and nomediv parameters are corrects.
try
connection1.Open()
sqlcmd = String.Format("select distinct HomeTeam from tutto WHERE anno='{0}' AND div= '{1}' AND HomeTeam <> 'NULL'", annocampionato, nomediv(i))
SetSqlCommand(sqlcmd, 1)
sqlreader1 = sqlcommand1.ExecuteReader()
Do While sqlreader1.Read()
If sqlreader1.HasRows Then '
nomesquadra = RTrim(sqlreader1.GetString(0))
......
End If
Loop
connection1.Close()
Catch ex As Exception
MsgBox(ex.Message)
connection1.Close()
End Try
Try to explain better: the program enters into the WHILE loop and sqlreader1.hasrows is TRUE but sqlreader1.GetString(0) return index out of range exception. If I change the command to SELECT * FROM tutto, the result is the same.
Thanks in advance
Pamela
P.S. I'll avoid to use the string concat for the release version

I think your logic is backward. Granted, the documentation is thin.
If you get one line then the following happens:
Do While sqlreader1.Read()
returns true and reads the data.
If sqlreader1.HasRows Then '
returns false because there is no MORE data.
It makes no sense to check HasRows in the loop. In fact, it makes no sense to check it at all - just loop over the Read() method.

Related

save huge xml from sql to web

In sqlserver I have a function which generates a complex xml of all products with several tables joined: location, suppliers, orders etc.
No problem in that, it runs in 68 sec and produces around 450MB.
It should only be called occationally during migration to another server, so it doesn't matter it takes some time.
I want to make this available for download over webserver.
I've tried some variations of this in classic asp:
Response.Buffer = false
set rs=conn.execute("select cast(dbo.exportXML() as varchar(max)) as res")
response.write rs("res")
But I just get a standard
An error occurred on the server when processing the URL. Please contact the system administrator.
If you are the system administrator please click here to find out more about this error.
Not my usual custom 500-errorhandler, so I'm not sure how to find the error.
The problem is in response.write rs("res"), if i just do
temp = rs("res")
the script runs, but displays nothing of cause; if I then
response.write temp
I get the same failure.
So the problem is writing such a ling string.
Can I save the file from tsql directly; and run the job periodically from sql agent?
I found that there seems to be a limit on how much data can be written at once using Response.Write. The workaround I used was to break the data into chunks like this:
Dim Data, Done
Done = False
Do While Not Done
Data = RecordSet(0).GetChunk(8192)
If Not Len(Data) = 0 Then
Response.Write Data
Else
Done = True
End If
Loop
Try this:
Response.ContentType = "text/xml"
rs.CursorLocation = 3
rs.Open "select cast(dbo.exportXML() as varchar(max)) as res",conn
'Persist the Recordset in XML format to the ASP Response object.
'The constant value for adPersistXML is 1.
rs.Save Response, 1

Asp-Classic ADODB Recordset missing Records

one of the simplest Components in my website just stopped working from one day to the other without any changes in Code.
'Connection Declaration as connection
Set rs = Server.CreateObject ("ADODB.Recordset")
rs.Open "SELECT * FROM tablename ORDER BY id DESC", connection, 1, 3
while not rs.EOF
'writing some Table from the records in DB
'Simplified Code %>
<tr><td><%=rs("id")%></td><td><%=rs("description")&></td></tr>
<%
rs.MoveNext
Wend
in my Database i have verified the extraordinary number of 30 records :(
when above code is executed i see 2 of them
This tells me two things,
first: the tablename is Correct and the connection to the Database is established
second: the table-generation in itself is correct
I also have a smaller Testing-System. there the exact same code on a sample Database produces the expected Results.
Unfortunately i have no means of "instant-access" to my main page for "debugging purposes"
Is there any known Bugs for ADODB Recordsets losing records? Please keep in mind the Code is exactly the same and working "error-free".
A few suggestions.
Use Option Explicit if not already - (I didn't see it in your code) this will display SQL errors, so that may help.
Check that you haven't destroyed RS.
Also, "connection, 1, 3" means 'active connection', 'cursortype', 'locktype'
Your cursortype is 'adOpenKeySet' - 3 or 'adOpenStatic' is better, unless you specifically want a KeySet? try calling the Open this way to force the defaults (which oddly enough are 3 and 1 respectively !) :
RS.Open "SELECT * FROM tablename ORDER BY id DESC",connection
I also usually write RS output loops like this :
If Not RS.BOF Then
' write table tag HTML
Do While Not RS.EOF
' write table row + row data
RS.MoveNext
Loop
' write end table tag HTML
Else
' write "RS is empty!"
End If
This will make it easier to tell if recordset is empty or not.

Getting "Multiple-step operation generated errors. Check each status value." error using ADO with SQL server 2008

We are in the process to migrate our SQL 2000 box to SQL 2008. But we ran into an issue; when a result set (rows or not) is returned by using a query that has a UNION. Later in the code we try to add a new row and assign field to it but because a UNION was used, when we try to assign a value to the field it gives us a Multiple-step operation generated errors. Check each status value. error. We tried the following code on a Windows XP & Windows 7 and got the same result. But when we change our connection string to point back to our SQL 2000 box we don't get that error any more.
The following example show the problem we are having.
var c = new ADODB.Connection();
var cmd = new ADODB.Command();
var rs = new ADODB.Recordset();
object recordsAffected;
c.Open("Provider=SQLOLEDB;Server=*****;Database=*****;User Id=*****;Password=*****;");
cmd.ActiveConnection = c;
cmd.CommandType = ADODB.CommandTypeEnum.adCmdText;
cmd.CommandText = "create table testing2008 (id int)";
cmd.Execute(out recordsAffected);
try {
cmd.CommandText = "select * from testing2008 union select * from testing2008";
rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient;
rs.Open(cmd, Type.Missing, ADODB.CursorTypeEnum.adOpenDynamic, ADODB.LockTypeEnum.adLockBatchOptimistic, -1);
rs.AddNew();
rs.Fields["id"].Value = 0; //throws exception
rs.Save();
}
catch (Exception ex) {
MessageBox.Show(ex.ToString());
}
finally {
cmd.CommandText = "drop table testing2008";
cmd.Execute(out recordsAffected);
c.Close();
}
The link below is an article that gives a great breakdown of the 6 scenarios this error message can occur:
Scenario 1 - Error occurs when trying to insert data into a database
Scenario 2 - Error occurs when trying to open an ADO connection
Scenario 3 - Error occurs inserting data into Access, where a fieldname has a space
Scenario 4 - Error occurs inserting data into Access, when using adLockBatchOptimistic
Scenario 5 - Error occurs inserting data into Access, when using Jet.OLEDB.3.51 or ODBC driver (not Jet.OLEDB.4.0)
Scenario 6 - Error occurs when using a Command object and Parameters
http://www.adopenstatic.com/faq/80040e21.asp
Hope it may help others that may be facing the same issue.
It is type mismatch, try
rs.Fields["id"].Value = "0";
or make sure you assign a Variant to the value.
Since I posted this problem, we figured out that the problem was when you do a union the attributes on the fields are not bound (i.e. the attributes: basecatalog, basetable & basecolumn are empty) to remedy our problem we had to force the values of those attributes, by saving the recordset to xml (adPersistXML), change the xml and reopen the recordset from the xml. This rebound the fields and we were able to continue. We know this may not be the most efficient solution, but it was for an older app and we didn't want to rewrite the sql statements. It looks like the main error Multiple-step operation generated errors. Check each status value. is related to when an error occurs when a value is assigned to a field.
Two things I can think of... Make sure your "ID" column will accept a zero (0). Also - I've stopped this issue on one occasion by not using the adUseClient cursor (try server).
Many times this is a type mismatch, trying to stuff a NULL into a non-null column, or attempting to write more characters into a column than it's designed to take.
Hope this helps. - Freddo
Same issue occurred to me the problem was that i violated an object property , in my case it was size the error came out as
"IntegrationException: Problem (Multiple-step operation generated errors. Check each status value.)"
Imports ADODB
Dim _RecordSet As Recordset
_rs.Fields.Append("Field_Name", DataTypeEnum.adVarChar, 50)
_Recordset("Field_Name").Value = _RecordDetails.Field_NameValue
_RecordDetails.Field_NameValue length was more than 50 chars , so this property was violated , hence the error occurred .
I found another scenario:
When I was trying to set the value of a adLongVarChar field in a new record for a memory-only adodb.recordset. In my case, the error was triggered because the string I was passing had a buried unicode character.
I found this error when our legacy application was trying to parse 1/1/0001 12AM date and time. Looks like VB6 recordsets doesn't like that value.
To get rid of the errors, I had to set all the offending dates to null.
I was getting this error when trying to insert/update the field with a value that did not match the table>field type.
For example, the database table > field was
char(1)
however, I was trying to insert/update
"apple"
into the record.
Once I change the inputted value to "a" and it worked.

Why adParamOutput parameter doesn't contain a value after execute

I am using ASP classic with ADO, connecting to SQL Server 2008.
I inherited this code and it is so mangled that I will try to recreate the relevant parts. If you need more detail or I left something out, please let me know.
I create a command and add parameters
oCmd.CommandType = adCmdStoredProc
...
oCmd.Parameters.Append oCmd.CreateParameter("#MyOutputParam", adInteger, adParamOutput, 4, NULL)
Later, I open a reader from that command:
oRS.Open oCmd, , adOpenForwardOnly, adLockReadOnly
After that, while oRS is open but before I've read any records or values, I try to get the output parameter's value using one of the lines below:
val1 = oCmd("#MyOutputParam")
val2 = oCmd("#MyOutputParam").Value
val3 = oCmd.Parameters("#MyOutputParam").Value
All three (val1, val2, val3) variables are DB NULL.
I have confirmed that running the SP in query analyzer returns a value to the #MyOutputParam parameter:
declare #p33 int
exec usp_GetResultAndOutput 1, 2, 3, #p33 output
select #p33
That returns a recordset of my expected records and a second recordset showing a number in a single row.
I've even tried calling rs.NextRecordset before attempting to get the output parameter and that didn't work.
Is there some other way that I need to be handling Output parameters?
Is it okay that I am returning a recordset and output parameters?
Output parameters cannot be retrieved until all the recordsets are enumerated until the end. Just think, how could the client possibly retrieve the output value of a parameter before the execution finishes? The Execute() call is simply starting the execution, the batch continues to execute on the server until all results are returned. While a client is iterating over a resultset produced by a SELECT the batch is executing that SELECT. The value of the output parameter is known only at the end of the batch. Therefore is not possible to know the output parameter value until the batch finished, which implies that all statements have executed, which in turn requires that all resultsets were consumed (iterated) by the client.
This is the canonical form of parsing a set of results:
do
{
while (rs.MoveNext)
{
// do something with the row
}
} while (Not rs.NextRecordset Is Nothing)
// now is safe to read the out param
response.write oCmd("#MyOutput")
As far as I can test the only thing that matters this is the CursorLocation. As long as the CursorLocation is set to adUseClient (3), the output parameters can be accessed anytime after the Execute. Any of the following do that
oConn.CursorLocation = adUseClient
or
oRs.CursorLocation = adUseClient
This is tested on SQL 2008 R2, IIS/ASP on Windows 7 and with SQLOLEDB provider.

SDAC -RecordCount and FetchAll

I am using SDAC components to query a SQL Server 2008 database. It has a recordcountproperty as all datasets do and it also has the FetchAll property (which I think it is called packedrecords on clientdatasets). Said that, I got a few questions:
1 - If I set FetchAll = True the recordcount property returns ok. But in this case, when I have a large database and my query returns a lot of lines, sometimes the memory grows a lot (because it is fetching all data to get the recordcount of course).
2 - If I set FetchAll = False, the recordcount returns -1 and the memory does not grow. But I really need the recordcount. And I also wanna create a generic function for this, so I dont have to change all my existent queries.
What can I do to have the recordcount working and the memory usage of the application low in this case?
Please, do not post that I dont need recordcount (or that I should use EOF and BOF) because I really do and this is not the question.
I thought about using a query to determine the recordcount, but it has some problems since my query is going to be executed twice (1 for recordcount, 1 for data)
EDIT
#Johan pointed out a good solution, and it seems to work. Can anybody confirm this? I am using 1 TMSCconnection for every TMSQuery (because i am using threads), so I dont think this will be a problem, will it?
MSQuery1.FetchAll := False;
MSQuery1.FetchRows := 10;
MSQuery1.SQL.Text := 'select * from cidade';
MSQuery1.Open;
ShowMessage(IntToStr(MSQuery1.RecordCount)); //returns 10
MSQuery1.Close;
MSQuery2.SQL.Text := 'SELECT ##rowcount AS num_of_rows';
MSQuery2.Open;
ShowMessage(MSQuery2.FieldByName('num_of_rows').AsString); //returns 289
EDIT 2*
MSQuery1 must be closed, or MSQuery2 will not return the num_of_rows. Why is that?
MSQuery1.FetchAll := False;
MSQuery1.FetchRows := 10;
MSQuery1.SQL.Text := 'select * from cidade';
MSQuery1.Open;
ShowMessage(IntToStr(MSQuery1.RecordCount)); //returns 10
//MSQuery1.Close; <<commented
MSQuery2.SQL.Text := 'SELECT ##rowcount AS num_of_rows';
MSQuery2.Open;
ShowMessage(MSQuery2.FieldByName('num_of_rows').AsString); //returns 0
Run your query as normal, than close the query
MSQuery1.SQL.Text := 'select * from cidade';
MSQuery1.Open;
MSQuery1.Close;
You need the close otherwise SQL-server has not closed the cursor yet, and will not register the query as 'completed'.
and run the following query right afterwards:
SELECT ##rowcount AS num_of_rows
This will select the total number of rows your last select read.
It will also select the number of rows your update/delete/insert statement affected.
See: http://technet.microsoft.com/en-us/library/ms187316.aspx
Note that this variable is per connection, so queries in other connections do not affect you.
I use ODAC and I believe SDAC inherits from the same base classes and works the same way as ODAC. In ODAC, there is an option called QueryRecCount under Options in your query component. Look for TCustomDADataSet.Options.QueryRecCount in your help file.
Setting QueryRecCount = True and FetchAll = False will reduce your memory usage and give you the record count. But SDAC will run a second query in the background to get the record count so it does add a little bit of extra time to your query.
Take a look at the Devart forum entry at http://www.devart.com/forums/viewtopic.php?t=8143.

Resources