Add Columns in SQL SELECT Statements
Add Columns in SQL SELECT Statements
(Note that the word 'AS' is not actually required by the syntax of VFP (or SQL Server);
but some of the dialects require it, and in any case, I think it improves the reading of the
Consultation.) Now, let's suppose we have some data in a table like this:
If we need to concatenate the columns of the name to create a 'full name', then,
we can do something like this:
Although, in practice, this is not as intuitive as it may seem at first glance. The issue here
is that when we create a 'computed column' (which is what I do here) VFP creates the
definition for that column based on the length of the existing columns in the concatenation.
So, if both fields 'cfirst' and 'clast' are defined as c(20), the result is defined with a
field with c(41). In other words, the 20 characters for the first field, one for the
space and 20 characters for each field.
This is fine, although it may be a waste of space; but it will not cause data loss and if
we actually want to shorten them, we can simply use the PADR() function to force the
width of a specific value:
However, if we are also converting data types (from numbers to characters, for
example), then we will have a power problem because in this case VFP is not aware of
How long the data could be. All it can do is rely on the definition of size.
of the first element found. Then, the following query:
It will return a resulting set with the column "cvalue" defined as c(6) - in other words,
the number of characters in the first value of the table. This, of course, means that the
the second value is truncated because it actually contains seven characters. So now it is
it is very important to ensure that we have specified a format for the field that is as
long enough to manipulate any possible value and we can use the PADR() function.
to control the format once we have transformed the data: like this:
SELECT PADR( TRANSFORM( nnum1 ), 10) AS cvalue FROM sample
However, the introduction of the CAST() function in VFP 9.0 provides an alternative, as it allows us
it allows us to directly tell VFP how we want to obtain the output of the results. So,
In VFP 9.0 we can write the first query this way:
All of this is very well when we are working with existing columns; but what happens if
Do we need to create a new column with a specific data type? Well, it's quite easy.
create character columns, using the SPACE() function (or even PADL()) to create the
required width:
Similarly, if you need a column for currency-type data, you should define them as "$U" and
a new data using an empty date string "{}", a new decimal column using a
zero string, a logical column using .F., etc.
$0
FROM sample
Having this, I might be tempted to think that creating a column for integer data would be so
simple as:
After all, when creating a column for integers in a table, it is initialized with '0', so,
It seems reasonable to tell VFP that when creating a column for value '0' we will get an integer.
Unfortunately, that is not the case! What actually happens is that VFP creates a column.
numeric with width = 1 and decimals = 0. The result is that it can only store the values
from 0-9. And this is not what we want!
So, how do we obtain an integer value? Well, before VFP 9.0 there was a little trick and
two possible ways to do it. The first (and simplest) would be to define the column with sufficient
space to store the integer.
The result is not actually a column for integer data, quite the opposite, it is a
very large numeric column (N(10,0)) and I always find it problematic to be counting so many
zeros. To create a true column for integers in a resulting set we have to
employ a trick that involves creating a Cartesian product.
A Cartesian product occurs when a query joins two tables without specifying a condition.
validation. The result is that each record from the first table is linked to each record from the
second. The resulting set contains, therefore, the number of records obtained from the
multiplication of the number of records in the first table by the number of records in the
second table. This will quickly generate a VERY large resulting set. A query like
this
Well, if we create a cursor called 'dummy' (fictitious) that has a single column (defined
like an integer). Then, we add an empty record to the cursor and include 'dummy' in the list
FROM the query without specifying a join condition, we force all columns of the
fictitious cursors are unconditionally added to the resulting set with an extra column,
for integer values, which is called by the name we have given in the fictitious cursor. From
this way:
The same trick can be used to add MEMO, GENERAL fields to the resulting set.
or even any column, for any type of data.
However, using VFP 9.0 we will no longer need to use this trick, thanks, a
more about the CAST() function. By using this function we can simply tell VFP to create
the type of column we need:
The VFP 9.0 Help file includes a table that defines the conversions that can be made.
with CAST() and those that don't. For example, it can display date values as characters, varchar,
datetime or memo; but not as numerical data.
Of course, the usual reason for adding a new column to the resulting set is that
then it can be updated with some values. A common requirement is to add a column
from logical values to the cursor that will be used as a source to print a report. The idea is
that when processing each record, an indicator is updated and we have some idea of what the
records that should actually be sent to the printer in case something goes wrong. The
the problem in this case is that the cursor created by a SQL select instruction is created in VFP from
read-only type.
Before version 7.0, we had to use another trick to create a read-only version of a
VFP cursor. It is based on the fact that the cursor is actually implemented as a table.
temporary and if it tries to use an existing cursor twice, VFP is required to create one
second table for that, and that table is going to be created as a read-write type. So, the code
next will create a read-write cursor in any version of VFP (even in
FoxPro 2.x!!
Version 7.0 of VFP introduced the READWRITE clause to the language, which tells VFP to create
directly a read-write cursor:
However, as I remembered a few days ago, it is important to know the old tricks as
we have some application running in FoxPro 2.6 for a client and the easiest way to
controlling the problem was to use a read-write cursor, of course, in FoxPro 2.6
I couldn't do it ... except using the trick shown before.