Showing posts with label sql server. Show all posts
Showing posts with label sql server. Show all posts

Tuesday, October 13, 2009

Custom paging in Gridview With ObjectDataSource

Many times we use paging with GridView with AllowPaging = "True" and binding the GridView with some ObjectDataSource. It actually fetches all row from the database and depending on the no of records it fetched, it generates the Pager section of the page and according to the current page index, it shows the set of record.
This approach is good for when you have limited no of record in the database. But there are many situations where there is thousands of rows in the database and you have to display only 25 records(PageSize) out of that thousands of records. So it is not good practice to fetch all record through object datasource to display only 25 records.
Here we should use custom paging to fetch only the 25 rows starting from the startindex which is
CurrentPageIndex*PageSize (As Index is 0 Based).
Calculated automatically by objectdatasource.
Here is the change you have to do

  • Set EnablePaging="True" for ObjectDataSource

  • Set The SelectMethod Property

  • Set value for following Properties of ObjecDataSource StartRowIndexParameterName, SortParameterName, MaximumRowsParameterName
    These parameters needs to be present in the method attached for selecting the result for objectdatasource.

  • Set SelectCountMethod to the name of method returning the total no of rows.


Here is my ObjectDataSourceCode


<asp:objectdatasource id="objDS" runat="server" enablepaging="True" selectmethod="SearchResult" typename="PRP.BusinessLogic.TpilTblNsefaoscripmaster" startrowindexparametername="paramStartRowIndex" sortparametername="paramSortExpression" maximumrowsparametername="paramPageSize" selectcountmethod="GetNoOfRows">
<selectparameters>
<asp:parameter name="paramSymbol" type="String">
<asp:parameter direction="Output" name="paramTotalNoOfRows" type="Int32">
</asp:parameter>
</asp:parameter>
</selectparameters>
</asp:objectdatasource>


The SearchResult & GetNoOfRows Function


public DataTable SearchResult(string paramSymbol,
int paramStartRowIndex, int paramPageSize, string paramSortExpression, out int paramTotalNoOfRows)
{
TpilTblNsefaoscripmasterHelper.SearchResult(paramSymbol, paramStartRowIndex, paramStartRowIndex + paramPageSize, paramSortExpression, ref paramTotalNoOfRows);
this.totalNoOfRows = paramTotalNoOfRows;
}
int totalNoOfRows = 0;
public int GetNoOfRows(string paramSymbol,
int paramStartRowIndex, int paramPageSize, string paramSortExpression, out int paramTotalNoOfRows)
{
paramTotalNoOfRows = totalNoOfRows;
return totalNoOfRows;
}


The parameter list for both the functions are same but the second function retuns int no of rows. But i don't have used two function call for getting the total noofrows. Inside select function i have set the totalNoOfRows parameter which is accessed inside GetNoOfRows method to get the no of rows. This works as objectdatasource calls both the method on same object instance of the class and none of the methods and the class variable is static and the select methos is called first and then the row count method is called.
Now check the stored procedure used for this purpose


Create PROCEDURE [dbo].[USP_TPIL_tbl_NSEFAOScripSelectForSearch]
@Symbol varchar(50),
@StartIndex int = 0,
@EndIndex int =25,
@SortExpression varchar(50),
@TotalNoOfRows int OUTPUT
AS
SET NOCOUNT ON
Select * from
(
SELECT m.Instrument,m.Symbol,m.SymbolDescription,ExpiryDate,
Row_Number() OVER (Order By
CASE WHEN @SortExpression='EXPIRYDATE' OR @SortExpression='EXPIRYDATE ASC' THEN m.EXPIRYDATE END DESC,
CASE WHEN @SortExpression='EXPIRYDATE DESC' THEN m.EXPIRYDATE END ASC ,
CASE WHEN @SortExpression='SYMBOL' OR @SortExpression='SYMBOL ASC' THEN m.SYMBOL END DESC,
CASE WHEN @SortExpression='SYMBOL DESC' THEN m.SYMBOL END ASC
) as RowNumber
FROM
[dbo].[TPILl_NSEFAOScripMaster] m
WHERE
(m.[Symbol] LIKE @Symbol OR @Symbol = '')
)t
Where RowNumber>@StartIndex AND RowNumber<=@EndIndex --return SELECT @TotalNoOfRows = Count(*) FROM [dbo].[TPILl_NSEFAOScripMaster] m WHERE (m.[Symbol] LIKE @Symbol OR @Symbol = '')


