Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Articles
Search: 

VFP Grids, Part III
Vlad Grynchyshyn, October 1, 2001
In this part, I will discuss about grid sorting by header click, grid sorting marker (indicator) and resizing of grid column by double click to the width of data. As usual, I have included some tips and warnings. Grid sorting by header click Last time, sorting of information by a click on...
In this part, I will discuss about grid sorting by header click, grid sorting marker (indicator) and resizing of grid column by double click to the width of data. As usual, I have included some tips and warnings.

Grid sorting by header click

Last time, sorting of information by a click on the header is popular in the lists and grids. This feature is very useful to search something among the hundreds of rows in the list. VFP grid does not have such feature built-in, however, as usual, it could be programmed.

There are a lot of approaches exists to organize this. We will not cover all of them, but just will describe the most generic approach that is useful to build a grid class with sorting capabilities. This means described approach could be used in any other case by cutting off too complex and useless parts from it. It is recommended to make this feature as a part of your grid class in the application so you will be able to re-use it in many other applications.

First of all, prepare a Click event of the header to fire sorting at the correct moment. Click event also fired when column moved or resized, so you will need to use something similar to what was described in the VFP Grids Part II article in previous release of UT magazine - make header class that will track resizing and moving of the column to separate just a pure click on the header. Of course, this will require all other things in the grid to support and maintain the replacing of default grid headers by new header class. This is needed anyway, if you want to use sorting feature for any grid. When column is resizable, click on the resizing area without resizing of column should be caught too - it is not good idea to sort column when mouse cursor is the resizing arrows, this will confuse users (as well as we hold this for another functionality described in the chapter 3. of this article). The resizing area of grid header is 11 pixels wide (6 pixels to left from the line between headers and 4 pixels to right from the header right edge). When you click on the resizing area without resizing, even when mouse is over the next header, mouse and click events are fired only for header that resizable by that resizing area. In the sample you can see how it is tracked in the header class - by MouseUp event we get the coordinates of the mouse pointer during and check if it was just a single click on the resizing area. If yes, set special flag so in the Click and DblClick events we can check if mouse is not in the resizing area.

Once pure click separated from all other actions, do the sorting. It consists of three parts - sorting manager, sorting routine and refreshing of grid after sorting.

Sorting manager tracks which column is currently sorted, define properties for sorting and holds a current state of the sorting. To do this, following properties are used:

  • Grid.SortedColumn - contains index of the current sorted column or zero if no column sorted. Index will be used to quickly track what column was last sorted and switch sorting off for that column when another column is clicked for sorting (though this is not required - index of sorted column could be determined in a simple loop through all columns and check for SortingState property value).

  • Grid.lAllowSorting - by default .T. - to allow disable sorting for the entire grid.

  • header.lAllowSorting - by default .T. - to allow disable sorting for this column.

  • Header.SortingState - 0 - not sorted, 1 - sorted in ascending order, 2 - sorted in descending order. Sorting manager will roll over these values and call the sorting routine if needed.

  • Header.DefaultSorting - this property determines what sorting order will be first when header is clicked. For example, preferred sorting order for dates is usually descending by default, so you might want to change this property to 2 from default value 1 - this will change the order of sorting from {not sorted}->{ascending}->{descending} to {not sorted}->{descending}->{ascending}.
  • Header.lEventSwitchOffSorting - an event-like property to switch off sorting and drop all extra indexes if any for a duration of certain process for which sorting will cause slow down or errors. This will be used by calling Grid.SetAll("lEventSwitchOffSorting",.T.) command and caught by _Assign method for this property in the header. This property will be also required in the grid class for case if SetAll function called when headers of grid are not prepared yet (otherwise when no any control with such property found, VFP sometimes throw error).

In the most complex case columns could be removed from the grid, so SortedColumn property might require updating after such process. For such case, it is recommended to have a method in the grid to scan all columns and update the SortedColumn value properly by index of the column, which contains non-zero sorting state. Well, you can organize another way to track the index of column that is currently sorted - by using a simple loop that returns index of currently sorted column.

Sorting routine is the main part of this feature. There are several ways to organize sorted data in the grid: - Store data in the array and show array content in the grid, sort array using asort() function. This way somewhat slower and number of records is limited to maximum number of array elements. - Re-query the view or SQL Pass-Through result set with another option for sorting. Slow for large data sets, however, the most easily to organize sorting by multiple columns. - Use indexes for the result set created on the fly or use existing indexes. This approach is the most quick because it does not store any intermediate result in the memory and does not require query of data from server again, but it require some programming.

