ODBC does not return value from table - odbc

I have trouble getting right values throughodbc. Instead of returning value stored in table to variable rezervovani, odbc returns value -858993460. I suspect using wrong datatypes in sqlbindparameter, but I do not know where.
DSN connection string is removed from code as is error reporting.
Please give advice.
int _tmain(int argc, _TCHAR* argv[])
{
SQLHENV hEnv;
SQLRETURN ret;u
SQLHDBC hDB2dbc;
SQLHSTMT hDB2stm;
SQLINTEGER rezervovani, nts = SQL_NTS;
string stm = "select"
" (select count(*) from bk_klienti_report where stav = 1) rezervovany,"
" (select count(*) from bk_klienti_report where stav = 2) konfigurace,"
" (select count(*) from bk_klienti_report where funkcni = 1) funkcni,"
" (select sum(zruseny) from bk_klienti_report where stav = 3) zruseny,"
" (select sum(nova_smlouva_dodatek) from bk_klienti_report) dodatek,"
" (select sum(funkcni) from bk_klienti_report where majitel = 'Podnikatel') podnikatel,"
" (select sum(funkcni) from bk_klienti_report where majitel = 'Obcan') obcan,"
" (select sum(funkcni) from bk_klienti_report where majitel = 'Zamestnanec') zamestnanec,"
" (select sum(disp_fo) from bk_klienti_report where funkcni = 1) + (select sum(disp_fo) from bk_klienti_report where pouze_smlouva = 1) disponenti_fo,"
" (select sum(disp_po) from bk_klienti_report where funkcni = 1) + (select sum(disp_po) from bk_klienti_report where pouze_smlouva = 1) disponenti_po"
" from bkdat001.bk_klienti_report";
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
ret = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_UINTEGER);
ret = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDB2dbc);
ret = SQLConnectA(hDB2dbc, (SQLCHAR*)DB2DSN.c_str(), DB2DSN.length(), (SQLCHAR*)DB2USR.c_str(), DB2USR.length(), (SQLCHAR*)DB2PWD.c_str(), DB2PWD.length());
ret = SQLAllocHandle(SQL_HANDLE_STMT, hDB2dbc, &hDB2stm);
ret = SQLPrepareA(hDB2stm, (SQLCHAR *)stm.c_str(), SQL_NTS);
ret = SQLBindParameter(hDB2stm, 3, SQL_PARAM_INPUT, SQL_C_SSHORT, SQL_INTEGER, NULL, 0, &rezervovani, sizeof(rezervovani), (SQLINTEGER *)nts);
ret = SQLExecute(hDB2stm);
cout << rezervovani
SQLDisconnect(hDB2dbc);
SQLFreeHandle(SQL_HANDLE_DBC, hEnv);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 1;
}

Related

Conversion failed when converting the varchar to data type int: SQL

