URL: http://www.firstbasesoftware.com/man/man1/dbsql.htm
Last modified: 12 September 1995
Copyright © by FirstBase Software.
[
Index of Contents] [
FirstBase RDBMS Overview]
Dbsql is a non-procedural language and command interpreter that allows complex database relations involving any number of databases to be queried, displayed, or even stored as new FirstBase data objects. Every dbsql statement is executed -- results are either projected (displayed) or stored.
Although the standard for SQL uses only uppercase, dbsql will handle both uppercase and lowercase. However, in this manual page all key words will still appear in uppercase.
In interactive mode, dbsql will provide a dbsql> prompt. Each statement, entered on as many lines as needed and terminated with a semicolon, is then executed as a dbsql command. Once the result is projected or stored, the prompt is redisplayed.
To exit interactive dbsql use an end-of-file keystroke (Control-D) or either the quit or exit directives. A full list of directives appears below.
Stored dbsql commands or scripts can be processed using the -f switch. During this batchmode processing, dbsql will execute each statement, projecting results to standard output. If this output is redirected, dbsql could run as a background process.
Some parts of dbsql default behavior are controlled by the environment. The pagelength and width of the display device are determined at run time using termcap(3) routines. These variables can also be controlled by the -p and -w switches.
The environment variable PAGER is also used for the -P option. This option, effective only in interactive mode, will use a standard UNIX paging tool (like more(1)) to display the results of a request. This feature is quite useful if the results to a query are many pages long.
Formatted output using dbsql is done using a mixture of switch settings and augmentations to the standard SQL SELECT statement. First, the -h must be specified to enable report headers to be generated. Then, indentation is controlled by -i.
Top and bottom margins are manipulated using the -mN format where N is 1 through 4 depending on which section the margin_value is going to represent: top of page to header, header to top of text body, bottom of text body to footer, footer to bottom of page. The default for each of these four margin values is 2 (for two lines of space in each place).
For more information on formatted output, see the section entitled REPORT GENERATION below.
When dbsql is executing statements, temporary files, databases and indexes are sometimes created. The default area for this storage is in /usr/tmp, but can be controlled with the -t switch.
The default output of dbsql is formatted in columns, if the result will fit horizontally on the display device. Otherwise, the output is displayed vertically.
However, by using the -e switch, dbsql can be forced to generate standard FirstBase dbemit(1) style output. This output is one record per line, with tokens separating the fields. The default token is a comma, though the -c option controls this character separator.
The -H option turns on HTML output mode. In this mode, all output will be as HTML documents with a table representing the results. The -HB option places a border around the table, with the width specified by any connected digits, for example -HB2. In a similar manner, -HC controls table cell padding.
To communicate with dbsql using a CGI (Common Gateway Interface) request, use dbmacro(1). One method is to generate the needed dbsql query into one temporary file, and the command file that executes the query into a different temporary file, use the dbmacro function popen on the command file, read all output from the process with fgets and print this output to standard out using the dbmacro function puts or printf.
Other option switches affecting the dbemit(1) style output are -q for forcing quotes around all alpha type fields and -v for formatting date and dollar type fields. The -n switch is used to force the long fields to print using the string "\n" in place of newlines. This format is understood by dbload(1).
The last six clauses are all optional -- only the <from clause> is required to project (display) the <select list>. Each of the components of this <query specification> is listed in detail in the grammar. There are also many examples below.<query specification> ::= SELECT [ ALL | DISTINCT ] <select list> <from clause> [ <where clause> ] [ <order by clause> ] [ <group by clause> ] [ <having clause> ] [ <header clause> ] [ <footer clause> ]
The <where clause> is used to limit the set of records or relations displayed. The limitations described can be very complex, with AND/OR connections between sub parts. Standard math notation, set and string functions, and parenthesis for grouping are all supported.
The <order by clause> is used to display the results in a specific order. Either ascending or descending order can be specified. Note that each element of the <order by clause> must also appear in the actual >select list>, or be a numeral representing a column from this list.
The <group by clause> can be used to partition the set of found records or relations into groups. Each part of the <select list> for these requests must be single valued per group, or be a function on a field or column. The function, for example SUM, will be done for that one group only. Note that in dbsql, group by presumes order by.
The <having clause> is an optional clause used to limit the groups chosen in the <group by clause>. Only those groups passing the restrictions in this clause will be included in the final display.
The <header clause> and <footer clause> can be used to specify report headers and footers. See the section on REPORT GENERATION below.
The result of the CREATE VIEW is an actual FirstBase database complete with a database dictionary. The names of the fields can be controlled (and must be! if the <select list> contains expressions as opposed to simple fields or columns) using the optional <column list> .<view definition> ::= CREATE VIEW <table name> [ <column list> ] AS <query specification>
<drop view statement> ::= DROP VEIW <table name>
The <where clause> is used to limit the selected records to any subset describable using standard dbsql expressions, as done in the SELECT statement.<index definition> ::= CREATE INDEX <index name> ON <table name> ( <index column> [ {,<index column>}... ] ) [ <where clause> ] <index column> ::= <column name> [ ASC | DESC ]
The result of a CREATE INDEX is the index and index header portion of a FirstBase index. Since dbigen(1) is not used during this index creation, an index dictionary, as created by dbdind(1) is not used nor generated.
<drop index definition> ::= DROP INDEX <index name>
The more useful types of data to run through FORMFIELD are $ for DOLLARS and d for DATE. Remember standard FirstBase format for DOLLARS is without the decimal, so expressions without a DOLLARS type involved will need to be multipled by 100 before running through FORMFIELD, if type $ is requested. Standard FirstBase format for DATE is MMDDYY.
Secondly, there are a number of command line switches, already mentioned above, that concern formatted output. The switches -i, -p and -w control the indentation, page length and page width. The series of -mN switches controls the four top/bottom margins.
Headers and footers are specified using the HEADER and FOOTER, as defined by the <header clause> and the <footer clause>. The literals themselves need to be of the form
where each part is separated by an apostrophe. Note there is a leading apostrophe also. This feature is the same three part title method used by nroff(1)."'Left Part'Middle Part'Right Part'"
Using this three part header format to denote HEADER and FOOTER requests allows control over most all desired output styles. The left parts are left justified, the middle parts are centered, and the right parts are right justified.
Furthermore, separate EVEN and ODD headers and footers can be specified. This feature enables reports to be formatted for double sided results.
There are also a set of key words or macros that can be used in the building of the HEADER and FOOTER values. The following is a list of these macros.
In dbsql, full UNIX path names are allowed in the <from clause>. But once used there, only the basename of the database (variable) is used in all other clauses. See the EXAMPLES below.
A side effect allowing UNIX pathnames is that the forward slash character, the `/' character, has two meanings: one inside of PATH names, the other when used as a divide symbol. Due to this dual use of the slash, white space of some kind must appear on each side of this character when used as a divide symbol.
Another feature of dbsql, partially supported by standard SQL, is the pattern matching mechanism of the LIKE predicate. This predicate, used in the <where clause>, implements pattern matching using the standard UNIX regular expression mechanism, with a slight modification to the allowed meta-characters.
Standard SQL uses only two meta-characters for its <pattern>, the % (percent) and _ (underscore). The percent matches one or more characters, the underscore matches exactly one. These meta-characters work in dbsql, along with all other standard UNIX meta characters for regular expression pattern matching (*, ., [], etc).
Again, all dbsql keywords are given in uppercase even though lowercase keywords are also acceptable.database1: -- -------- ---------- ----- ID Date Item Price -- -------- ---------- ----- 1 01/02/90 book 9.00 2 12/21/89 tape 8.00 3 12/01/89 cd 9.50 4 02/03/90 tape 7.50 5 07/08/90 cd 8.99 6 09/08/90 tape 7.50 database2: -- ------------------------------ -------- ID Title Quantity -- ------------------------------ -------- 1 The Joy Of Spiders 4 2 Best Of The Janes 18 3 Jump - Off The Edge 11 4 The Sticks - One On One 11 5 Molly McFaren - Live 7 6 Poking Holes In A Vacuum 12
This query displays all (*) fields of all records in database1.SELECT * FROM database1;
This query finds all records in database1 with "cd" entered in the field Item, and displays the fields ID and Item.SELECT ID, Item FROM database1 WHERE Item = "cd";
This selects all records in the database where the Item field entry contains "b%k", i.e. all records with an entry in Item starting with a b, ending in a k, with any number of characters in between.SELECT * FROM database1 WHERE Item LIKE "b%k";
Here all records where the Item is a book or tape will be displayed.SELECT * FROM database1 WHERE Item IN ("book", "tape");
This query displays all records whose Item entry is between "book" and "tape". (This would display all records with book, cd or tape in the Item field.)SELECT * FROM database1 WHERE Item BETWEEN "book" AND "tape";
The output of this query will be all Date entries between May 15, 1990 and Dec. 31, 1990.SELECT Date FROM database1 WHERE Date > "051590" AND Date < "123190";
The output of this query displays all database1 records having a Price entry that is greater that the average value of Price. The average Price is also displayed.SELECT database1.*, AVG(Price) FROM database1 WHERE Price > AVG(Price);
This query displays all database1 records having a Price entry that is not greater than the average value of Price.SELECT * FROM database2 WHERE NOT Quantity > AVG(Quantity);
Here, the contents of database1 are displayed, but the output is sorted (ORDER BY) Price.SELECT * FROM database1 ORDER BY Price;
In this example, the contents of database2 are displayed. Notice that only records with a Quantity of 11 will be displayed.SELECT * FROM database2 GROUP BY Quantity HAVING Quantity = "11";
This query displays the contents of database1, and a new field - COUNT(*). Note that Item must have a count higher than 1 to be included in the output.SELECT database1.*, COUNT(*) FROM database1 GROUP BY Item HAVING COUNT(*) > 1 ;
Here, each value of the Quantity field is displayed once, and the sum of all quantities having that same value is displayed next to it.SELECT Quantity, SUM(Quantity) FROM database2 GROUP BY Quantity;
This query displays the ID and Quantity fields of database2 and also displays the value of "ID + Quantity * 5" in a field named "Quant * 5 + ID". Note that the math function is performed as (Quantity * 5) + ID.SELECT ID, Quantity, ID + Quantity * 5 LABEL AS "Quant * 5 + ID" FROM database2;
Here, we are displaying a list of Items (GROUP BY), and the quantity of each item - COUNT(*).SELECT Item, COUNT(*) FROM database1 GROUP BY Item;
In this example, the Item and Quantity fields are shown for all records where the Item is a "cd" or the Quantity is 9 - 11. The output of this query is the cross product of the requested fields of the 2 databases.SELECT database1.Item, database2.Quantity FROM database1, database2 WHERE database1.ID = database2.ID AND database1.Item = "cd" OR database2.Quantity BETWEEN 9 and 11;
Here, the output is the same as the previous example, but any duplicate records are removed (DISTINCT). Also, the output is sorted by Quantity because of the ORDER BY clause.SELECT DISTINCT database1.Item, database2.Quantity FROM database1, database2 WHERE database1.ID = database2.ID AND database1.Item = "cd" OR database2.Quantity BETWEEN 9 and 11 ORDER BY database2.Quantity;
This query searches database1 for "tape" entries in the Item field, and then displays their titles in the database2.Title field. Notice that this field has been renamed (using "label as") as Tapes. Also notice that the 2 databases are in different directories.SELECT database2.Title label as "Tapes" FROM /usr/database/database1, ~/database2 WHERE database1.Item = "tape" AND database1.ID = database2.ID;
This example uses a query within a query. This is known as a subquery. This will find IDs and Items in database1 whose IDs are also found in database2 with Quantity greater than 10.SELECT ID, Item FROM database1 WHERE ID IN (SELECT ID FROM database2 WHERE Quantity > 10);
This query displays the Date field of database1 and the SYSDATE (today's date). Notice that SYSDATE is not formatted.SELECT Date, SYSDATE FROM database1;
This produces the same result as the previous example. Notice that SYSDATE is now properly formatted.SELECT Date, FORMFIELD(SYSDATE, "d", 6) FROM database1;
This query displays all the date of all records whose Date entry is earlier than the current date.SELECT Date FROM database1 WHERE Date < SYSDATE;
This query displays the ID, Item and Price fields of database1. Also included, are a header and footer. To display header information, the query must be run with the -h flag.SELECT ID, Item, Price FROM database1 HEADER "''My Very Own Report''" FOOTER "'$USER'$CONAME'-$PAGE-'";
This query displays the ID, Title and Quantity (renamed Amount) fields of database2 along with a new field (ID + Quantity). This field has been has been truncated and formatted, after being multiplied by 100 to place into standard FirstBase DOLLARS form.SELECT ID, Title, Quantity LABEL Amount, FORMFIELD(TRUNC((ID + Quantity) * 100.0, 0), "$", 10) LABEL "Formatted Result" FROM database2 HEADER ODD "'odd header'middle part'-%-'" EVEN "'-%-'even header'right part" FOOTER ODD "'odd footer'middle part'-%-'" EVEN "'-%-'even footer 'right part'";
This query creates a new FirstBase database (database3) with fields OrderDate, PtNum and Tapes, using data from database1.CREATE VIEW database3 (OrderDate, PtNum, Tapes) AS SELECT Date, ID, Item FROM database1 WHERE Item = "tape";
This query creates a FirstBase index (index3) for database3. The index finds all records with a PtNum greater than 3, and sorts the resulting records by OrderDate.CREATE INDEX index3 ON database3 (OrderDate) WHERE PtNum > 3;
ABS ALL AND ANY AS ASC AVG BETWEEN BY COUNT CREATE DESC DISTINCT DROP EVEN EXISTS FOOTER FORMFIELD FROM GEQ GROUP HAVING HEADER IN INDEX INTO IS LABEL LENGTH LEQ LIKE LOWER MAX MIN NEQ NOT NULL ODD OF ON OR ORDER POWER ROUND SELECT SOME SUBLINE SUBSTR SUM SYSDATE TO TRUNC UPPER VIEW WHERE
Finally, two or more variable queries (queries involving two or more databases) that use an equivalence join, or equijoin, can be further optimized using standard FirstBase autoindexes. To utilize this feature, make sure at least one of the fields used in the join is a true FirstBase autoindex as defined in the database dictionary. This feature is well worth using, even if autoindexes need to be set up from scratch. See dbdind(1) and dbigen(1) for more details on autoindexes.
<all set function> ::= { AVG | MAX | MIN | SUM } ( [ ALL ] <value expression> ) <boolean factor> ::= [ NOT ] <boolean primary> <boolean primary> ::= <predicate> | ( <search condition> ) <boolean term> ::= <boolean factor> | <boolean term> AND <boolean factor> <character> ::= <digit> | <letter> | <special character> <character representation> ::= <nonquote character> | '' <character string literal> ::= '<character representation>...' <column list> ::= ( <column name> [ {,<column name>}... ] ) <column name> ::= <identifier> <column specification> ::= <column name> | <table name>.<column name> | <table name>.* <comparison operator> ::= = | <> | < | > | <= | >= <distinct set function> ::= { AVG | MAX | MIN | SUM | COUNT } ( DISTINCT <column specification> ) <exact numeric literal> ::= [ + | - ] <unsigned integer> [ .<unsigned integer> ] | [ + | - ] <unsigned integer>. | [ + | - ] .<unsigned integer> <factor> ::= [ + | - ] <primary> <footer clause> ::= FOOTER [ ODD | EVEN ] <literal> [ ODD | EVEN <literal> ] <from clause> ::= FROM <table reference> [ {,<table reference>}...] <group by clause> ::= GROUP BY <column specification> [ {,<column specification>}... ] <having clause> ::= HAVING <search condition> <header clause> ::= HEADER [ ODD | EVEN ] <literal> [ ODD | EVEN <literal> ] <identifier> ::= <letter> [ { [ _ ] { <letter> | <digit> } }... ] <label> ::= LABEL [ AS ] <literal> <letter> ::= <lowercase letter> | <uppercase letter> <literal> ::= <character string literal> | <numeric literal> <numeric literal> ::= <exact numeric literal> <order by clause> ::= ORDER BY <sort specification> [ {,<sort specification>}... ] <pattern> ::= <value specification> <predicate> ::= <value expression> <comparison operator> <value expression> | <value expression> <comparison operator> <subquery> | <value expression> [ NOT ] BETWEEN <value expression> AND <value expression> | <value expression> [ NOT ] IN ( <value expression> {,<value expression>}... ) ] <value expression> [ NOT ] IN <subquery> | <column specification> [ NOT ] LIKE <pattern> | <column specification> IS [ NOT ] NULL | <value expression> <comparison operator> ALL <subquery> | <value expression> <comparison operator> ANY <subquery> | <value expression> <comparison operator> SOME <subquery> | EXISTS <subquery> <primary> ::= <value specification> | <column specification> | <set function specification> | <simple function specification> | ( <value expression> ) <query expression> ::= <query term> | <query expression> UNION [ ALL ] <query term> <query specification> ::= SELECT [ ALL | DISTINCT ] <select list> <table expression> <header clause> <footer clause> <query term> ::= <query specification> | ( <query expression> ) <search condition> ::= <boolean term> | <search condition> OR <boolean term> <select list> ::= <value expression> [ <label> ] [ {,<value expression> [ <label> ] }... ] | * <set function specification> ::= COUNT(*) | <distinct set function> | <all set function> <sequence number> ::= <unsigned integer> <simple function specification> ::= ABS(<value expression>) | FORMFIELD(<value expression>, <value expression>, <value expression>) | LENGTH(<value expression>) | LOWER(<value expression>) | POWER(<value expression>, <value expression>) | ROUND(<value expression>, <value expression>) | SUBSTR(<value expression>, <value expression>, <value expression>) | SUBLINE(<value expression>, <value expression>, <value expression>) | SYSDATE | TRUNC(<value expression>, <value expression>) | UPPER(<value expression>) <sort specification> ::= { <sequence number> | <column specification> } [ ASC | DESC ] <subquery> ::= ( SELECT [ ALL | DISTINCT ] { <value expression> | * } <table expression> ) <table expression> ::= <from clause> [ <where clause> ] [ <order by clause> ] [ <group by clause> ] [ <having clause> ] <table identifier> ::= <identifier> <table name> ::= [ <authorization identifier>. ] <table.identifier> <table reference> ::= <table name> <term> ::= <factor> | <term> * <factor> | <term> / <factor> <unsigned integer> ::= <digit>... <value expression> ::= <term> | <value expression> + <term> | <value expression> - <term> | <value expression> | <term> <value specification> ::= <parameter specification> | <variable specification> | <literal> <variable specification> ::= <variable name> <where clause> ::= WHERE <search condition>
This section describes the other four commands within dbsql. All of these commands create or destroy FirstBase data objects.
<view definition> ::= CREATE VIEW <table name> [ <column list> ] AS <query specification> <index definition> ::= CREATE INDEX <index name> ON <table name> ( <index column> [ {,<index column>}... ] ) [ <where clause> ] <index column> ::= <column name> [ ASC | DESC ] <drop index definition> ::= DROP INDEX <index name> <drop view statement> ::= DROP VEIW <table name>
FirstBase User's Guide and Reference Manual