In this article we will discuss only approach with use of indexes. Other approaches could be adapted hereby easy way by replacing the way data set is sorted in the sorting routine, and the way grid is refreshed after sorting.

In the sorting routine following properties are used:

  • private Header.CurrentTag - this will store a tag name used for sorting by this column.

  • Header.SortingExpression - when this property is not empty, expression in it will be used for indexing. When it is empty, sorting routine will build the expression using the ControlSource expression of the column enclosed into the certain functions to make indexing process more reliable.

  • Header.SortingTag - If this property is not empty, index tag name in this property will be used with assumption it is already exists in the record source for this grid. Why create a new index tag on the fly when index for this field already exists?

Last two properties give more options for programming of sorting. For example, when grid contain 2 columns First Name and Last Name, it is good idea to sort data by First Name + Last Name no matter which of these two columns are clicked. Of course, it might require additional sorting indicator and programming, so better leave this property for case when default sorting routine is not capable to sort column properly. We will discuss multiple columns sorting later.

Sorting routine check if SortignTag or CurrentTag properties are not empty, and use these tags for sorting. CurrentTag is not cleared till the end of the header object life, or till the special situation occurred that require deleting of this temporary tag (this is done by setting the property lEventSwitchOffSorting to .T.). This is some sort of reusability - we create index only once (this can take some time), store tag name of created index in this property, and then just re-use it to do not spend time for indexing next time. When CurrentTag property is empty, routine will create an index tag for the record source and store tag name in this property.

When expression for indexing is specified, routine will just use it without any verification (though basic error-tracking could be done anyway). Otherwise sorting routine will attempt to build the expression with checking of all circumstances, include NULL values and SET COLLATE settings. Remember that maximum index expression length is 240, but it is dropped to 120 with SET COLLATE setting is set to something other than "MACHINE". Index does not accepts NULL values, so we add NVL() function to assure no null values appear in the result set. For long character and memo fields we use PADR() function. Finally, when ControlSource value contains expression, not the field, we use PADR() for character values anyway to assure length of the expression result is always the same. Of course, we cannot sort by fields of General type. There is also a big difference for indexing for different record sources. For views, cursors and SQL Pass-Through cursors we can create structural index tag without any problem, because the file with these tags will be deleted from the disk automatically as soon as record source is closed. However, view with table buffering could not be indexed by INDEX command. We can quickly switch to the row buffering temporarily, index the view, then set buffering to table buffering again. However, changing of the buffering mode cause error if view contains uncommitted changes. Well, you can tell user that grid on that form could not be sorted when data changed, or just prepare indexes just after view opening and specify prepared index tags in the SortingTag property of each header, then set buffering mode to table buffering.

It is bad idea to create structural index tag for a table, because expression in ControlSource could contain reference to other fields and even to related tables, so other user that will open that table after our indexing could have errors because that. In addition, creating of structural index require exclusive access rights to that table. For such case we use non-structural index tags stored in the temporary CDX file with the same name as a tag name. This creates some other potential problems. "BEGIN TRANSACTION" command cannot start transaction in the data session that contains alias with opened non-structural index. Before this command you require to close all non-structural indexes. Really, it is better to do not show user entire data set with tens of thousands of records. Prepare a filter condition and select into the grid only little subsets of the data from large table. This will work much more quickly, and no problems with direct access to table, like problem with non-structural index tags in this case. In addition, indexing of the large table accessed through network is quite slow. Anyway, in case you require sorting for table, try to use for sorting as many existing index tags in the table as possible, and then switch off sorting for columns that have no existing index tag in the table. Another solution - before transaction starting, use Grid.SetAll("lEventSwitchOffSorting",.T.) so grid will delete non-structural index tags if any. This will require special attention for transactions in the child forms called from the form with such grid.

When record source contains more than 1000 records, we display the message using the DispSortingMessage method of the header, that by default show a simple "WAIT WINDOW" message for duration of the sorting. You might want to prepare the progress bar to display a progress of indexing or some other way to indicate the indexing (sorting) in progress. In addition, it is possible to display sorting progress by using custom function call inside of the index expression: function will be called for each indexed record, code in function update graphical progress bar (speed of indexing will be worse in such case).