I am creating a web app in asp.net mvc I have a query which looks like below
using (SqlConnection conn = new SqlConnection(_connStr))
{
conn.Open();
var p = new DynamicParameters();
p.Add("#SP_RoleId", "7,8,9", dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#SP_UserId", userId, dbType: DbType.Int32, direction: ParameterDirection.Input);
var obj = conn.Query<PendingKmsRequest>(sql: "SELECT [f].[id] AS [FileId],[fvr].[Id] AS [RequestId], [au].[Name]"
+ ", [fvr].[RequestByUserId], [fvr].[FromDate], [fvr].[ToDate],[f].[Title], [fvr].[Status], [fvr].[StatusRemarks]"
+ "FROM [dbo].[File] AS[f]"
+ "INNER JOIN [dbo].[FileViewRequest] AS [fvr] ON [f].[CurrentFileVersionId] = [fvr].[FileVersionId]"
+ "INNER JOIN [Access].[User] AS [au] ON [fvr].[RequestByUserId] = [au].[Id]"
+ "WHERE ([fvr].[Status] = 'P' OR ([fvr].[Status] = 'A' AND [fvr].[StatusByUserId] = #SP_UserId AND GETDATE() BETWEEN [fvr].[FromDate] AND [fvr].[ToDate]))"
+ "AND (SELECT 1 FROM [Access].[UserRoleMap] WHERE UserId=#SP_UserId AND RoleId IN(#SP_RoleId)) = 1", param: p, commandType: CommandType.Text);
if (obj != null && obj.Count() > 0)
return obj.ToList();
else
return new List<PendingKmsRequest>();
}
NOTE: Role id is always like (7,8,9) and it is int column in the database.
I get this conversion error on this line of code:
WHERE UserId = #SP_UserId AND RoleId IN (#SP_RoleId))
This is the error:
Conversion failed when converting the nvarchar value '7,9,10' to data type int.
How can I prevent this error?
The following line in your question code:
p.Add("#SP_RoleId", "7,8,9", dbType: DbType.String, direction: ParameterDirection.Input);
The value "7,8,9" is string and parameter type DbType.String is string as well.
But, you said this is int in your database. This is mismatch.
Further, your query:
WHERE UserId = #SP_UserId AND RoleId IN (#SP_RoleId))
The query is using IN clause.
Dapper can convert your value for IN clause if pass in an IEnumerable.
Change the line of code as below:
p.Add("#SP_RoleId", new[] {7,8,9}, dbType: DbType.Int32, direction: ParameterDirection.Input);
No need to use convert string in array or any string split() function
If you have comma saperated string then you can check it like below steps,
If you have #SP_RoleId = "7, 8, 9"
You can convert this string as below
#SP_RoleId = ",7,8,9," ( ',' + ltrim(rtrim( #SP_RoleId )) + ',' )
Now use Like to check ,UserId,
Updated code as below,
using (SqlConnection conn = new SqlConnection(_connStr))
{
conn.Open();
var p = new DynamicParameters();
p.Add("#SP_RoleId", "7,8,9", dbType: DbType.String, direction: ParameterDirection.Input);
p.Add("#SP_UserId", userId, dbType: DbType.Int32, direction: ParameterDirection.Input);
var obj = conn.Query<PendingKmsRequest>(sql: "SELECT [f].[id] AS [FileId],[fvr].[Id] AS [RequestId], [au].[Name]"
+ ", [fvr].[RequestByUserId], [fvr].[FromDate], [fvr].[ToDate],[f].[Title], [fvr].[Status], [fvr].[StatusRemarks]"
+ "FROM [dbo].[File] AS[f]"
+ "INNER JOIN [dbo].[FileViewRequest] AS [fvr] ON [f].[CurrentFileVersionId] = [fvr].[FileVersionId]"
+ "INNER JOIN [Access].[User] AS [au] ON [fvr].[RequestByUserId] = [au].[Id]"
+ "WHERE ([fvr].[Status] = 'P' OR ([fvr].[Status] = 'A' AND [fvr].[StatusByUserId] = #SP_UserId AND GETDATE() BETWEEN [fvr].[FromDate] AND [fvr].[ToDate]))"
+ "AND (SELECT 1 FROM [Access].[UserRoleMap] WHERE ',' + lTrim(rTrim(#SP_RoleId)) + ',' like '%,' + lTrim(rTrim(UserId) + ',%' " // Updated line
+ "AND RoleId IN(#SP_RoleId)) = 1", param: p, commandType: CommandType.Text);
if (obj != null && obj.Count() > 0)
return obj.ToList();
else
return new List<PendingKmsRequest>();
}

use operation logic inside SQL Query?

I have a Query string inside Employees Page that read URL Parameter
to get Companies employees from DataBase if parameter is ALL the page should display ALL Employees but if CompID Equal Specific ID it will Get only Employees for this Company to do that i am using two queries but i am sure that i can use only one query to get the same result
my Query String Parameter is :
String CompID = HttpUtility.UrlDecode(Request.QueryString["CompID"]);
The SQL Query to display ALL Employee is :
Query1 = "SELECT TbEmp.empID, TbEmp.fName, TbEmp.lName, TbEmp.email," +
" TbEmp.phoneNbr, TbEmp.compID, TbEmp.gender, " +
"TbEmp.address, TbComp.compName From TbEmp" +
" INNER JOIN TbComp on TbComp.compID = TbEmp.compID ORDER BY TbComp.compID"
The SQL Query to Display Employees for specific companie is :
Query2 = "SELECT TbEmp.empID, TbEmp.fName, TbEmp.lName, TbEmp.email," +
" TbEmp.phoneNbr, TbEmp.compID, TbEmp.gender, " +
"TbEmp.address, TbComp.compName From TbEmp" +
" INNER JOIN TbComp on TbComp.compID = TbEmp.compID WHERE TbEmp.compID = #CompID ORDER BY TbComp.compID DESC"
Can someone help me to merge those two queries in one query ?
The is a simple or-and case. Assuming your #CompID is numeric and you can send a zero to indicate the 'All' search...
INNER JOIN TbComp on TbComp.compID = TbEmp.compID
WHERE (#CompID = 0) or (#CompID <> 0 and TbEmp.compID = #CompID)
ORDER BY TbComp.compID DESC"
Although I would not suggest using queries to write your logic in asp.net (use stored procedures with parameters instead).
You can do this :
Solution 1 :
string Query1 = "SELECT TbEmp.empID, TbEmp.fName, TbEmp.lName, TbEmp.email," +
" TbEmp.phoneNbr, TbEmp.compID, TbEmp.gender, " +
"TbEmp.address, TbComp.compName From TbEmp" +
" INNER JOIN TbComp on TbComp.compID = TbEmp.compID " ;
String CompID = HttpUtility.UrlDecode(Request.QueryString["CompID"]);
if( CompID<>"")
{
Query1 += " WHERE TbEmp.compID = " + CompID //Beware : Chance of injection
}
Query1 +=" ORDER BY TbComp.compID";
Solution 2 : Assuming #CompID will be passed null if it is not there.
Query2 = "SELECT TbEmp.empID, TbEmp.fName, TbEmp.lName, TbEmp.email," +
" TbEmp.phoneNbr, TbEmp.compID, TbEmp.gender, " +
"TbEmp.address, TbComp.compName From TbEmp" +
" INNER JOIN TbComp on TbComp.compID = TbEmp.compID WHERE
TbEmp.compID = Isnull(#CompID, TbEmp.compID) ORDER BY TbComp.compID DESC"

Trying to pass parameters from asp.net when using a DECLARE statement but getting an error saying "Must declare the scalar variable "#pID"

I have a table called ReportValues that stores all the information about a player in key and value pairs. The table has a foreign key from another table called Reports. I'm trying to get all the data in one row for each report where the keys will be the column names and the values will populate the returned table. If I'm inserting the #pID manually and not as a parameter, then the code works, but when using parameter I get the following error: "Must declare the scalar variable "#pID". Here is my code:
public DataTable getBarChartData(int p_ID)
{
//this query is transposing rows into columns as each key gets a column and the grouping variable is RV.report
string sqlQuery = "DECLARE #keyName AS VARCHAR(MAX) ";
sqlQuery += "SELECT #keyName = ";
sqlQuery += "COALESCE(#keyName + ', ', '') + CAST(keyName AS VARCHAR(20)) ";
sqlQuery += "FROM(SELECT DISTINCT keyname FROM ReportValues) ActivePlayers ";
sqlQuery += "SELECT #keyName keyNames ";
sqlQuery += "DECLARE #DynamicPIVOT AS VARCHAR(MAX) ";
sqlQuery += "SELECT #DynamicPIVOT = 'SELECT ' + #keyName + ";
sqlQuery += "' FROM ( ";
sqlQuery += "SELECT RV.report, RV.keyname, RV.value FROM ReportValues RV ";
sqlQuery += "join ReportValues RV1 on RV.report = RV1.report ";
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = #pID and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
sqlQuery += "WHERE r.timeStamp >= dateadd(hour, -240, GETDATE()) ";
sqlQuery += ") ";
sqlQuery += ") ActivePlayers";
sqlQuery += "PIVOT(";
sqlQuery += "MAX(value) FOR keyname IN(' + #keyName + ') ";
sqlQuery += ") Result; ' ";
sqlQuery += "EXEC(#DynamicPIVOT) ";
int pID = p_ID;
//this passes the query and param to an execution function
DataTable dtLabels = GetBarChartDataByUser(sqlQuery, pID);
return dtLabels;
}
//this is the sql execution function
public DataTable GetBarChartDataByUser(string strQuery, int pID)
{
SqlConnection con = new SqlConnection(createConnectionReadOnly());
con.Open();
try
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = strQuery;
cmd.Parameters.AddWithValue("#pID", pID);
SqlDataAdapter dap = new SqlDataAdapter(cmd);
//here is where I get the error
DataSet ds = new DataSet();
dap.Fill(ds);
return ds.Tables[0];
}
catch (Exception ex)
{
}
finally
{
if (con.State == ConnectionState.Open)
{
con.Close();
}
}
return null;
}
"and RV2.value = #pID" is part of a dynamic string and is not treated as a variable in your dynamic string building query. In SQL Server variable scope only extends to currently executing batch or function and therefore the dynamicly built code executing inside "EXEC()" has no knowledge of variable #pID.
You can solve the problem in a few ways, one of them is below:
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = #pID and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
to
sqlQuery += "join ReportValues RV2 on RV.report = RV2.report ";
sqlQuery += "where RV1.value <> 1 and RV1.keyName = ''SessionStage'' and RV2.value = ' + CONVERT( VARCHAR, #pID ) + ' and RV2.keyName = ''PId'' and RV.report in ( ";
sqlQuery += "SELECT id FROM Reports r ";
(notice ' + #pID + ')
Another (I would argue a better way) is to replace:
"EXEC(#DynamicPIVOT) "
with
"EXEC sp_executesql #DynamicPIVOT, N'#pID INT', #pID "
Note: #DynamicPIVOT must be declared as NVARCHAR( MAX )
Note 2: declare #pID to be the same data type as RV2.keyName. This will avoid type conversions during query execution
To help with diagnosing similar problems in the future, I suggest you inspect the value of sqlQuery just before it is executed and paste it in SQL Management studio.
This will make it clear which parts are strings and which parts are SQL executable code.

nested select statements taking too long to load on SQL server

I have a page that displays reports on a grid. The grid uses an Object data source which is bound to a class that returns data. The class itself uses standard SQL query to return a count of records and binds to a dataview. The issue we are having is that it takes about 10 minutes sometimes to load and I know there has to be a better way but cannot for the life of me, figure out what. Hoping to get some insights from anyone on how to optimize this for performance. The data class is shown below: any feedback would be appreciated. There are about 650 attorneys returned by the attorney view which is bound to 2 tables: attorneys and locations table. The view on which the counts are performed on is bound to 2 tables also: current cases and previous cases tables and that returns about 125,000 cases total. Caching is out of the question because the end user will be able to supply any start and end dates to generate the report.
Dim PendingStringBuilder As String = "((dbo.cases.attorney_id = dbo.attorneys.att_id) AND (dbo.cases.date_assigned <= #StartDate) AND (dbo.cases.closing_date >= #StartDate OR dbo.cases.closing_date IS NULL)) OR ((dbo.casepreviousattorneys.attorney_id =
dbo.attorneys.att_id) AND (dbo.casepreviousattorneys.previous_assignment_date <= #StartDate) AND (dbo.casepreviousattorneys.unassignment_date >= #StartDate OR dbo.casepreviousattorneys.unassignment_date IS NULL))"
Dim AssignedStringBuilder As String = "((dbo.cases.attorney_id = dbo.attorneys.att_id) AND (dbo.cases.date_assigned >= #StartDate) AND (dbo.cases.date_assigned <= #EndDate)) OR ((dbo.casepreviousattorneys.attorney_id = dbo.attorneys.att_id) AND (dbo.casepreviousattorneys.previous_assignment_date
>= #StartDate) AND (dbo.casepreviousattorneys.previous_assignment_date <= #EndDate))"
Dim CountTable As String = " dbo.cases WITH (NOLOCK) INNER JOIN dbo.tlkpcasetype ON dbo.cases.case_type_id = dbo.tlkpcasetype.case_type_id FULL OUTER JOIN dbo.casepreviousattorneys ON dbo.cases.case_no = dbo.casepreviousattorneys.case_no"
Dim dt As New DataTable("ReportTable")
Dim dr As DataRow
dt.Columns.Add("CasesPending", Type.[GetType]("System.Int32"))
dt.Columns.Add("CasesAssigned", Type.[GetType]("System.Int32"))
dt.Columns.Add("ProbationViolation", Type.[GetType]("System.Int32"))
dt.Columns.Add("BailOnly", Type.[GetType]("System.Int32"))
dt.Columns.Add("TotalCases", Type.[GetType]("System.Int32"))
dt.Columns.Add("AttorneyID", Type.[GetType]("System.Int32"))
dt.Columns.Add("AttorneyName", Type.[GetType]("System.String"))
dt.Columns.Add("AttorneyFirstName", Type.[GetType]("System.String"))
dt.Columns.Add("AttorneyLastName", Type.[GetType]("System.String"))
dt.Columns.Add("UnitID", Type.[GetType]("System.Int32"))
dt.Columns.Add("UnitName", Type.[GetType]("System.String"))
dt.Columns.Add("UnitType", Type.[GetType]("System.String"))
dt.Columns.Add("OfficeID", Type.[GetType]("System.Int32"))
dt.Columns.Add("Office", Type.[GetType]("System.String"))
If cn.State = ConnectionState.Closed Then cn.Open()
Dim cmd As SqlCommand
Dim rdr As SqlDataReader
strSQL = "SELECT DISTINCT dbo.attorneys.user_id, dbo.attorneys.att_id AS AttorneyID, dbo.attorneys.first_name +' '+ dbo.attorneys.last_name AS AttorneyName, dbo.attorneys.unit_id AS UnitID, dbo.tlkpunit.unit AS UnitName, dbo.tlkpunit.unit_type AS UnitType,
dbo.tlkpunit.office_id AS OfficeID, dbo.tlkpoffice.office AS Office, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprCasesPending FROM " & CountTable & " WHERE (" & PendingStringBuilder & ")) As CasesPending, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprCasesAssigned FROM " & CountTable & " WHERE (dbo.tlkpcasetype.case_type <> 'Probation Violation') AND (dbo.tlkpcasetype.case_type <> 'Bail Only') AND (" & AssignedStringBuilder & ")) As CasesAssigned,
"
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprProbationViolation FROM " & CountTable & " WHERE (dbo.tlkpcasetype.case_type = 'Probation Violation') AND (" & AssignedStringBuilder & ")) As ProbationViolation, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprBailOnly FROM " & CountTable & " WHERE (dbo.tlkpcasetype.case_type = 'Bail Only') AND (" & AssignedStringBuilder & ")) As BailOnly, "
strSQL += "(SELECT COUNT(DISTINCT dbo.cases.case_no) AS ExprTotalCases FROM " & CountTable & " WHERE (" & AssignedStringBuilder & ")) As TotalCases "
strSQL += " FROM dbo.attorneys WITH (NOLOCK) LEFT OUTER JOIN dbo.tlkpunit ON dbo.attorneys.unit_id = dbo.tlkpunit.unit_id LEFT OUTER JOIN dbo.tlkpdivision ON dbo.tlkpunit.division_id = dbo.tlkpdivision.division_id LEFT OUTER JOIN dbo.tlkpoffice ON dbo.tlkpunit.office_id
= dbo.tlkpoffice.office_id WHERE (dbo.tlkpunit.unit <> 'test-unit') "
cmd = New SqlCommand(strSQL, cn)
cmd.Parameters.AddWithValue("#StartDate", DateAStart)
cmd.Parameters.AddWithValue("#EndDate", DateAEnd)
rdr = cmd.ExecuteReader()
While rdr.Read
If rdr("CasesPending").ToString = 0 And rdr("CasesAssigned") = 0 And rdr("ProbationViolation").ToString = 0 And rdr("BailOnly") = 0 Then
'Do not add record
Else
dr = dt.NewRow()
dr("CasesPending") = CInt(rdr("CasesPending"))
dr("CasesAssigned") = CInt(rdr("CasesAssigned"))
dr("ProbationViolation") = CInt(rdr("ProbationViolation"))
dr("BailOnly") = CInt(rdr("BailOnly"))
dr("TotalCases") = CInt(rdr("TotalCases"))
dr("AttorneyID") = rdr("AttorneyID")
dr("AttorneyName") = rdr("AttorneyName")
dr("UnitID") = rdr("UnitID")
dr("UnitName") = rdr("UnitName")
dr("UnitType") = rdr("UnitType")
dr("OfficeID") = rdr("OfficeID")
dr("Office") = rdr("Office")
dt.Rows.Add(dr)
End If
End While
rdr.Close()
cmd.Dispose()
If cn.State = ConnectionState.Open Then cn.Close()
Dim dv As New DataView(dt)
dv.Sort = "AttorneyName ASC"
Return dv
Read up on "sql execution plans" and you may want to review your table indexes. It is likely that these things will yield the greatest results. See this SQL Server Optimization MSDN article for more information.
I also notice in your VB code you are not parameterizing your SQL string. You should consider doing this after the above for additional performance benefit.
For more information on using SQL parameters see:
http://www.codinghorror.com/blog/2005/04/give-me-parameterized-sql-or-give-me-death.html
http://technet.microsoft.com/en-us/library/ms186219.aspx
Try using a stored procedure. This will have the code compiled in the Sql Server already and the execution plan stored ahead of time. John