As i am using Sql Server 2005, i used ROW_Number() function. The value of output parameter "TotalNoOfRows " is set to the variable "totalNoOfRows" inside "SearchResult" function.
To know about how to get Row Number in Sql Server 2000 please check the bottom of this link.

Friday, February 20, 2009

Paging in Datalist and Repeater

Datalist and Repeater doesn't provide any paging by default like gridview or datagrid. So we avoid using datagrid/repeater as much as possible. But there comes situation where using datalist or repeater is easier to maintain the design for the page. Like some product is displayed like row by row with 4 producs in a single w. There its tough to achieve (but not impossible) this design output wit datagrid/gridview. So we choose datalist making its RepeatColumns="4" RepeatDirection="Horizontal".
But paging???
So i created a control named as COUSPaging (Cous is my project name). Which contains two link buttons as "Next" and "Previous" and a textbox for goto page as below



In my control i used a public event "PageIndexChanging" which is of type GridViewPageEventHandler, so that it sends the same parameter as GridView. The event is handled from the Parent page containg the DataList.
The Paging.aspx Page Code:
<table>
<tr>
<td>
<asp:LinkButton ID="linkPrevious" CssClass="button" runat="server" Text="Previous" CommandName="Previous" OnClick="linkPrevious_Click"></asp:LinkButton>
</td>
<td>
<asp:Literal ID="litPageCount" runat="server"></asp:Literal>
<span id="spanGotpPage" runat="server">Goto Page:
<asp:TextBox Width="15" ID="txtPageNo" CssClass="inputfld" runat="server" MaxLength="3"></asp:TextBox>
<asp:Button ID="btnGo" runat="server" Text="Go" CssClass="button" OnClick="btnGo_Click" />
</span>
</td>
<td>
<asp:LinkButton ID="linkNext" CssClass="button" runat="server" Text="Next" CommandName="Next" OnClick="linkNext_Click"></asp:LinkButton>
</td>
</tr>
</table>

.Cs Page Coding:

void Controls_Paging_PreRender(object sender, EventArgs e)
{
litPageCount.Text = string.Format("{0} of {1} Pages ", SelectedPageIndex + 1, TotalNoOfPages);
if (SelectedPageIndex == TotalNoOfPages - 1)
{
linkNext.Enabled = false;
}
else
{
linkNext.Enabled = true;
}
if (SelectedPageIndex == 0)
{
linkPrevious.Enabled = false;
}
else
{
linkPrevious.Enabled = true;
}
txtPageNo.Text = (SelectedPageIndex + 1).ToString();
}
protected void btnGo_Click(object sender, EventArgs e)
{
int newPageIndex = 0;
try
{
newPageIndex = Convert.ToInt32(txtPageNo.Text) - 1;
if (newPageIndex > TotalNoOfPages - 1)
{
newPageIndex = TotalNoOfPages - 1;
}
if (newPageIndex < 0)
{
newPageIndex = 0;
}
SelectedPageIndex = newPageIndex;
PageIndexChanging(btnGo, new GridViewPageEventArgs(newPageIndex));
}
catch { }
}
public event GridViewPageEventHandler PageIndexChanging;
public int PageSize
{
set
{
ViewState["PageSize"] = value;
}
get
{
if (ViewState["PageSize"] is int)
return (int)ViewState["PageSize"];
else return 0;
}
}

