Tips_todo   >   Sql   >   SQL Misc

SQL Misc

This section contains information on miscellenous SQL topics.

Begin SQL Text

; @MOD:1 Modified method to reopen multiple main window instances if they exist. ;; 2005-09-22 Doug K per Andy HOmnis Studio provide a handy set of Omnis commands for preparing lengthly SQL scripts. The following sample code shows how you can use the SQL script set of Omnis commands.

Begin critical block
Begin SQL script
SQL: SELECT SUM(tsheet_Hours)
SQL: FROM tsheet
SQL: WHERE tsheet_Date >= @[DateFrom]
SQL: AND tsheet_Date <= @[DateTo]
SQL: AND tsheet_emp_Serial = IN ([InClause])
End SQL script
Get SQL script {SQLText}
End critical block

Reading the SQL text code in the above format is much easier than a lengthy con() function and it saves you from having to type all of those double quotes and commas around the characters and variables in the con() function.

The SQL script Omnis commands are global so if you want to be extra careful you should enclose each SQL script group in a Begin/End critical block to safeguard against multi-threading issues.

Connecting Records

In SQL you are responsible for maintaining your own record connections. Coming from DML that seemed like extra work, but very quickly I started liking having control over the record connections. It got real easy when I added a table class methods called $setLinks(ParentRow) and $getSiblings(ParentRow).

NULLS

There are some people that like NULLS, others dislike them.

NULLS are important for statistics. A NULL value won't affect the average, whereas a ZERO value does affect the average.

Let's say you are doing a survey of households, and a person leaves the question asking for their annual income blank. In the database NULL is better than ZERO because you can calculate a valid average household income on all the records, since the NULLS won't be included in the average. (Zero are included.)
However if you calcluate a A as B*C, and B or C is NULL your result 'A' will be NULL. That can be a real problem when calculating invoices!

So you need to be very careful with NULLS.

Generally I don't want NULL values in my records so in my base superclass table class I have a $setNullsToBlank method which loops through the boolean, number, and integer columns in the current line and sets any NULL values to zero.

With real RDBMSs empty dates must be NULL and empty foreign key columns must be NULL, they can not be "empty" or "zero".

SQL Assist

SQL Assist is a utility, currently available with the subscriber version of StudioTips. SQL Assist was written to make it easier for developers (like me) who aren't familiar with SQL syntax. SQL Assist generates SQL scripts for creating and modifying SQL server tables from your schema classes.

There are various features in SQL Assist to help you move from OmnisDML to OmnisSQL.

See Utilities > SQL Assist for more information.

SQL Browser

I found the SQL Browser to be marginally helpful when I was learning SQL. At times it was counter productive to the learning process. I found the interface is a bit clunky and buggy. (that was v1.2).

I still use the SQL Browser from time to time to look at the server tables.

When I was learning SQL, I used the SQL browser to create my first few SQL tables. But I knew that if I wanted to recreate my tables in another database I would be better off storing my SQL server table columns and indexes information somewhere and write code to prepare the CREATE TABLE statements from that stored information.

I created a parent table called 'sqltable' and a child table called 'sqlcols' and entered by SQL table and related columns in those tables. This worked fine, but there was a catch. The SQL table/column data had to be stored in a separate data file, because if I wanted to start a new data file, where would the SQL table data be? Heaven forbid if I lost the data file with my SQL table definitions.

2 years later I read an Omnis list server posting by Reg Paling where he mentioned he was storing his SQL table information in the file classes. I tested the idea and found that to be a much better way. See the topic 'File Classes' for more information.

In StudioWorks I moved away from the file classes and am now storing the information about indexes and foreign keys using special @TAGs in the description column of the schema class. The SQL Assist utility helps with the creation of @TAGs in the schema class column descriptions.

SQL Problem Solving

If you are new to SQL (like me) it's easy to hit a problem that baffles you for hours. This section covers a couple of head scratchers that have had me or other stumped. If you have any to add to this list, be sure to email them to me.

SQL ERROR HANDLER

It's a good idea to add a $sqlerror handler method in your base superclass table class.

If you put a "Calculate Row as $cinst" and "Get SQL script {#S1})" followed by a permanent 'Breakpoint' in the $sqlerror handler method you will be able to catch and analyze any SQL errors. See the t_Base table class in StudioTips for the $sqlerror handler method I use. It's not fancy but it helps me out when I hit SQL errors. Feel free to copy and modify it.

YOU CAN INSERT AND DELETE RECORDS BUT CAN'T UPDATE OLD RECORDS

1. Check the Schema class. You MUST have a primary key (Unique field field). And it must be set it to kTrue.
2. Makes sure you are sending the OldRow as a parameter. Row.$update(OldRow)

YOU CAN INSERT ONE RECORD, BUT CAN'T INSERT A SECOND RECORD

1. The second record doesn't have a unique value for field(s) in that table which require unique values.

YOU CAN'T INSESRT ANY RECORDS

1. Are you logged onto the data file?
2. Do you have a session and cursor? And is it the right one?
3. Is one of the columns in the record a NULL value for a column set to No Nulls?

FETCH ONLY BRINGS BACK ONE RECORD TO THE LIST

1. You must specify the number or records to $fetch. Use $fetch(kFetchAll). $fetch() only gets 1 record.
2. $fetch(kFetchAll) only brings back 1 record. If you did a $fetch() before, the list.$linemax will be 1.

FIELD REFERENCE PARAMETERS IN TABLE CLASS METHODS

Passing 'Field Reference' parameters to a table class method can give you problems.

Floris Buyse ran into quite a 'hair puller' when 'Do default' refused to work in the table class method. After looking through the code, I noticed the call to the table class method was:

Do pRow.$update(ivRowOLD) ;; pRow is a field reference parameter
Changing pRow from a field reference parameter to a row parameter solved the problem.

I caught the problem because I too have had odd things happen when I passed field reference type parameters to table class methods.

SELECT FOR UPDATE USING ONE CURSOR

OmnisSQL has no transaction management, ie rollback capability, and I'm using optimistic record locking, only locking records at the last moment to do the update. It made sense to me to lock the parent record at the start with a Select ... For Update, then process all the child records, and finally update the parent record at the end, unlocking with a "Where Current Of.." update statement. For some reason Studio started crashing on both Mac and Windows platforms. I finally realized it was because I was attempting to do this all in one cursor and YOU CAN'T DO THAT. Mac's have a Type 1 error, Windows NT popped up Dr. Watson.

So the fix was to Select ... For Update, change to a new cursor, update the child records, change back to the original cursor and do the Update ... Where Current Of.

Thanks to Michael Houlberg for this tip.

USING SQL RESERVED WORDS FOR COLUMN NAMES

Using SQL Reserved Words for column names will give you troubles. While I was creating an email module I used the words "To" and "From" as column names. The CREATE TABLE statement would not execute. Looking at the back of the Omnis Programming Manual (blue on) I soon found the problem. "To" and "From" are SQL reserved words.

SINGLE OR DOUBLE QUOTE CHARACTER (' OR ") IN SELECT COMPARISON VALUE

If you are trying to select LastName = O'Sullivan, the single quote character can give you grief. Use of bind variables will eliminate the problem. Another solution is to replace all the single and double quote characters with underscore characters so that "LastName = O_Sullivan". In SQL the underscore character is a single character wildcard.