Tuesday, March 27, 2012
binding input parameters leads to SQL_ERROR
select a, b
from mytbl
where col0 = ?
The first time I run SQLExecute, everything works fine, but when I call
SQLExecute a second time with a modified input parameter, it returns
SQL_ERROR. Below is the code I'm running with the error checking removed and
the names simplified.
SQLAllocHandle(SQL_HANDLE_STMT, hconn, &m_hstmt)) ;
SQLPrepare(m_hstmt, (UCHAR *)m_query.GetBuffer(), m_query.GetLength()));
SQLBindParameter(m_hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0,
&where_param, 0, 0);
SQLBindCol(m_hstmt, 1, SQL_C_BIT, addr1, 0, 0)
SQLBindCol(m_hstmt, 2, SQL_C_BIT, addr2, 0, 0)
SQLExecute(m_hstmt) //works ok
SQLFetchScroll(m_hstmt, SQL_FETCH_NEXT, 0)
where_param = 10
SQLExecute(m_hstmt) //fails
SQLFetchScroll(m_hstmt, SQL_FETCH_NEXT, 0)
My goal is to run execute many times with a variety of parameters. I was
trying to have the odbc driver read from the address specified in
SQLBindParameter to set the value of the input parameter. I'm further
confused by the problem because when I try to retrieve error information by
calling SQLGetDiagRec, nothing is returned. Thanks for your help.
Scott
The problem goes away when I call SQLCloseCursor after completing the fetch.
The MSDN SQLBindParameter documentation at
http://msdn.microsoft.com/library/de...dparameter.asp
gives no indication that SQLCloseCursor should be needed.
I suppose that I am now just concerned that I am introducing extra
processing overhead by calling SQLCloseCursor.
Scott
"ScottD" wrote:
> I am trying to read the results from a query like
> select a, b
> from mytbl
> where col0 = ?
> The first time I run SQLExecute, everything works fine, but when I call
> SQLExecute a second time with a modified input parameter, it returns
> SQL_ERROR. Below is the code I'm running with the error checking removed and
> the names simplified.
> SQLAllocHandle(SQL_HANDLE_STMT, hconn, &m_hstmt)) ;
> SQLPrepare(m_hstmt, (UCHAR *)m_query.GetBuffer(), m_query.GetLength()));
> SQLBindParameter(m_hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0,
> &where_param, 0, 0);
> SQLBindCol(m_hstmt, 1, SQL_C_BIT, addr1, 0, 0)
> SQLBindCol(m_hstmt, 2, SQL_C_BIT, addr2, 0, 0)
> SQLExecute(m_hstmt) //works ok
> SQLFetchScroll(m_hstmt, SQL_FETCH_NEXT, 0)
> where_param = 10
> SQLExecute(m_hstmt) //fails
> SQLFetchScroll(m_hstmt, SQL_FETCH_NEXT, 0)
>
> My goal is to run execute many times with a variety of parameters. I was
> trying to have the odbc driver read from the address specified in
> SQLBindParameter to set the value of the input parameter. I'm further
> confused by the problem because when I try to retrieve error information by
> calling SQLGetDiagRec, nothing is returned. Thanks for your help.
> Scott
|||Are you making sure that you've fetch all of the rows? Even if only
one row is returned by the query, you should call SQLFetchXXX() until
it returns SQL_NO_DATA. Otherwise the driver doesn't necessarily know
that you've finished fetching rows on the current resultset/cursor.
Alternatively, you can use SQLMoreResults() to flush the remaining data
on the wire and position on the next resultset (if there is one,
otherwise it cleans up the connection).
SQLCloseCursor shouldn't add too much overhead. I'm assuming you're
using the default (firehose) cursor. If so, SQLCloseCursor just makes
sure that all of the data from the previous statement has been
consumed, and the connection is ready for the next statement.
Brannon
bind variables / parameter queries
I'm writing an Access pass-through query against a SQL server backend and I need some advice on passing parameters. Currently I use vba to substitute the literal values for the parameters prior to passing the query to SQL Server. However, I am going through a loop thousands of times with different literals for these parameters which causes the server's cache to fill up. In Oracle, there is a way to use bind variables for the parameters so that only one copy of the query is cached.
Does anyone know how I can do this in SQL Server?
For instance, I have 20,000 employees and I'm pulling info by SS#:
Select * from EmpTable where SS_number = [SSN]
Is there a way I can pass this query to SQL Server and then pass the value of [SSN] as I loop through the dataset?
Thanks.write a stored procedure, and instead of calling the database engine 20,000 times, just call it once and pass it a list of 20,000 numbers
come to think of it, where would you get 20,000 numbers? sounds like you might want to look for a JOIN solution|||SQL Server actually goes you one better, in that its ODBC drivers will automagically parameterize a query for you (unless you get really creative in modifying the query).
As Rudy pointed out though, if you have more than 20 iterations from a given client, you really ought to be thinking about a JOIN based solution... Doing that kind of thing on that scale one row at a time is WAY too much work for me!
-PatP|||Thanks, guys. I'll get write access to the backend and write a stored proc.
I'll have to read up on how to pass values to the proc (I'm guessing it's like a function).
Thanks again.|||How about this?:
Dim cnn As ADODB.Connection
Set cnn = New ADODB.Connection
cnn.Open "DSN=PKRebate2001", "sa", ""
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = cnn
.CommandText = "sp_UpdateCustomerUnique"
.CommandType = adCmdStoredProc
.Parameters.Refresh
.Parameters("@.ImportMonth").Value = IM
.Execute
End With
Set cmd = Nothing
Set cnn = Nothing|||If you are looking to get automatic parameterization, that VBA code is conceptually good.
-PatP
Thursday, March 22, 2012
Binary parameters to stored procedures?
CREATE PROCEDURE Reporting_TicketSelectGroups
@.publicPart NVARCHAR(400),
@.checkField BINARY(46),
@.langCode VARCHAR(9)
AS
...
I've created a DataSet with the name of the stored proc as as its query
string and with this expression as its parameter value for @.checkField:
=Code.CheckField(Parameters!ticket.Value)
This in turn refers to a function in the Code tab of the Report
Properties property sheet:
Public Function CheckField(ByVal aTicket As String) As Byte()
...
Return Convert.FromBase64String(...)
End Function
The idea is that there is a parameter called ticket and it is split in
to two parts, one part being in binary, and these two parts are then
used as parameters to the various queries used in the report. When I
attempt to preview this report, I get this error message:
An error has occurred during report processing.
Query execution failed for data set 'Groups'.
Implict conversion from data type nvarchar to binary is not allowed.
Use the CONVERT function to run this query.
I'm assuming the last two sentences come from SQL Server and indicate
that my byte[] value is being converted to string on the way -- either
that or I have stuffed it up in some way. Can anyone tell me whether
this approach should work, or is simply not possible to pass binary
parameters from RS?
--
Damian CugleyI wrote:
> I have a stored procedure that takes a byte string as an argument:
> [...] Can anyone tell me whether
> this approach should work, or is simply not possible to pass binary
> parameters from RS?
I gather from the deafening silence that it is possible to pass neither
binary parameters nor other formats like UUIDs.
My workaround was straightforward enough, once I had decided to do it: I
wrote a base64 (RFC 1521) codec in T-SQL so I can pass the data safely
as a character string.
Wednesday, March 7, 2012
BETWEEN predicate with passed parameters
I tried a standard BETWEEN predicate in my WHERE clause like:
IF '200401' BETWEEN ?BegPer and ?EndPer then salesanal.ptdbud01 else 0
But, it's returning an error that my Then statement is missing. I can't use a normal statement like 'IF ?BegPer >= '200401' and ?EndPer <= '200401', then....' because users could enter a RANGE of periods, so it would be difficult to code all of the possible combinations this way. I'm actually doing this in Crystal, but if someone can give me a standard MSSQL example, I can translate that over to Crystal.
Thanks in advance,
MichelleUSE Northwind
GO
SELECT *
FROM Orders
WHERE OrderDate >= '1996-07-08 00:00:00.000'
AND ShippedDate <= '1996-07-15 23:59:59.000'
GO|||Yeah, I can't just use the standard WHERE clause with >= and <=. I need to return a separate value for each month of the calendar year (these are setup in separate fields on my report). So, if the user enters parameter values into begper = '200401' and endper = '200403', then the report needs to print all 3 fields for months 01, 02, and 03, because they all fall within the range of 200401 and 200403. I would have to code all possible combos of a begper >= 'xx' and endper <= 'yy', ya know? While that may be entertaining, I wonder if there's a more efficient route? <g>
More details:
Table:
Custid, Janbudget, Febbudget, Marbudget, Aprbudget, etc etc.
User enters runtime parameters for a monthly period range, such as between '200401' (January) and '200403' (March). In this case, my report should only print the values in fields Janbudget, Febbudget and Marbudget. All other fields will either not print or print 0.
Any other ideas?
Thanks!
Michelle :)
Originally posted by Brett Kaiser
USE Northwind
GO
SELECT *
FROM Orders
WHERE OrderDate >= '1996-07-08 00:00:00.000'
AND ShippedDate <= '1996-07-15 23:59:59.000'
GO|||You need to use Group BY and use scalar functions...hold on...|||Like this?
SELECT OrderId
, DATEPART(yy,OrderDate) AS OrderDate_yy
, DATEPART(mm,OrderDate) AS OrderDate_mm
, DATEPART(yy,ShippedDate) AS ShippedDate_yy
, DATEPART(mm,ShippedDate) AS ShippedDate_mm
, COUNT(*) AS Orders
FROM Orders
WHERE OrderDate >= '1996-07-08 00:00:00.000'
AND ShippedDate <= '1996-07-15 23:59:59.000'
GROUP BY OrderId
, DATEPART(yy,OrderDate)
, DATEPART(mm,OrderDate)
, DATEPART(yy,ShippedDate)
, DATEPART(mm,ShippedDate)
Tuesday, February 14, 2012
Best way to launch report from a C# Winforms app?
Ideally I would like to create an IE window that shows only the report, that is, only the report viewer toolbar is visible, the IE toolbars and menus are hidden. I want to specify IE as the browser in case some other browser is installed as the default web browser.
Can anyone link me to a tutorial or provide a code snip? Thanks.Hi do not launch in IE. use ReportViewer Control to see that. You can add reports to your application by adding from Add Web Reference.|||Alas, it is at present still a .Net 1.1 application. I'll use ReportViewer when I upgrade it to .Net 2.0. In the meantime I'll launch IE to view the report. I tried to use SendKeys.Send to send F11 to get IE in fullscreen mode, but SetForegroundWindow did not work when given the Handle property of the process object returned by Process.Start.
Thanks for your response.