public int CurrentPageIndex
{
set
{
ViewState["CurrentPageIndex"] = value;
}
private get
{
if (ViewState["CurrentPageIndex"] is int)
return (int)ViewState["CurrentPageIndex"];
else return 0;
}
}
public int StartIndex
{
get
{
return SelectedPageIndex * PageSize;
}
}

public int TotalNoOfPages
{
get
{
return (int)Math.Ceiling(TotalNoOfRows / (float)PageSize);
}
}
public long TotalNoOfRows
{
set
{
ViewState["TotalNoOfRows"] = value;
}
get
{
if (ViewState["TotalNoOfRows"] is long)
return (long)ViewState["TotalNoOfRows"];
else return 0;
}
}
public int SelectedPageIndex
{
set
{
ViewState["SelectedPageIndex"] = value;
}
get
{
if (ViewState["SelectedPageIndex"] is int)
return (int)ViewState["SelectedPageIndex"];
else return 0;
}
}
protected void linkNext_Click(object sender, EventArgs e)
{
if (SelectedPageIndex < TotalNoOfPages)
{
SelectedPageIndex = SelectedPageIndex + 1;
PageIndexChanging(sender, new GridViewPageEventArgs(SelectedPageIndex));
}
}
protected void linkPrevious_Click(object sender, EventArgs e)
{
if (SelectedPageIndex > 0)
{
SelectedPageIndex = SelectedPageIndex - 1;
PageIndexChanging(sender, new GridViewPageEventArgs(SelectedPageIndex));
}
}

The page where the control is used

Here the page size is initialized. From the cs page call the bind datalist function as

void bindDataList()
{
long totalNoOfRows;
ImageTblMasterTable dtImage = ImageTblMaster.SelectAll(-1, 1, pagingDL.StartIndex, pagingDL.PageSize, out totalNoOfRows);
pagingDL.TotalNoOfRows = totalNoOfRows;
dlImage.DataSource = dtImage;
dlImage.DataBind();
}

Here i am using custom paging. So i am sending the page start index and page size which is converted to ennIndex before the call to SP. Here is code from SP

Select @TotalNoOfRows = Count(*) FROM [dbo].[Image_tbl_Master]

Select * from
(
SELECT ROW_NUMBER() OVER (ORDER BY ImageId) as RowNumber, m.* FROM [dbo].[Image_tbl_Master] as m
)t Where
RowNumber >= @StartIndex
AND
RowNumber <= @EndIndex As i am using SQL Server 2005 i get the facility of ROW_Number() but in SQL Server 2000 or before, there is no row number. So you have to change the query like Select * from ( Select (Select Count(*) from Image_tbl_Master where ImageId<=img.ImageId )as RowNumber, img.* from Image_tbl_Master as img )t Where RowNumber >= @StartIndex
AND
RowNumber <= @EndIndex

Here row number is calculated on the fly through a subquery. See the where clause "ImageId<=img.ImageId ", it is responsible for the sorting. As i was sorting with ImageId i have used it like that.

Thursday, September 18, 2008

Run aggregate on datatable column

I had one table with columns "Name" and "Department" which i need to display in a multiline textbox. like below
Name~~~~~~~~ Dept
Tarun Ghosh~~~SWD
Diptangshu Das~SSWD
So that the names and Dept are aligned properly. So i needed the Max of the string length of the column "Name" and give a right-padding to name to make all of same length with the maximum lengthed name.
Firstly i went with the primitive looping through each record and calculate the max of the row, if it is greater than the global max, set global max to current max algo...
But i was not satisfied with the approach even though no problem.
Then i got the
public Object Compute(
string expression,
string filter
)
function of DataTable. Expression par needs to be some aggregate function lik Sum, Avg,Min,Max,Count,Var. with filter expression is same as where clause in dt.Select() function.
But one problemmmmmmmm.... The expression parameter can't work on computed column. Like say you have two column qty and unit price. You need to get the max(qty*unitPrice), then first you have to add a new column to hold the value of the multiplied result and then use the compute function on that column.
So in my case i wanted to get the max of length. So i added a column as

