Você está na página 1de 19
80572018 xBase fo SOL. XBase to SQL (Comparing XBase Commands to SQL Equivalents) Last Modified: January 31, 2001 Ken Mayer, Senior SQA Engineer BASE, Inc. NOTE: This document was originally written for Visual dBASE 7.0/7.01, it has been updated for dB2K (release 1) to include information about new properties, events, etc., and any new controls since the document was first written. If a control is new it will be noted. In updating this document, the images were left "as is" unless it was felt to be absolutely necessary to change them In addition, this document refers to dB2K a lot, but unless itis about a dB2K specific aspect, the text can be used for Visual dBASE 7.0 through Visual dBASE 7.5. The Purpose of this Document This document is provided to assist developers moving from earlier releases of dBASE (dBASE/DOS, Visual dBASE 5.x, ‘tc,) as well as other dialects of XBase move to dB2K. This document will attempt to compare and contrast XBase ‘commands and Local SQL equivalents. However and very importantly, this is not a suggestion that you should use all of these SQL equivalents in your d82K development. "Why not", you might ask. Because many of these will return read-only queries, which in most applications will serve no purpose. Instead, you will want to use the OODML of dB2K for most situations (see other HOW TOs in the Knowledgebase). ‘Special Note: some of these commands will work fine with Visual (BASE 5.5 and 5.6, but there are no guarantees —- the ‘SQL capabilites of the BDE were greatly enhanced in the 32-bit version of the BDE (4.5 and later releases), so if you try many of the commands shown here with VaBASE 5.x, you may find yourself getting a lot of "Capability not supported” errors. ‘There are times when using the local SQL commands may be a faster or more efficient way to do things (not many, but still.) NOTE: my primary source of information here is a really good book on SQL: Understanding the New SQL: A Complete Guide, by Jim Melton and Alan R. Simon, Morgan Kaufmann Publishers, San Francisco, 1883, ISBN: 1-55860-245-3. This book uses an excellent approach to teaching SQL and is well worth the rather high price. (This is in addition to ontine help but if you need to spend much time working with SQL, | heartily recommend this particular book ~- | have no experience with any others that are out there...) In addition to the book mentioned above, there is a "SQL Help" icon in your dB2K folder -- this discusses local SQL ‘commands in greater depth than is discussed here, Most importantly, it discusses these as implemented by the BDE. Various Explanations SQL commands, like XBase commands, are not generally case sensitive. In this document they are usually shown in all ‘caps to differentiate them from the data, fields, etc., but you can use them in mixed case, all caps, all lower case, etc. In the text of this document | usually give "Syntax’ listings. When | do, | use brackets (< and >) around the name of a value. For example, | might say: SELECT * FROM if you wanted to use the "FISH" table in the samples folder, you would replace "" with "fish" (without the quotes) ~ the resulting command would look like: SELECT * FROM fish When referring to Paradox tables, you may need to include the .DB table extension, and in some cases you may want to, ‘or need to include the extension anyway. When executing most of these commands, the table does not need to be opened. The examples should be fairly clear, and most of them have been tested against the samples tables that ship with dB2K, Intpsiwwwzdbase,con/KnowledgebaselINTxbase_to_sqlix2sqh.him ang 80572018 xBase fo SOL. Many of the SELECT statement options retum a result query, rather than opening the table directly as you might expect. This query is opened in dBASE as a temporary table, in the form of an alias with the name of SQL_. Any table ‘opened this way is not updatable (tis read-only). if you are not sure, you can use code along these lines to find out /Hssue your sevect statenent and then: 4 Cetablenane> $ 08#() ) 17 do whatever you want to do -- it's updateabie alse 1 At 43 read-only endif ‘The term columns is used to reference the fields in a record, and the term rows is used to reference records in a table (hese are standard SQL terms). I you see a pipe ()), it means you have an option for what to use (for example: "* | " will mean that you can use either the wildcard for “all fields" or a list of specific feldnames separated by commas). If you see a command option in square brackets ( (], it means that this is optional, and is not required. This is often shown with the "WHERE" clause, ie., SELECT * FROM [WHERE ) In many of the examples below, in order to actually use the samples tables, their BDE aliases are used. The BDE alias is ‘a pointer to a "database", and preceeds the table (for details on BDE Aliases see other HOW TO documents in the Knowledgebase). As an example, you may want to manipulate the “FISH” table in the OB2KSAMPLE database. To reference this table, it must be preceeded with the database reference: ":db2ksample:", .e., SELECT * FROM :dbaksample: fish ‘Some columns in tables may have spaces or use SQL reserved words as the field names ~ in those cases, you need to reference them with the table name in front of them with a dot separator, and quotes around the field name. Example: SELECT nane, fish. jength cn" FROM :ch2ksanpLe:fish Finally, a last mention ~ for the most part, you will need to know very litle SQL in dB2K, but for those who want to know more, its here ... this document does not cover all aspects of SQL. The purpose of this document is to be a comparison of XBase commands to local SQ. commands and to give a developer a basic understanding of how SQL works in d82k with local tables. (Many ‘SQL Server’ software packages, such as Interbase, Oracle, and others have much more advanced SQL engines, the Borland Database Engine will pass along any SQL it does not directly understand to these engines and return the proper results... if you are using one of these servers you may need to reference the manuals for ‘more details on what is possible...) Before You Start Reading If you are one of those who likes to try things as they are shown to you, you will want to make sure that the two database aliases referenced here are open. These are from the SAMPLES that are installed (by default) with dB2K, although some of the samples shown here use sample tables from aliases that do not exist (MUGS, from Visual dBASE 7.x) if you have ‘only got dB2K on your computer, and not an earlier version of Visual dBASE 7.x. In the Command Window, type: open database mugs ‘open database cb?ksanple You can then enter the commands in the Command Window You may wish to back up the tables in the sample directories before you tinker with any examples shown in this HOW TO document, or these tables may get deleted, indexes wiped, etc. fa command is shown split over multiple lines you will want to enter it as a single statement (no break), and remove the ‘semicolins (;) shown at the end of the breaks .. If you wish to S90 the results of a command you have entered, you will want to enter the SELECT command as shown, and then type: BROWSE ~- this will bring the table up in the standard browse mode so you can see the results. When you issue a SQL SELECT statement, dBASE automatically opens the result (whether itis a result query, or the actual lable in question) in a new work area. This means that if you do a lot of working with local SQL you may have a lot of open work areas. In your code, if you wish to use a SQL select to get a result query and then do something with it, you will want to close that result and retum fo your previous work area. You might want to do something along the following lines: carea = altas() // current work area SELECT * FROM whatever WERE whateveroptions Intpsiwwwzdbase,con/KnowledgebaselINTxbase_to_sqlix2sqh.him ane 80572018 xBase fo SOL. // do what you need to retrieve results you are Looking for use 17 close the query select ( cArea ) // back to previous work area When done, you may want to close your tables and result queries by typing: CLOSE TABL When you are completely done, you may also wish to issue the command: CLOSE DATABASES to make sure you don't leave those open (the next time you start dBASE it will open these for you XBase Command Equivalents in SQL (as implemented by the BDE) This section of the document is aimed at showing direct equivalents to XBase DML commands (XDML) in SQL. There may be other XOML commands that map closely to SQL commands, but these are the ones | could find an equivalent for. APPEND/APPEND FROM You can add rows to a table using the SQL INSERT command. ‘APPEND ‘SQL Syntax: INSERT INTO ctaplenane> [( )] 5 VALUES (" ) Ifyou leave out the column listing, there must be a value for each field, and fields are fillad in the sequence the fields are defined in the table structure (i.e, first value is placed in the first field ...) If you use the column listing, you must specify at least one column and the associated value. If you leave columns out of the list, they will be empty (null - this means that the empty() function will return true, but isblank() may not). Example: 17 add a new row to fish table in “so2xSample” database: INSERT INTO :ds2kSample:#ish (rane, species, fish."length en”); VALUES (George", “Human", 18 ) You can then browse the table after opening it and you will see the new row: SELECT * FROM :c82kSanple:Fish BROWSE APPEND FROM SQL Syntax: INSERT INTO ctablenane> SELECT * | ; FROM ctablenane> [HERE ] ‘The columns in the select statement must match the columns in the table being inserted into (although the fieldnames do not have to match, the number of columns, the types and the sizes must match). If you use the field list, the fields must match as noted Example: INSERT INTO :dB2kSanple:#ish SELECT * FROM :db2KSanple:#ish2 ‘The above would assume you had made a copy of the fish table in the dB2KSample directory ( "copy table fish to fish2" ) ... and perhaps had changed the data in the second table. Ifyou use the optional "WHERE" clause (this is discussed later in this document in some detall) only the rows in the table being appended from that meet the condition would be appended, Example: INSERT INTO :d82KSample: fish SELECT * FROM :a®2KSample:fish2 WHERE Fsh2."Length cn” <= 18 itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him ang 80572018 xBase fo SOL. COUNT ‘The XBase DML command COUNT is used to count the records in a table. You can add qualifiers (COUNT FOR ...) and s0 on, And you can use a COUNT .... TO ... to save the value to a memory variable, ‘The SQL equivalent is to generate a read-only query that contains a single row with a single column with the number of rows, optionally it will count just the rows that that match a condition: SQL Syntax: SELECT COUNT(*) FROM ctablename> [WHERE ) Examples: SELECT COUNI(*) FROM :c82kSanple:#ish Wo: SELECT COUNI(=) FON :cB2xSanple:4ish MHERE fish."Length cn” <= 16 This will return a result table with a name like "SQL_1" or "SQL_2". You can browse it and see the results - you will end Up with a single column (or field) named "COUNT___" (note ~ that is three underscore characters ~ it may not look like it depending on what fonts are being used and such). If you then close all tables or issue "USE" the temporary result table wil be closed and gone Ifyou wish to save the value to a memory variable, you could do something like: area = atias() SELECT COUNT(*) FROM :cB2KSanple:fish WHERE fish."Length cn" 1 save to a memory variable: 17 close the temporary table: select (cArea) There are more ‘calculations’ toward the end of this document. DELETE/ZAP ‘The dBASE table format (,DBF) uses a "soft delete", The only advantage to using this is that it means that the records are left in the table in case you need to recall them, The XBase DML is designed to work with this feature, and all local SQL and OODML commands that work with .OBFs actually map to the soft delete for .DBF tables. NOTE that this only occurs {for .DBFs ~ this is the only table format that uses the soft delete ~ all other table formats actually delete a row when you specify that you really want to delete it Local SQL respects the "SET DELETED" setting, which determines whether or not to display rows that have been “flagged” as deleted ‘SQL Syntax DELETE FROK ctablenane> [MHERE ] WARNING: If you leave off the condition for this command you will empty your table! This is the equivalent of ZAP, except that DELETE FROM ignores the setting of SET SAFETY and will not ask if you really wish to delete the rows in the table NOTE: Just like the ZAP command, "DELETE FROM" requires exclusive use of the table. If you are not sure if you can obtain exclusive use of the table, you may wish to use the following function (by Peter Rorlick, found in the dUFLP library ..): ‘Function UseExclusive( cTableWane, TTrNewtres ) local Isuccess H1A§, user wants it tn 0 new work area: select select() endif // open the table with the exclusive parameter: tse (eTablewane) exclusive UE defaute: success = false U noxt we need to see if we can actually do this: ‘elece tag DunmyXVZ // nonexistart index tag 7 the above Line will throw one of three Iitpsiwwwzdbase,con/KnowledgobaselINTxbase_to_sqlix2sql.him 4ng 80572018 xBase fo SOL. UI ervors: 1/110: “Operation requires exclusive use of table’ W533: "Tag not found: Dusrw2" or 135: “Table 1s not indexed catch( exception © ) If eccode == 53 // messoge = “Error: Tag not found” Yi we have succeeded in opening the table exclusively ISuecess = true endif endery 17 table 45 now open one way or another return ISuecess Note that if you do this, you will then want to close the table before executing the SQL DELETE command. Example: AF Usebxclusive( ":4B2KSanple: ish" ) DELETE FROM :d82KSanple: ish KHERE name TS HULL else endif Examples: 1) detere empty rows DELETE FROM 1482KSanple:Fish WHERE name TS HULL U7 detete specific row: DELETE’ FROM :402KSanple:Fish WERE nane = “George’ 17 enpty the table (only do this if you have backed up the table) DELETE FROM 882KSanpie: Fish ‘As another caveat ~ if you are unfamiliar with the "soft delete" feature of .DBF tables, the data is stil there, but to retrieve ityou would need to use the XBase RECALL command (details in online help). To completely remove deleted rows of a table you would need to use the XBase PACK command, or the OODML database object's packTable() method. To view rows that have been deleted, issue the command SET DELETED OFF, or use the Properties dialog to set this option. To not see deleted rows, SET DELETED ON (this is the default in dB2K). DELETE TABLE ‘The XBase DML command DELETE TABLE is used to remove a table and all i's associated files (MDX, .DBT in the case of a .DBF, in the case of a .DB table, all the myriad assorted files that may be created). ‘The SQL command for this is DROP TABLE. ‘SQL Syntax ROP TABLE Example (only do this if you have backed up the table.) DROP TABLE :. | PRIMARY Note that the word "PRIMARY" is used for .DB tables with a primary index in place of the shown above (the .DB table format can create a primary index with no index name, so this keyword is vital). For .DBFs with a primary index, Use the index name Examples: W for a 08: DROP INDEX sas2Ksaeple:Fish.spectes itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him sno 80572018 xBase fo SOL. //. or for a .08 (note that this is an example but the 1 Kable does not exist «.. this WiLL return an error 1-§ you try 4 right naw): INDEX ‘The XBase DML command INDEX, with i's various options, is used to create indexes for your tables. With .DBF tables, it is used to create either LNDX files or MDX tags. ‘The SQL command for this is CREATE INDEX, Note that with .DBFs this command will create .MDX tags, but no .NDX files - there is no option for this. SQL Syntax: (CREATE INDEX cindexrane> OW 3 (ccolunmt> [, ‘There are some serious drawbacks here if you are used to creating expression indexes -- you cannot do this in SQL. You ‘can create indexes on multiple columns, but not on expressions. Further, you cannot create PRIMARY indexes with this command ~ the only way to create a PRIMARY index using SQL is with the CREATE TABLE command (i.e, when you create the table originally) and to the best of my knowledge this only works for Paradox tables. Examples’ (CREATE INDEX name2 ON :682KSample: Fish ( mare ) (CREATE INDEX nanespecies ON 14B2KSanple:fish ( mane, species ) REPLACE ‘The REPLACE command is the XBase DML method of programmatically assigning a value to a field, or by using the ALL" option, of replacing the data for a specific field (or fields) in all rows of a table. SQL Syntax: SET = [, = [ wiene ] ‘The "SET" is where you list the fields and what their new values are to be when the UPDATE has done it's job. Examples: (One example might be a need to replace a logical field for all rows in a rowset with “false UPDATE MyTable SET myLogicalFieid = false Note: In my non-scientific testing this is faster than the XBase REPLACE ALL command, and substantially faster than the oom method (which actually requires creating a loop to process a table row by row and storing a new value for each Ifyou needed to have a condition, let's say a date field based on some value: @ = aate() UPDATE MyTable SET myLogicelField = false; WHERE nybaterelé <= :e SET FIELDS ‘The XBase DML SET FIELDS command is used to limit the fields displayed or accessed in a table. ‘The SQL. version of this is to use a field list instead of the wildcard for the field names. In addition you can create calculated fields "on the fly"... see "USE" below. SET FILTER ‘The XBase DML SET FILTER statement was how a lot of filtering got done. Filters are done in SQL by using the optional WHERE or HAVING clauses which shows up in many of the commands in this document. You may find that the WHERE clause is substantially faster than the XBase filter. ‘The operators are important, as the syntax is not exactly the same between XDML and SQL: Iitpsiwwwzdbase,con/KnowedgebaselINTxbase_to_sqlix2sql.him eng 08/05/2018 xBase fo SOL. XBase sau fand/.and. fang forior. lor nov not not Hes le lempty(jisBlank() is mull nat emplyinot isBlank() is not null [stingt+string2 lstringt || string2 (concatenation of strings) Note that the sequence of the less than or greater than symbols combined with the equal signs is quite important in SQL (in other words, >= works, => does not), You can stack conditions up by combining them with and andior or operators just like you can in XBase. ‘The Where clause is the standard filter, and is used as below. The Having clause is used with aggregate calculations (calculated fields), where these fields have specific values. The Having clause can only be used when there is a calculated field and there is a Group By clause. SQL Syntax ~ Where clause: SELECT + | FROM WHERE 5 ‘eondition> [ORDER BY cFelanane(s)>] Example: SELECT * FROM :082KSanples: Fish We SQL Syntax — Having clause: SELECT FROM 5 kav? BY 5 HAVING ( ) (ORDER 8Y ) Example: SELECT Lneiten."invoice 14", sun( aty ) AS totalaty FROW :mugs:lineiten ; GROUP BY Linesten. "invoice id” 5 avINe ( sun(qty) <= 3) Note that you can combine a WHERE and a HAVING clause ... In addition (from LocalSQL Help): "A HAVING clause filters data after the aggregation of a GROUP BY clause. For filtering based on row values prior to aggregation, use a WHERE clause." Special Options Item List In XBase, there is the "$" operator, which is used to see if a string is contained in a list of strings (or in an individual string see below). In SQL, this is done with the "IN" clause: ‘SQL Syntax SELECT * | fom ctablenane> WHERE 5 “fieldname> IN ( citenl>, «-- ) Example: Note that the result query that is retumed is editable ... Special Options String1 In String2 This is different from the previous in that here we are looking for a match in a single string. In XBase, you could check to itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him m9 80572018 xBase fo SOL. see if a string was contained anywhere in the string (i.e, "somestring” $ fieldname ). In SQL this takes a bit more work, but with the use of some special wildcard characters, you can get there, The resulting rowset may be read-only. (NOTE: SQL is case sensitive ...) SQL Syntax: SELECT * | FROM ceablenane> IMERE 5 ‘flelénane> LIKE "stringeilth-wildeard(s) ‘The two wildcard characters are "%6" and *_" (percent and underscore). ‘The percent sign refers to anything on that side of the character string (see examples), the underscore refers to a single character. If you are familiar with DOS wildcards for flenames, the percent sign is similar to the asterisk (*), and the underscore works identically to the question mark (?). Examples: // return any ron where the nawe has the Letter ‘a’ tn tt 1 return any row uhere the name begins with 'B* SELECT * FROM ‘ob2KSanple:fisn WHERE nore LIKE "BY UI return any row were the none ENDS with "fish Sevecr * FROM ‘aB2kSaeple:fish MHERE nore LIKE "%fish™ 1 return any row where the nane storts with any to W characters, and then has the Letters "ue" and any 1 other characters ofter «+. SELECT * FROM :252¢Sanple:F3h WHERE nase LIKE "_uet” ‘And so on. Using a combination of these two characters you can do pretty much anything you need ... see also below where string functions are discussed -- you can use the string functions on a field name to make these case insensitive searches .. SET INDEX/SET ORDER ‘The XBase DML has SET INDEX and SET ORDER, which have similar uses. However, while SET INDEX can open .NDX files, SQL does not use these at all, and frankly doesn't know what they are. Using an index in SQL is pretty simple, but you can also bypass the index tags and simply tell BASE to order the data in whatever fashion you wish ‘SQL Syntax SELECT * | FHon ctablenane> ; ‘OROER BY [, ...) (ASCIDESC) Note that you can use more than one fieldname in the list, and you can refer to a calculated field (see below). ‘The ASC" and "DESC" operators are optional - the default sequence is to order a table in ascending sequence (ASC), but you can order it in descending if you wish (by adding "DESC" to the end of the ORDER BY clause or to the end of the individual field reference). Interestingly you can sort with a combination of ascending and descending fields using SQL in ‘one command, Note that if an index tag exists, you can use the index tag name in place of the field name. If the index tag has the same name as the field name, dBASE will use the index tag. I the index tag name is the same as a field name, SQL will use the index tag as well. Examples: 1/ order the custoner table by Last nae: SELECT * FROM imugs:custoner ORDER BY custorer."Iast rane” Uf order the custoner table by Last none in descending sequence: 11 case insensitive: SELECT'* FROM :nugeicustoner ORDER BY UPPER( customer. "Last mane” ) UW auttipte fields (descending state, ascending Last rane) Sevecr * FROM snugs:custoner ORDER BY custorer, "state 1d” DESC, custoner. “last mane” ASC 1 cateatoted Fretd: Iitpsiwwwzdbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him ang 80572018 xBase fo SOL. SELECT cust rane" ||", * | custoner."first mane" AS fullnane, ; Note that you cannot use the wildcard in conjunction with a calculated field, and the rowset will be read-only because of the calculated field, ‘SET RELATION ‘The XBase DML uses SET RELATION to determine relationships between tables, SQL can do related tables, but you will always get, with local tables, a read-only rowset. This can get quite complex. You need to use the SQL JOIN clause to relate tables, and there are a lot of options (INNER JOIN, OUTER JOIN ...) ‘The only place that this makes a lot of sense is if you are creating a report in dB2K (since the resulting query would be read-only anyway - reports don't generally write to the tables). The report engine actually doesn't handle some sets of tables very well (such as parent/child/arandchild or a master table with two (or more) detail tables). Using a SQL JOIN for these situations makes sense, For any forms that use multiple tables in dB2K you will want to use the OODML data objects (see other HOW TO documents in the Knowledgebase). It you must use SQL Joins, | recommend (and this is the only time | recommend this) that you use the SQL Designer to model your joins, and then extract the output SQL and simplify it as much as you can (the SQL Designer generates some fairly lonathy code, some of which may be unnecessary). ‘An example of an outer join used with three tables --a master table with two detall tables is (don't try this at home unless you actually have tables with these names and fields...) SELECT + FROM *Restprin.dbé® Testprin FULL OUTER 20IN "tartdets.dbF" Testaets. ON (Testprin.LinkField = TestdetdLinkField) FULL OUTER 30IN "testdet2.db6™ Testaet? ; ON (Testprin.LinkField = Testdet2,LinkField ) The tables would be linked using a field called "LinkField”, and the table names are "TestPrim" for the primary (parent) table, and "TestDet1” and "TestDet2" for “Test Detail 1" and "Test Detail TOTAL ‘The XBase DML TOTAL command creates a new table that contains totals for numeric fields in the original table you are totalling from. See the section below on calculations and aggregate functions. The local SQL command for this retums similar results USE In XBASE DML, to open a table, you use the "USE" command. In SQL the SELECT statement is how you open a table. ‘The SELECT statement is the one SQL statement you must know if you wish to use dB2K and the OODML properly. SQL Syntax: SELECT * | FROM ctablenane> 5 [oRDER BY [, ¢Fieldnane> ...J] 5 [wens ‘The “*" is a wildcard for the fields. Rather than selecting all felds in the table, you may wish to limit the field list. This can be done by listing each field you wish separated by commas. Examples’ SELECT * FROM :ob2¢Sanple fish SELECT mane, species FROM :d2¢Sample: fish Ifa field uses a SQL reserved word as the fieldname, or the field has spaces in the fieldname itself, you need to precede the field with the tablename, a dot, and put the fieldname in quotes, i... SELECT nae, fish. jength cn" FROM :ct2KSanple:fish itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him ong 80572018 xBase fo SOL. Calculated Fields You can create calculated fields with your SQL SELECT statement but as soon as you do this, your resulting table will be read-only. In addition, you cannot use the wildcard for “all fields" . SQL Syntax SELECT , AS FROW Assimple example of this might be to multiply the amount of items ordered in the Mugs examples lineitem table by 10 (the cost of each mug): SELECT gty, @ty*10 AS ondertotal FROH :mugs:lineiten ‘There are other calculations discussed later in this document that are "buil-in-to-SQL” calculations NOTE: You cannot use the fieldlist wildcard with a calculated field in the fieldist(i.e., you cannot use ", calcfield") Save To Itis possible to save a result query to another table using the optional SAVE TO clause. This can be useful with JOINS and other complex SELECTs. Using the calculation above as an example: SELECT Lineiten. "invoice ic", aty, qty"1@ AS ordertotal FROM :nugs:Linesten ; NOTE: This will save the table to the local directory, unless you add the BDE Alias to the output tablename. Once you have the output table, you can open it in an updateable way, but remember that the original. table(s) that this data has been pulled from will not be updated Other Options The SQL statement has many other options, some of which are discussed elsewhere throughout this document Very importantly, and one of the most powerful aspects of SQL, you can combine many of the options shown throughout this document into a single SELECT statement, Building such a statement can be a bit tricky, but you can do some pretty ‘complex things with one command using SQL. Zap ‘See the "DELETE" command earlier in this document. Misc. SQL Features Not Covered Above Unique Rows in a Table Ifyou wish to select all unique rows in a table using XBase, you must define an index tag that uses the UNIQUE operator. In SQL you can do this much easier, with a couple of drawbacks ‘SQL Syntax SELECT DISTINCT [, ...] FROM Problems: this will not allow you to select any fields except those you are checking for “uniqueness”. You can use multiple Sida nthe SELECT statement, ul the DISTINCT operator wil na comnatin of unique ves fr ta dorset Bo Example: 17 you wight want to use this to find all unique rows 77 based on the lost nawes of your custoners SELECT oISTINCT customer, Last mane” FROM snuge:custoner However, using a subquery, you could use this to actually get all ofthe fields (columns) in the customer table where the nique value you wanted was found: SELECT * FROM smugs:custoner WHERE custoner."last mane" IN ; (SELECT DISTINCT custorer."Iast name” FROM :mugs:custoner) ; itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him 1019 80572018 xBase fo SOL. ORDER BY custorer. “Last name SumiGroup By You may wish to total a field in a table. By itself this will generate a single-row, single column table that is read-only may also wish to group that total by some other field ~ this would be used to generate the total for all rows of that by" field, This calculation will also generate a read-only query. SQL Syntax: SELECT SUM( ) FROM SELECT , SUN ) FROM + (GROUP BY This will create a field called: SUM OF where is the name of the field you tell it to "sum". Examples (using the Mugs database's lineitem table): 1/ total of the qty Fleld ... -- one row, one field query SELECT SUM( qty) FROM smugs'Lineiten Uf return a total for each invoice: Seuser Tineitem, "invoice ig", SUM qty ) FROM mugs:linesten GROUP BY Linetten. “invoice id* U return a total for each ‘en: SELECT Lineiten."iten ie", SUM( qty ) FROM :mugs:2ineiten GROUP BY LineSten."iter id! Other Calculations In XBase, you have the CALCULATE command, in SQL you can simply add the following into a SELECT statement. The following include examples... MAX() SQL Syntax: SELECT HAX( ) FROM where is the name of the field you tell it to return the "max" of. Example: SELECT MAX( Fish.“length cn ) FROM :oB2KSanpLe: fish Ifyou want to see all of the fields in row that match this (and if you have multiple rows with the same value, all rows that match this), you could use a subquery (some details on these later in this document): SELECT * PROM :082KSample:fish WHERE fish."length cn? = (CSELECT MAXC Fish. "Jength cn”) FROM :€82KSanple: Fish ) MIN() SQL Syntax: SELECT MIN( ) FROM This will return the value of the field in question from the row with the smallest value in that field, This will create a field called: MIN OF where is the name of the field you tell it to return the "min" of. Example: SELECT MIN( Fish."“Length cm ) FROM :082KSanple:f3sh If you want to see all of the fields in row that match this (and if you have multiple rows with the same value, all rows that match this), you could use a subquery (some details on these later in this document): SELECT + FROM :0B2KSample:fish WHERE fish."length on” = 3 (SELECT MING Fish."Jength cn" ) FROM :aB2KSanple! fish ) AVG() SQL Syntax: SELECT AVG( cfleldnane> ) FROM itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him ane 80572018 xBase fo SOL. This will return the average of the values in the field. This will create a field called: AVG OF where is the name of the field you tell it to return the average of. Example: SELECT AVG( Fish. Length cn ) FROM :2B2KSanpe: Fish COUNT?) COUNT was discussed previously in this document under the COUNT heading, Subqueries ‘Subqueries can be used to limit the data returned in a query by comparing values against another table (or even in the ‘same table ~- see the calculations above). SQL Syntax SELECT * | FROM ctablenane> WHERE () ‘The subquery would be another SQL Select statement. ‘The subquery can use a special operator "EXISTS" to see if the value of the subquery exists in the main query created by the SELECT statement. Example (note that this uses the MUGS database): SELECT * FROM smugs:custoner WHERE EXISTS 5 (SELECT * FROM :mugs:Lavelce MHERE Invoice. "custoner 4d" Note that this is not getting data from the Invoice table, itis just comparing the customer table to find any rows that have a matching row in the invoice table, Ifa customer does not have any invoices, they will not appear in the result set. Multiple Tables In addition to the discussion of JOIN under the "SET RELATION" heading previously in this document, itis possible to ‘open multiple tables in a single query. The resulting query from this may be read-only, and it can produce some very unusual results. ‘SQL Syntax SELECT * | FON ctablenaneD>, 5 SELECT .cField>, . FROM; ablenawel>, SELECT , . FROM; ablenawel> , ‘The last statement shown in the syntax above is useful when working with a lot of fields from different tables ~ you assign an alias to the table by putting a space after the tablename (after the FROM clause) and the name of the alias. Examples: Ifyou browse this, you will see that for every record in FISH there is a record from SAMPLE. This can give you some very odd results This should give the exact same results as above except that it will only display two fields, one from each of the tables SELECT a.nane, b.sanple FROM :ab2Xsanple:fish a, :d82KSample:sanple b ‘And once again, this should give the same results as above, but the syntax is a bit easier to type, because of the use of the aliases. Note that the alias can be more than a single letter... (we could have used "TableA" and "TableB" or anything we wanted ...) itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him sano 80572018 xBase fo SOL. Creating Tables One of the most useful features of local SQL is the ability to create tables on the fly and to modify their structures (see below). You can create tables using the CREATE TABLE command in SQL: ‘SQL Syntax: CREATE TABLE ctablenane> ( ctyper(csize>) 2.) ‘This can get tricky ... The SQL types don't always map exactly to the field types in the table. The following two listings show all of the field types you can use, one for .DBF and the other for .DB (Paradox) tables, and how they map to the ‘appropriate table type: ‘SQL Field Maps for .DBFs ‘sau DBF [SMALLINT [Long INTEGER [Long [DECIMAL(Y) |[Numeric(XY) [NUMERICOCY)|[Numeric(XY) FLOAT(XY) _ [Double [CHAROS) [Character(x) [VARCHAR(Q)_|[Character(X) [DATE [Date BOOLEAN _|Losical |BLOB(x,1) [Memo BLOBG.2) [Binary [BL0B%.4) _OLe [TIMESTAMP __[TimeStamp [MONEY [Numeric(20,4) [AUTOINC __|[Autoincrement SQL Field Maps for DBs ‘SQL DB [SMALLINT _|[Short INTEGER _|[Long [DECIMAL(X.Y) [BCD INUMERICO ), and note that the keyfield must be the firs field in the table! A-simple example of the CREATE TABLE command: CREATE TABLE TEST (; Fist Wane" Char( 28 )s Last Nave” Char( 28) Notes” B1e8('18, 1) ) (The last field created would be a memo.) Modifying Table Structures The local SQL commands, in addition to allowing you to create tables on the fly via code, allow you to alter the structure of a table. The only modifications that can be done are by adding or deleting columns (fields) SQL Syntax: ALTER TABLE ctablenane> ; 09 (ctype>) | DROP ; [avo (ctypes) | DROP ... J You can stack the addidrop commands and you can mix them in the same SQL statement, The types are from the listings above. ‘There appears to be a problem with .DB tables and Autoincrement tables ~ you can create a new table with an autoincrement field, but you cannot add one to an already existing table. This limitation does not apply to .DBF tables. Date Formats According to the local SQL Help file provided by dBASE, Inc., Local SQL expects date literals to be in a U.S. date format ‘of month/day/year (either two or four digit ~ see below). To prevent date literals from being mistaken by the SQL parser for math (division) calculations, enclose your dates in quotation marks -- this keeps "1/23/1998" from being mistaken for 1 divided by 23 divided by 1998. Leading zeros for the month and day fields are optional Ifthe century is not specified for the year, the BDE setting FOURDIGITYEAR controls the century. If FOURDIGITYEAR is, sset to FALSE and the year is specified with only two digits, years 49 and less will be prefixed with 20 (i.e., 2049) and years of 50 or higher will be prefixed with 19, (This is much like using the SET EPOCH setting, set to 1950, in standard ‘BASE commands ...) To use a date outside of those bounds, specify the year in the date with all four digits More information from the Visual BASE newsgroups from those in countries other than the US, who have done some testing, show the following * Ifyour application uses European date formats (SET DATE GERMAN, SET DATE ITALIAN, etc.), and you need to use a literal date, always write the date with the day first as you are used to, and always use dots as separators: a.sql = (sete: fron ‘aytable.dbé' where ¢atun = '17.01,2999"] © Ifyour application uses US dates (SET DATE AMERICAN), and you need a literal date, always use the date with the month first, and always use slashes as the separator: 4g.sql = [select * fron ‘nytable.db¢" where datun = '1/27/1099"] Basically it appears that the separator marks (the slash or the dot) for dates tell the local SQL engine which version of the date to expect. Ifit sees the dot as the separator, it will assume that the date is European, and that the first characters (to the left of the dot) are the day of the month, and the next set of characters (between the two dots) are the month. if you se a slash, local SQL assumes that the date is in US date format, and that the first characters (lo the left of the slash) are the month, and the next set of characters (between the slashes) are the day of the month, In either case, the characters to the right of the second mark (dot or slash) are always the year, and can be either in two or four digit year format (see above...) Thanks to Ivar B, Jessen for detailing this out and hopefully shedding a bit more light on the subject String Functions ‘These functions can be used in WHERE clauses, field lists, ORDER BY clauses, and so on UPPER(), LOWER() ‘These two functions work exactly as the XDML/ABASE functions work. They convert the values to all upper or all ower htp:lwaw.dbase.com/KnowedgebaseINTixbase,to_sqlx2sqh.him sane 80572018 xBase fo SOL. case .. TRIM) ‘The TRIM() function has some parameters, the syntax is a bit different from the BASE version: SQL Syntax: TRING camattotrin> ("<3") FROM cFielénane> ) ‘The part is one of the following: LEADING Characters at the beginning of the field TRAILING Characters at the end of the field BOTH Characters at both ends of the field ‘The default character to trim is a space, but in the syntax listing above there is an optional character you can ask to have removed. An example of this might be a field where you had leading asterisks on the left of a number: SELECT TRIM( LEADING "*" FROM MyField ), NAME, otherfuelds FROM myTable ‘The use of the TRIM() function will retum a read-only query. SUBSTRING() Tris similar to he ASE SUBSTR( futon in that you must give a starting place and an ending pace, but in SAL the ‘SQL Syntax SUBSTRING( FROM FOR ) If you wanted to get the first three characters of the "NAME" field, you could use: 17 this will return the name field in one cotunm, and U1 the First three characters in the next, with the 77 second colum none being: *nane substring 1 SELECT name, SUGSTRING( nane FROM 1 FOR 3 ) from :oB2KSanple: fash As above, this will tum a read-only query, as we are creating a calculated field. Date Function 'n. BASE we have the day(), month), year) and various ater functions that can be used both on fields and other date ‘SQL uses the EXTRACT() function with some specific options. SQL Syntax: EXTRACT FROM ) Where is one of the following: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND. Example: // this will return the ‘custoner a" field, and Ua second field naned: “EXTRACT DAY FROM order. date’ SELECT inveice."custoner ic", EXTRACT( DAY FAOM invoice. order date" ) FROM :mugs:invoice ‘As with other calculated fields, this will generate a read-only query. CAST Function This function is a SQL function with no equivalent in dBASE XML (although VBASE 7.x will automatically cast some field types, depending on what you are doing). ‘The CAST function is used to convert the value in the specified field to the data type specified. CAST can be applied to literal and calculated values as well. It can be used in a WHERE clause, a columns list for the SELECT statement, or as part of an UPDATE statement. SQL Syntax: CAST( AS <éatatype> ) Iitpsiwwwzdbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him 159 80572018 xBase fo SOL. ‘The datatype parameter may be one of the standard types used by local SQL (CHAR, INTEGER, NUMERIC, and so on). You cannot use BLOB, MEMO or BYTEs fields as types to cast to or from, Converting a column value with CAST allows use of other functions on an otherwise incompatible type, such as using the ‘SUBSTRING function on a DATE field ‘When applied to the data retrieved through a SELECT statement the effect is temporary, and does not affect the actual “stored” data. When applied to an UPDATE statement the effect is permanent Memory Variable Substitution Itis offen necessary to insert a variable into your SQL Select statements, either in WHERE clauses, or what have you. ‘There are a couple of ways of doing this. Examples: SeLE ue Angelfish" TT * FROM 7882KSanple:fish WHERE nate ~ :evar Another possibility is to use quotes around the variable (for string or date comparisons): T+ FROM roB2kSanple:fish WHERE nare = "&eVar. ‘The reason for the macro above (see & in online help) is that local SQL needs to see a valid SQL statement and cannot evaluate the dBASE variable itself (inserting the macro causes dBASE to evaluate if before it gets passed along to the SQL parser). For dates, | recommend you use the parameter ~- it appears to work with less problems than trying to get a combination of ‘quotes and the value to be evaluated properiy. In the examples above, you can add wildcards and change the statements to use the LIKE clause, rather than the "= operator. NOTE: If you are using a SQL Select in a query object's sq/ property, you can set the value in the following manner: evar = “Blue Angelfish ° new guery() Gesal_ © [SELECT * FROM :a2KSomple:Fish WHERE name = “Teevare{”) 1 OR ~~ note: do not conbine the two of these! 4 Sew guery() Gesgl = [SELECT * FROM :ce2KSanple:fish WERE rane = :cVar] Giparans(.“evar® J = “Blue Angelfish ‘The use of the square brackets as delimiters is to make it easier to read the code above. A combination of single and double quotes is much harder to read than one with brackets and quotes. Back to the Command Window. You can also us Dates Note that SQL understands dates only as character strings. ‘An example of this is: SELECT * FROM smugs:invoice WHERE invoice."order date” See the section on date formats above. Logicals Use the words "true" or "false", and local SQL will understand a test for a logical value SELECT * FROM mytable WHERE nylogical = TRUE Using SQL With the OODML itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him 169 80572018 xBase fo SOL. One of the main reasons people wish to know more about SQL with dB2K is so that they can use SQL with the data objects that are part of the product, or what is called the OODML (Object Oriented Data Manipulation Language). ‘The statements discussed here can be used very similarly to the way they are shown, however, ifthe SQL statement would produce a read-only query as shown in the text above, then it will do so for the OODML. Query Object's SQL Property ‘The Query object is the data object seen first by most dBASE developers, as itis the way to open or access a table. Atit’s most basic, the query object must have three statements to work, and they must be in the sequence shown: queryane = new Query() // create an instance of a query ‘queryMame.sql.= “sone SQL stateent™ // the sgl. seLect Or what-have-you Gueryane.active = true // activate the query object ‘There is a lot more detail on the query object and other data objects in the HOW TO document comparing XBase to OODML in the Knowledgebase, but let's take a look You can use the WHERE clause here, if you desire to, but you may want to use the filter property of the rowset object (which is created when your query is activated). You may decide to use the WHERE clause here, and perhaps use the filer property for something else Very importantly when using the WHERE clause with a SQL select in a query object's SQL property, is getting the delimiters “just right". The SQL statement itself must be a character string. This means that you need to use nested delimiters, which can be hard to read. querylane sql = “select * from custoner where lastname = “Jones 1 4s harder to read than querylane.sql = (select * from custoner where lastname = “Jones"] ‘The second statement is easier to read, because the quotes don't get mixed up ~-a single quote next to a double quote is. very hard to determine what is what .. Ifyou need to use a variable, rather than a literal value as shown above, the syntax for the above will change ... ‘queryiane,sal~ [select * from custoner where Lastnane ~Joetanes("] Note that this embeds the quotes in the string and when the query's active statement is set to true, the string is evaluated properly. As noted elsewhere, date values require delimiters. Also as noted, numeric and logical values are handled as literals, 50 they do NOT need the quotes... queryane.sql = [select * from custoner where Custage > Tenage Wor: updated = false queryliane.sql = (select * from custoner where Updated = }sbUpdated You can use the fiter property of the rowset object to filter your data. This filter cannot be a dBASE expression, but instead must be a sql expression, as we've been examining them here (i.e, use the WHERE clause examples for i). However, one thing you should note, the SQL SELECT statement recognizes all of the LIKE options for the WHERE clause, which allows a lot of flexibility to extract data, using wildcards. The fiter property of the rowset does not recognize these options. Using the example shown above of a variable and the custAge field of the table: querytiane = new query() Gueryane.sql = “select * from custoner” 11 soneunere in your code. age = 22 ueryane.rowset.fllter = “Custage > “wnage Intpuiwwwzdbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him ame 80572018 xBase fo SOL. (Note that you can use the findKey() method, and more, in the rowset -- details in other HOW TO documents in the Knowledgebase). Indexing/Ordering Data ‘The biggest stickler when generating a query in local SQL is that the ORDER BY clause, unless you are ordering the data by only one field, nearly always creates a read-only query. Instead, you should use an index tag in your table, and then use the rowset’s indexName property: queryiiane = new query() Gueryane.sql = “select * from custoner” 77 this mist be ofter the active property is set to rue: Joins Joins are used to combine tables into a "virtual" table ~- these create, using local SQL, a read-only query. Ifyou need to set up your master/detall or parent/child relationships, you need to use the masterRowset/masterFields properties of the rowset, or if you are using tables that are not local (,DBF or .DB), then you would want to use the query object's masterSource property. ‘The only reason you might need a join in the OODML is for a report .. Details on these are in other documents in the Knowledgebase. Other Details ‘There is probably a lot more that can be discussed, but this is aimed at getting you started ... check out the local SQL online help fle, and ifall else fails, please use the newsgroups provided by dBASE, Inc. for assistance. The SQL Designer In dB2K there is a design surface that can be used to create .SQL files, or to simply model your SQL statements. ‘The only real drawback to using this is that the code it generates can be a bit lengthy: + Italways generates field lists, even if you select all fields in a table; ‘* Italways places the table name in front of each field (necessary or not); * Ifyou wish to actually use the SQL generated in any fashion other than a reference to the SQL file ( query-sq| "@mysql.sql") you must either add the semicolins to the end of each line generated, or you must put it ll into a single line (particularly if using it with the sal property of a query). On the positive side, the SQL designer is visual to an extent, and you can “run” the SQL generated and view the results in a browse window .. My personal opinion is that unless you are doing reports that require more than two relatedilinked tables, you probably never need to use the SQL Designer, and even then, use it to model the SQL, and then clean up the generated code. Summary This was more of an overview of SQL in Visual dBASE than a primer. There are options we have only touched on. While the implementation of SQL in the BDE is pretty good, in most situations in dB2K you will be better served to use the OODML. To that end, you should examine the HOW TO documents in the Knowledgebase. Unfortunately there are places in the OODML of dB2K where you are supposed to use SQL syntax for things, but the developers of dBASE didn't get all of the options set (fiters are an area that comes to mind quickly -- it would be nice to be able to use the LIKE clause with the wildcard options ...). Oh well. With some experimentation you should be able to ‘come up with what you need ... ‘Once again, thanks to Gary White, who provided me with an updated copy of the LOCALSQL help file produced by Inprise, and did some editing/review of the document as well. itp dbase,con/KnowledgebaselINTxbase_to_sqlix2sql.him sano 80572018 xBase fo SOL. DISCLAIMER: the author is an employee of dBASE, Inc., but has written this on his own time. If you have questions regarding this HOW document, or about dB2K you can communicate directly with the author and

Você também pode gostar