Asp.net(c#) Custom Paging With Stored Procedure - Bad Performance During Pagination

I have a asp:GridView with datasource like List
I added custom paging, using a procedure, when i use the procedure in MS SERVER Management
Studio its performance is fast, as soon as i try it in asp.net, performance is awful during
pagination.
The 1st step (when the gridview fills) is very fast, but when i am starting to paginate,
the performance kills, i am waiting 5-25 seconds for passing to the next page.
Dear all, what must i do to solve this problem, will you help me ?
HERE IS THE STORED PROCEDURE
CREATE PROCEDURE [sp_QS]
#startRowIndex INT,
#maximumRows INT,
#afterWhere NVARCHAR(MAX),
#sortBy NVARCHAR(MAX),
#totalRows INT OUT
AS
SET NOCOUNT ON;
DECLARE #P NVARCHAR(MAX), #Q1 NVARCHAR(MAX), #Q2 NVARCHAR(MAX)
DECLARE #first_id INT
SET #startRowIndex = (#startRowIndex - 1) * #maximumRows
SET #Q1 = 'query part 1'
SET #Q2 = 'query part 2'
IF #startRowIndex = 0
BEGIN
SET #startRowIndex = 1
END
SET ROWCOUNT #startRowIndex
SET #P = 'SET NOCOUNT ON; DECLARE #out INT SELECT #out = id FROM table1 ' + #Q2 + '
WHERE ' + #afterWhere + ' SELECT #out'
IF OBJECT_ID('tempdb..#t1','u') IS NOT NULL
BEGIN
DROP TABLE #t1
END
CREATE TABLE #t1 (col INT)
INSERT #t1 EXEC(#P)
SELECT #first_id = col FROM #t1
DROP TABLE #t1
--SELECT #first_id AS FFFF --PRINT #first_id
SET ROWCOUNT #maximumRows
SET #P = 'SET NOCOUNT ON;' + 'SELECT ' + #Q1 + ' FROM table ' + #Q2 + ' WHERE (id >=' +
CAST(#first_id AS NVARCHAR(60)) + ') AND (' + #afterWhere + ') ' + #sortBy
EXEC(#P)
SET ROWCOUNT 0
-- GET THE TOTAL ROWS
IF #startRowIndex = 1
BEGIN
SET #P = 'SET NOCOUNT ON;' + 'SELECT COUNT(id) FROM table1 ' + #Q2 + ' WHERE ' +
#afterWhere
IF OBJECT_ID('tempdb..#t2','u') IS NOT NULL
BEGIN
DROP TABLE #t2
END
CREATE TABLE #t2 (col INT)
INSERT #t2 EXEC (#P)
SELECT #totalRows = col FROM #t2
DROP TABLE #t2
SELECT #totalRows AS QueryResultRowCount
END
GO
AND HERE IS THE CODE IN ASP.NET(WITH C#)
private void BindData()
{
string connectionString = "Server=localhost;" +
"Database=Northwind;Trusted_Connection=true";
SqlConnection myConnection = new SqlConnection(connectionString);
SqlCommand myCommand = new SqlCommand("usp_GetProducts",
myConnection);
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.AddWithValue("#startRowIndex",
currentPageNumber);
myCommand.Parameters.AddWithValue("#maximumRows", PAGE_SIZE);
myCommand.Parameters.Add("#totalRows", SqlDbType.Int, 4);
myCommand.Parameters["#totalRows"].Direction =
ParameterDirection.Output;
SqlDataReader sqlReader = myCommand.ExecuteReader();
while(sqlReader.Read())
{
// filling List<> object to bind to gridview as datasource
}
...
}
I have to buttons 'next' and 'prvious', pressing these buttons, i am changing
currentPageNumber with + or - 1, calling BindData() method after it.
Thanks in advance
That's an SQL against the AdventureWorks database from SQL Server 2005 samples:
DECLARE
#FirstRow int,
#LastRow int,
#Sorting varchar(50);
Declare #SelectClause nvarchar(max),
#Params nvarchar(MAX);
SELECT #FirstRow = 1, #LastRow = 10;
SELECT #SelectClause = 'WITH CTE AS (
SELECT
ROW_NUMBER() OVER ( ORDER BY ' + COALESCE(#Sorting, 'SalesOrderID ASC') + ' ) AS RowNumber,
COUNT(*) OVER() AS TotalRows,
SalesOrderID,
OrderDate,
DueDate,
CASE OnlineOrderFlag WHEN 1 THEN ''Yes'' ELSE ''No'' END as OnlineOrderFlagString
FROM
Sales.SalesOrderHeader
WHERE
SubTotal > 100)
SELECT * FROM CTE WHERE RowNumber >= #FirstRow AND RowNumber < #LastRow',
#Params = '#FirstRow int, #LastRow int';
exec sp_executesql
#statement = #SelectClause,
#params = #Params,
#FirstRow = #FirstRow,
#LastRow = #LastRow;
After you have execute query you can fetch total rows value from first row if exists. Note, that if you must provide ability to sort by computed columns like the OnlineOrderFlagString, the query will become bit more complex:
DECLARE
#FirstRow int,
#LastRow int,
#Sorting varchar(50);
Declare #SelectClause nvarchar(max),
#Params nvarchar(MAX);
SELECT #FirstRow = 1, #LastRow = 10, #Sorting = 'OnlineOrderFlagString ASC'
SELECT #SelectClause = 'WITH CTE_1 AS (
SELECT
SalesOrderID,
OrderDate,
DueDate,
CASE OnlineOrderFlag WHEN 1 THEN ''Yes'' ELSE ''No'' END as OnlineOrderFlagString
FROM
Sales.SalesOrderHeader
WHERE
SubTotal > 100),
CTE_2 AS (
SELECT
ROW_NUMBER() OVER ( ORDER BY ' + COALESCE(#Sorting, 'SalesOrderID ASC') + ' ) AS RowNumber,
COUNT(*) OVER() AS TotalRows,
SalesOrderID,
OrderDate,
DueDate,
OnlineOrderFlagString
FROM
CTE_1
)
SELECT * FROM CTE_2 WHERE RowNumber >= #FirstRow AND RowNumber < #LastRow',
#Params = '#FirstRow int, #LastRow int';
exec sp_executesql
#statement = #SelectClause,
#params = #Params,
#FirstRow = #FirstRow,
#LastRow = #LastRow;

Resources