DataColumn col = new DataColumn("Length");
col.Expression = "Len(Name)";
col.DataType = typeof(int);
dt.Columns.Add(col);
object obj= dt.Compute("Max(Length)","");
Response.Write(obj.ToString());

obj is storing the max length value
Some useful link
Link1
Link2

Wednesday, September 17, 2008

Get the date diference in the form of x Years y months z days

Somethimes we need to get the difference of two dates in SQL server to send the result to front end. The result of DateDiff SQL function will give the difference of the date for a particular part like year or month or day... If you think of just concatinating the results got from three datediff function with parameters for year,month and day, you will get the wrong result. WHY???
DateDiff(Year,'2007/31/12','2008/1/1') is 1 though the difference only 1 day.
Similarly month differnce and day difference will be shown as 1.
So the result age is "1 year 1 month 1 day". But actyually only "1 day".
Here is a function i wrote to get the exact value. This is very useful when you need to get the age on today when you have DOB stored in your database. Here you have to send the DOB as @startdate and GetDate() as @endDate

Create FUNCTION [dbo].[fn_GetDateDifference] (@startDate as DateTime,@endDate DateTime)
RETURNS varchar(50) AS
BEGIN
DECLARE @res varchar(50)
DECLARE @mon int,@year int,@day int
SELECT @year = DateDiff(year,@startDate,@endDate)
--SET @year = @day/365
SET @startDate = DateAdd(Year,@Year,@startDate)
if(@startDate > @endDate) --If the month value of Start Date is more than that of End Date
--@startDate can become more than date 2 if the values are like
--@startDate = '2007/12/15' and @endDate = '2008/02/01',
--The datediff year will be 1 though only 2 month+ difference
BEGIN
SET @year = @year - 1
SET @startDate = DateAdd(Year,-1,@startDate)
END
SELECT @mon = DateDiff(Month,@startDate,@endDate)
--SET @mon = @day/28
--Select @mon = DateDiff(Month,@startDate,@endDate)
SET @startDate = DateAdd(Month,@mon,@startDate)
if(@startDate > @endDate)
--Same as year,month can show maximum of 1 unit more if the start date "Day" val in more than end date "Day value"
BEGIN
set @startDate = DateAdd(Month,-1,@startDate)
set @mon = @mon - 1
END
SELECT @day = DateDiff(Day,@startDate,@endDate)
set @res = ''
If(@year > 0)
SELECT @res = Cast(@year as Varchar(10)) + ' Year(s) '
if( @year>0 or @mon>0)
Set @res = @res + Cast(@mon as Varchar(10)) + ' Month(s) '

set @res = @res + Cast(@day as Varchar(10)) + ' Day(s)'
--set @res = @year & ' '
--select @res = @year & ' ' & @mon & ' ' &@day
RETURN @res
END

Note: It is not a good practice to use backend sqlserver for this kind of calculations. It is preferable to return two dates to front end and then do the desired calculations.

Monday, July 14, 2008

Generate Your Dynamic Report Through Reporting Service

I have posted some articles on reporting service. Here is a sample project which will generate report dynamically. It is having an interface where you select the database in a DDL then a table or view from the selected DB and select some columns for details and group of the report. Then it will generate the report RDL and publish it to your report server. If you want to select from multiple tables with joining, you can do that also by giving your custom query.
Here are some setting which you will have to change to run the project like
string serverName = "localhost"; //The server where the report will be published.
string reportVirtualPath = "LocalReportServer"; //The virual directory path of the reportserver
string parentFolder = "QuoteReports"; //The folder where the reports will be published.
Here i am using some AppSettings val in web.config. Change those according your local settings. But in "MasterConStr" the 'Initial Catalog' value should be 'master' because this connection string is used for fetching data about DBs.
Add the web reference of the reporting service to your ptoject. You may have to change the "RSLocal.ReportService2005" AppSettings value.
Here is the link of the project http://w17.easy-share.com/1700907813.html
Here i am using sql express repoting service and my report server and database is in dame machine. If you have the Report server installed in other machine than the Database you may have some problem with the DataSource. For that pls refer to my other post Use stored credential for report created by c# code.