Speed of sorting is amazing when sorting this way view, cursor or SQL Pass-Through cursor. Sorting of the table is quick when table is on the local disk, but usually it is slow because access to database and its tables through network. The result cursor of the VFP SELECT statement could be sorted too. However, use NOFILTER option for result set, otherwise indexing might be slow because direct access to the table through network (as well as use of non-structural indexes is not a good idea, as already described).

After sorting, we require to refresh grid properly. There are situations when changing of sorting direction can cause strange effects with grid rows appearance. For example, sort grid in ascending order, put record at first record in the current sorting order, and then sort again in descending order. Usually grid after this show only single row - the last row in descending sorting order, and empty space below it. User anytime can use scrollbar to return grid to good-looking state, however, the strangest thing is that grid often show this behavior when all rows in the record source fit into the visible area of grid. Imagine situation when you see all rows from data source in grid, click sorting, and then you see only one row... This usually confuse user - why grid is scrolled when all records could be visible at once? To fix this behavior of grid, we use one extra refreshing of grid by setting record to the first record in current sorting order, then set it back to the current record. This assures record is centered in the current visible area of grid or all rows are shown in grid when all rows fit into the visible area. This also could be improved even more - when record at the end of the record source in new sorting order, show last records by such way that there are as little space left without records at bottom of grid as possible. To do this, in case record is at bottom of grid, move record pointer to top, move it back to current record minus half of the number of records that fit in current visible area of grid, then set record pointer back to the required record. Note that this is useful only when record pointer is currently in the few last records. Moving record pointer back and forth could be slow for certain record sources, specially with large number of record or filter set for record source, so this is not a good idea for a generic case.

Above approach is good for sorting only by one column. In case you want to organize multi-column sorting, you will require collecting all sorting expressions from columns that are currently joined to sorting by multiple columns, and that have sorting state not zero. This is required to do even in case user switch off sorting for this particular column to keep other columns sorted correctly. Re-use of existing index tag is very hard to organize in such case, because single column use several sorting expressions now. Usually this requires converting of all expressions to the character type and cut them by limitation of 240 characters (or even 120 character when collating sequence is used). In addition, it is hard to organize sorting expression by such way that one column is sorted in ascending order and another - in descending. It requires to inverse the value of expression for the column with descending order. Inversing is different for different data types. For example, numeric values are easy to invert just by using the "-" sign operator. In our case we will work only with character values. In such case we need to change "A" to "z" and vise versa. You can use chrtran() function to do this quickly with use of 2 prepared strings. For example:

"Control" > "Binding" 
chrtran("Control", cAllChars, cAllReverseChars) < chrtran("Binding", cAllChars, cAllReverseChars)

cAllChars and cAllReverseChars are prepared by following way:

cAllChars = ""
cAllReverseChars = ""
for nCharIndex = 0 to 255
  cAllChars = cAllChars + chr(nCharIndex)
  cAllReverseChars  =cAllReverseChars + chr(255-nCharIndex)
endfor
So, for example, index expression for 2 columns with Last name and First Name, when data sorted by Last Name in ascending order and by First Name in descending order, will look like following:
NVL(LastName,space(35)) + chrtran(NVL(FirstName,space(35)), cAllChars, cAllReverseChars)
In case collating sequence is used, the problem even more complex. The order of characters do not match to the order of character codes, so strings cAllChars and cAllReverseChars will look by different way. To prepare them, create a table with 1 character column and fill it by all characters. Index this table with use of required collating sequence, the read all characters into these strings using ordered table - this will assure all characters in these strings are in correct order. When string character is not a single byte, these strings become too long to use them in the index expression because significant slow down in chrtranC() function. Well, sorting by different order direction is possible by very simple way when using views or query statements for sorting - ORDER BY clause of the SELECT statement allows specifying of the sorting direction for each sorting element.

There are few different models of sorting by multiple columns.

  • Common sorting across all columns, for example, First Name + Last Name - sorting one column cuse sorting by all columns in group

  • Fixed: click on the column sorts it. Click on the second column adds sorting to the first sorting. After that two clicks on the first column can leave only second column sorted.

  • Cascade: 2 or more columns are joined in the sorting, when one (main) is sorted, second could be sorted together with main column, when main column is not sorted, clicking on second column cause main column is sorted automatically. In case of three columns third column click cause sorting of second and first (main) automatically. Sometimes complex models allow having more than one secondary column.

  • Dynamic: like fixed, but all columns are joined into a single sorting process, so user can organize any combination of sorting columns.