Thursday, May 29, 2008

Reporting service: Dynamic Toggle Group

In my current project i have to use Reporting Service 2005 for generating some reports. It was the first time for me to RS. The report was showing some group on Year >> Month >> Day. The report was drill down one. I had to show the current month's days open i.e when the user open the report which is decending sorted with year,month,day will show the report with current mont's days expanded. All other years and month will remain collapsed.
For that i added two parameter to my report through
Report Layout (Designer)-> Report (Menu) -> Report Parameters(sub menu).
The parameters are showYear of type int and showMonth of type int.
Default value for showYear, i selected "non-queried" and in the textbox wrote =Year(Today)
and same for showMonth with TB value =Month(Today) so that the default value is set to the current month and year.
Now i edit the group showing the month and in the visibility tab i set "Initial Visibility" expression to "=IIF(Parameters!showYear.Value=Fields!Year.Value,false,true)", so that if the yeay is equals to current year then it will stay initially visible. And for day i set expression to "=IIF(Parameters!showYear.Value=Fields!Year.Value,IIF(Parameters!showMonth.Value=Fields!Month.Value, false,true),false)", so that if the month and year is euals to current then it will be stay initially visible (i kept the "Visibility can be toogled by another report item" section as it was.).
Now when i preview the report i found everything is running fine. By default it is expanding current year and month and if i put some other value in the report changing textbox it is expanding corresponding record. But the "+" and "-" signgs for toogle for those initially expanded is showing opposite i.e. "+" even when initially it is expanded and "-" when clicked to collapse.
Why this is happening? After searching various properies for the report and its item i got the "InitialToogleState" property of the textbox which by default is collapsed. Then i set this property to expression so that it is "Collapsed" and "Expanded" properly to show "+" and "-" sign respectively.
I set the year textbox's (TB which is responsible for toggle in year group row) InitialToogleState property to "=IIF(Parameters!showYear.Value=Fields!Year.Value,true,false)" and for month's one "=IIF(Parameters!showYear.Value=Fields!Year.Value,IIF(Parameters!showMonth.Value=Fields!Month.Value, true,false),true)" . Then i saw the result was as desired.
We can hide the Parameter Promt in the report viewer by ShowParameterPrompts="False" in the reportviewer control and send the parameter by querystring as 'showYear=2004&showMonth=5' .
Some points to note:
1) "InitialToogleState" property is boolean. "Collapsed" indicates false and "Expanded" true
2) "Initial Visibility" is set to month and day rows where as "InitialToogleState" is set for year and month TB.


One useful link:http://msdn.microsoft.com/en-us/library/aa337391.aspx

Wednesday, April 16, 2008

Problem Numeric check in SQL Server

In my datase i had a table which contains both numeric and characters and the table datatype was Varchar, and i have to find the min of the of the numeric value. In sql server the function ISNUMERIC(expr) was the solution to get rid of the character value.
The ISNUMERIC function determines whether an expression is a valid numeric type. returns 1 when the input expression evaluates to a valid numeric data type; otherwise it returns 0. So i used the query like below
Select min(ColName) from demo where ISNUMERIC(ColName)=1
And i was getting my desired value.
But one day it started an exception in my asp.net page. And i could not find the reason.
After a long debugging i found that it was the problem with ISNUMERIC function of sql server. The ISNUMERIC function is returning 1 for some non-numeric character like '-' i.e
Select Isnumeric('-') returns 1 not 0.
And it was returning '-' from the query and error in asp.net page.
Then i tried with casting the result to int as.
Select Cast(min(ColName) as int) from demo where ISNUMERIC(ColName)=1
And in this way the error was solved but the min value was always 0 as Cast('-')=0
Then i identified this abnormal characters as excluded them through the where clause.
Select Cast(min(ColName) as int) from demo where ISNUMERIC(ColName)=1 and eadr not in('+','-','$').
This behaviour occurs for these three charactes('+','-','$') i have found so far.
For more information check this link

Wednesday, February 6, 2008

How to view all triggers

To view the trigger from a particular database Table
exec sp_helpTrigger @tabname='QTQuotationMaster'

If you want to see all the triggers available in the database then run this
SQL Server 2000:
select * from sysobjects where xtype ='TR'

SQL Server 2005:
Select * from sys.triggers

Wednesday, October 24, 2007

Using text, ntext Data Type SQL Server

In sql server 2000 (or before ver) we uses Text,NText data type for storing very long length of string datatype. Text is suitable for non-unicode (1 byte) string and NText for unicode(2 bytes). we can't manipulate these datatype with the regular dmls, but it requires some other way because of it's storing process which is different from other data types (except Image which is stored in the same way for binary data). These datatypes's values are stored outside the row and a 16 bit pointer is tored which points to the root of the internal pointer which points the fragment of the data stored in different pages.
We need to use READTEXT (to read), WRITETEXT ( to replace ) and UPDATETEXT (to modify) these values.
First create a table and insert some values in it
CREATE TABLE TestNTextDataType ( [Id] [int] NULL , [Name] [Ntext] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
insert into TestNTextDataType values(1,'This is a test')
insert into TestNTextDataType values(2,'This is second test')

Declare a pointer to the 'Name' Column as
Declare @ptrToCol varbinary(16)
Select @ptrToCol=TextPtr([Name]) from TestNTextDataType where [Id]=1

The @ptrToCol pointer points to the NText value 'This is a test'.

READTEXT { table.columnName @ptrToCol @offset @size } [ HOLDLOCK ]
Reads values from a column, starting from a specified offset and reading the specified number of bytes.
READTEXT TestNTextDataType.[Name] @ptrToCol 5 2
Result: is
The value of offset is 5 and as it is zero based it points to the 6th character 'i' and the length is 2 so the two characters starting from 'i' is returned. If you pass 0 as the size then 4KB of data is read.
Read More

WRITETEXT { table.columnName @ptrToCol } [ WITH LOG ] { data }
Permits minimally logged, interactive updating of an existing column. WRITETEXT overwrites any existing data in the column it affects
WRITETEXT TestNTextDataType.[Name] @ptrToCol 'Updated Test Final'
It will update the 'This is a test' value to the new value 'Updated Test Final'. Remember that the pointer @ptrToCol points to the [Name] column of the row with the id=1 (Where clause).
Read More

UPDATETEXTUPDATETEXT { table.columnName @ptrToCol } { NULL @insertOffset } { NULL @deleteLength } [ WITH LOG ] [ inserted_data]
Updates an existing field. Use UPDATETEXT to change only a part of a text, ntext, or image column in place.
UPDATETEXT TestNTextDataType.[Name] @ptrToCol 8 4 'New String'
Previous value was 'Updated Test Final' insert offset 8 points to 'T' of Test and the delete length 4 deletes the 'Test' and inserts the value 'New String'. So the result value becomes 'Updated New String Final'.
Read More

DataLength(Expression)
To get the length of the column value for Text,NText and Image datatype you have to use DataLength function.
Select DataLength([Name]) Length from TestNTextDataType where [Id]=1
will return 48 as the length of 'Updated New String Final' string because the datatype is NText of the column so every charter will take 2 byte and there are 24 characters. If the datatype was Text then it will return 24. The DATALENGTH of NULL is NULL.

PATINDEX , SET TEXTSIZE, SUBSTRING, TEXTVALID are use useful functions to work with these datatypes.
Note: ntext, text, and image data types will be removed in a future version of Microsoft SQL Server. Avoid using these data types.