This could be organized by using additional header properties like "cMultipleSortingColumns" that store a list of column indexes used for joined sorting, as well as cascade sorting model will require to define also column dependencies for sorting (priority order number - which column is main in the sorting, which is secondary etc.). For dynamic sorting no additional property is required, just another management of sorting.

Multi-column sorting also requires special approach for displaying sorting indicators. In such case this require to maintain as many controls as could be displayed at once to indicate sorting for all colum,nd currently sorted. For dynamic sorting the number of indicators will match to the number of the columns in grid that could be sorted.

In the sample there is no such complex thing as multiple-column sorting, however, you can see most of the things discussed here for sorting.

Grid sorting marker (indicator)

There are many ways to show user that certain column of the grid is sorted. The simplest approach is to change the background or foreground color of the header caption, or add a special arrow-like character to the header caption to indicate sorting (usually characters "^" and "v". This does look acceptable but not very good. It is possible to use a separate control to indicate sorting, but this is not an easy task. Well, putting the arrow-like control above the grid just above the header caption is as easy task as putting of the control over the grid cell - all rules apply here too (see VFP Grids Part II article in previous Universal Thread Magazine). However, in many applications you can see a little arrow inside of the header. In VFP it is hard to organize such thing and this require some workarounds. There are two approaches.

First is to use a separate window defined by the command "DEFINE WINDOW ... IN WINDOW ... NAME ..." and changing that window shape by using Windows API function SetWindowRgn() to make it look like an arrow, and even show something under arrow imitating the raise or sunken effect using a set of colored lines. The second approach is putting a usual transparent contianer control over the grid and using a set of lines to organize arrow. Instead of the control with lines simple drawing on the form could be used to draw the lines over the header using form methods for graphics, but this require even more effort for refreshing such sorting indication.

The problem with putting something over the grid header is very frustrating - grid header redraw self always above any other VFP control despite you just used ZOrder method to put your control to top to cover all other controls. There are reports that this behavior does not appear when running VFP application on W2K system; under Windows NT it always appear. Grid header will draw self over other controls as soon as certain events occur that cause header refresh. Following is a list of such events and events that require to refresh the sorting indicator:

  • Headers click (in any case) and right click (strange, but indeed grid header move self above any other control when right-clicked).

  • Grid refresh() method call

  • Change of current cell (AfterRowColChange event)

  • Grid move or resize or grid header is move or resize

  • Grid scrolling

  • Header height change (catch this in the MouseUp event of the grid)

  • Grid losing focus - put grid into container to catch this moment

Well, all these things, as you can see, could be caught by a simple way except the last one. Losing of focus for grid do not cause any grid event firing after grid headers refreshed. This could be caught by putting grid inside of the container, that is not good for certain cases, specially for generic grid class.

Windowed indicator is good unless it cause no conflicts for modal windows. In some cases another window defined by "DEFINE WINDOW ... IN WINDOW" command inside of the modal VFP form can cause a lot of side effects. Specially frustrating that such window does not fire any events and does not function properly by mouse clicks (it would be good to forward mouse clicks from sorting indicator to the grid header). For modeless forms such window gets focus, that also bad thing because a lot of events firing and this require special workarounds. To refresh sorting indicator from several places in code, separate grid class method is used. Refreshing calculates the correct position of indicator and places it. It contains method to refresh the indicator - to indicate different sorting directions, and set colors for arrow properly to the background color of the header. The coloring algorithm uses a color brightness distribution percentage to organize shadowed lines to simulate the raise effect. It also assure that arrow is visible anyway on the very bright or dark header background.

It is good idea to use the indicator control only in the run-time. In the Grid it is created in the Init event and destroyed it in the Destroy event of the grid. For multi-column sorting you probably will require an array, which contains references to all indicator controls created for sorted columns, or even create indicator for each column by storing reference to it in the header.

Resizing of grid column by double click to the width of data

You can see a useful feature in the applications with grids or lists - double click on the resizing area of the column header resize column automatically to the width of the information in that column. In the sample you can see in the header DblClick and MouseUp events how we separate double click on the header resizing area from all other events. This fires the auto-resizing algorithm. It gets the field size from the control source, and calculate the width of the column in pixels using TxtWidth() function for character 'O' (a character with average width) replicated to number of that field size in characters. Certain fields like memo field and fields with long space for characters usually contain a lot of extra space that is not used completely. In addition, expression could be used in the COntrolSource of the column that gives no idea about maximum number of characters displayed. It is good idea to do not expand column to the maximum size, just show the information by as good as possible way - to fit most rows information and do not take much space by the column. For such case algorithm scans records around current record position and calculate maximum value of the TxtWidth() function return for result of the expression. That will become a width of the column. However, if all rows around current record contain empty value, it is good idea to specify the default column width, for example, in the DefaultWidth property of header (that could be used also in some other cases).

Grid tips

You can show anything in the grid cell by using the container control. To refresh container accordingly to each row data, in the expression in the Dynamic* property you can use function call. Function will be called for each grid row, so in code inside this function you will be able to change anything in container and refresh it for that row. During such function call record pointer in the record source is at the appropriate record.

To make header caption multi-line, in VFP7 use WordWrap property of the header. In VFP6 multi-line headers could be made using either labels over header, or container controls that simulate grid headers (there are downloads for this in the Universal thread Downloads section).

To show tool tips for different parts of the grid, show your own control in the timer event that checks if mouse is not moved for certain time using MROW() and MCOL() function. The part of the grid could be determined using GridHitTest method of the grid. (Multiline/Fancy ToolTip Control working that way, you can modify it for this purpose; it is located in the Downloads section at the Universal thread site.)

Grid warnings

Do not use grid column control's "Value" property for calculations. To get data for calculations, do direct access to the grid alias data instead. This is because control in the inactive column is usually used for refreshing of the grid layout, and thus its Value property is not appropriate to the current row value.

Headers always cover VFP controls on form no matter how they arranged or located. Use separate window control that has also some disadvantages.

Vertical Scroll Bar position calculated using RecCount() and current RecNo(), not the really displayed records count. When record source is filtered or contains a lot of records marked for deletion, scroll bar often confuse users by inappropriate positioning. In such case use of the query or view is recommended.

VFP Grids, Next Parts

The upcoming articles should discuss the events model of grid, what is a cover shape and how to use it, the power of Dynamic* properties of column, saving and restoring of the grid layout, dynamic columns removing/adding, and more tips and warnings!

Download the samples for this article

Vlad Grynchyshyn, Soft Serve
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experience working with many MS development tools, components, utilities and documentation. Most experience is related to Visual FoxPro, MS SQL Server, Visual Studio and Visual Basic. He is active member of Visual FoxPro and SQL Server community, author of several articles for Universal Thread WEB site and other VFP community forums. He was MS MVP 2001-2002. He has a MS MCP certificate in Visual FoxPro area.
More articles from this author
Vlad Grynchyshyn, May 28, 2002
VFP does not support 256-color icons as project's icon (icon displayed for EXE in Windows Explorer). But 16-color icons usually looks ugly and too simplified. Here is an approach that allows organize 256-color icons for VFP EXE application. The approach is based on use of Resource Hacker appli...
Vlad Grynchyshyn, February 8, 2002
There is a situation often when we need some way to position a text cursor in the text of Editbox or RTF ActiveX controlwhen right click on the control. For example, we want to display a shortcut menu on right click. In menu, user select an option that insert some text into the control on place of c...
Vlad Grynchyshyn, March 16, 2001
Have you ever found a situation when your grid don't want to behave as you directed in design time? Custom controls in columns lost? Code of columns, headers or controls event not running? Read this FAQ then. Grid reconstruction behavior is a complete removing of all grid's controls and columns a...
Vlad Grynchyshyn, September 21, 2001
In VFP there are no direct way to assign code to the method or event in run-time mode. However, some workaround is possible with use of additional, 'hook' class. The sample below describes the approach. It is possible to make it generic. The approach is very useful to catch, for example, events of t...
Vlad Grynchyshyn, February 1, 2002
In VFP6 Grid value of the ToolTipText property of controls is displayed only for the entire grid or for current control when mouse is over it. Becuase there are a lot of parts in the grid, it is often useful to display tool tip for different parts separately. Unfortunately, VFP interprets grid as a ...
Vlad Grynchyshyn, February 8, 2002
The approach is based on a simple principle. LeftColumn property of the grid represents a column that is currently the leftmost visible column in the grid with current horizontal scrolling. As we scroll the grid horizontally, this property changes. We can assign this number to the ColumnOrder proper...
Vlad Grynchyshyn, October 6, 2000
Windows form caption properties stored in the user preferences. You can change them using Windows Control Panel\Display\Appearance. To get these parameters programmatically in VFP, you can use following routine as a sample.
Vlad Grynchyshyn, February 6, 2001
After some investigation, I managed to make a collection-like property of object. The following is a simple sample of how to organize collection-like access (rough, need to improve it to work as real collection). It is just to show an approach.
Vlad Grynchyshyn, June 20, 2001
This article describes how to configure grid to appear as a list similar to the list box or the drop-down list of combo box. It is for appearance only. All other things are as usual for any grid. This is useful for case when need to replace list box by a grid to display more records, because list...
Vlad Grynchyshyn, April 9, 2002
The SQLEXEC() function in VFP allows downloading of data from any data source through ODBC. Unlike remote views, SQL Pass-Through approach does not provide default (automatic) settings in the returned cursor to update data on the server after changes in the cursor at the client side. Anyway, it is p...
Vlad Grynchyshyn, September 4, 2001
There is a little problem for query to get something like a sum() for a character field to concatenate character values from all records in the group. Here is described solution. The approach below have an limitation to max 30 records in group for concatenation. Test it if it will work for more r...
Vlad Grynchyshyn, February 5, 2001
Suggest Grid1 is a name of grid required to put onto the form, grid should contain 10 columns an display data from the MyAlias alias. Grid should contain a combo box in the second colunm with the name Combo1. Following sample routine will allow you to see a generic idea of how to put grid on the for...
Vlad Grynchyshyn, January 26, 2001
I have seen many questions about sorting of a grid by clicking on its header and proper refreshing of grid after sorting. There is a reliable way to sort (index) grid cursor and properly refresh the grid without change of the record number AND with very good looking. I made this in my grid class and...
Vlad Grynchyshyn, January 11, 2001
Text field on SQL Serevr is not good to store binary data because it is not reliable and often SQL Server corrupts binary data in text field. varbinary type could be too short. There are certain difficulties to use image field on SQL Server to store and read binary data in VFP. Image field on SQL...
Vlad Grynchyshyn, September 1, 2002
Hussars Very often VFP applications are associated with Microsoft Office programs. Users want to use the formatting abilities of MS Word to create documents, send letters using Outlook and to carry out statistical analysis of data in Excel. "Smart tags" is a new technology used in O...
Vlad Grynchyshyn, February 5, 2002
SQL Pass Through commands often can take a lot of time for running and returning the result set to the client. It is often usefult to show a progress bar in case of such lengthy process. Also, FetchAsNeeded option, available for views, could be very useful for SPT cursors as well. However, how we ca...
Vlad Grynchyshyn, August 1, 2001
What is the grid and when to use it? Grid control is a set of the VFP objects that allow representing data in a grid-like scrollable list. Grid consist of the grid object itself and a set of the columns. Each column must have a header object and a control that represent a data in the grid col...
Vlad Grynchyshyn, September 1, 2001
In this part, I will discuss about grid columns and header tricks on how to make development with grids go faster. I will also discuss about detecting the exact positioning over grid header or cell. As usual, I have included some tips and warnings. Grid column and header tricks - how to make de...
Vlad Grynchyshyn, October 1, 2003
This is the monthly column of Vlad Grynchyshyn SQL Server Tips. This column includes four monthly tips in regards to SQL Server which covers various topics either discussed online on the Universal Thread or sent as a contribution by another person.
Vlad Grynchyshyn, November 1, 2003
This is the monthly column of Vlad Grynchyshyn SQL Server Tips. This column includes four monthly tips in regards to SQL Server which covers various topics either discussed online on the Universal Thread or sent as a contribution by another person.
Vlad Grynchyshyn, December 1, 2003
This is the monthly column of Vlad Grynchyshyn SQL Server Tips. This column includes four monthly tips in regards to SQL Server which covers various topics either discussed online on the Universal Thread or sent as a contribution by another person.
Vlad Grynchyshyn, September 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, August 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, July 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, June 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, February 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, January 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, March 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, May 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, April 1, 2003
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...
Vlad Grynchyshyn, December 1, 2002
Vlad Grynchyshyn is senior developer and project manager at the Ukrainian company "Soft Serve Ltd.", that provides custom-developed software solutions in several areas with use of wide range of development tools and languages. Vlad works in the MS Solutions department of the company, and has experie...