Character set, Collation

Here is an interesting challenge that I ran into in the Data Warehouse environment. While debugging a particular business user query, I joined between a string built in a sub-query to a column in a particular fact table with some 20million rows. BTW, I was using MySQL 5.0 and Toad 4.5 to run this query and instead of getting any result I got the following error!

MySQL Database Error: Illegal mix of collations (utf8_general_ci,COERCIBLE) and (latin1_swedish_ci,IMPLICIT) for operation '='    22    0

The query was simple and similar to
SELECT s.str, s.d1, s.d2
FROM (
    SELECT distinct 'string' str, dimension1 d1, dimension 2 d2
    FROM table_1
    WHERE ...
) s
LEFT OUTER JOIN table_2 t2
ON ...
WHERE s.str = t2.str
AND ...


Regular Expressions

MySQL regular expressions (RE) are a powerful tools that can be very useful in SQL string searches. They enable software engineer to build statements that are very concise and to handle complex string operations that otherwise wouldn't be possible.

If you are new to regular expressions or would like to know more about them, http://www.regular-expressions.info/ is a good site to visit. You can also get a RE tutorial at net|tuts+. Following is quick list of meta characters that can get you started in using them.

. => A dot matches single character
* => An asterisk matches zero or more of previous matched tokens
? => A question mark matches zero or one time the previous matched token
$ => A dollar at the end anchors the search to the end of string
^ => A caret symbol anchors the search to the beginning of the string
| => A pipe matches either of the two. Example: abc|xyz => either 'abc' or 'xyz'
{m,n} => A quantifier matching between 'm' and 'n' times. m & n are integers.

Different computer languages have some variations when it comes to more advanced searches and how they handle given character sets. MySQL uses REGEXP string function to implement and matches the string in case "in-sensitive" mode and to match otherwise see this blog.


MySQL User Defined Variable

This is a brief introduction to user defined variables in MySQL as many times I have gotten queries regarding how to use them in dynamic queries.

In MySQL you can easily create user defined variable and use it through out that particular session or client connection. A variable is a alphanumeric characters following a "@". In the versions 5 and above the name is case-insensitive and hence @VAR, @vaR all mean the same. For example:

set @var = 1;

The above statement creates a variable called "var" and sets it to 1. Also note you don't need to declare it before using it.

The statement,

set @var1 = 1, @var2 = 2, @var3 = 3;

sets all three variables in single statement. You can then select the variables from

select @var1, @var2, @var3;

Now, let us say that you would like to select particular row(s) from a given table. To do so you need to first build the sql string, prepare it and then execute it. This allows you to pass the variables one or more times to the same statement.

For this let us assume we have a table (table_t) that has two columns - id and name and has 3 rows (1, 'one'), (2, 'two') and (3, 'three'). To select row with id = 1

set @var = 1;
set @st = concat('select id, name from table_t where id = ', @var);
prepare stmt from @st;
execute stmt ;

And to select with string variable like names you need to escape the single quote as below.

set @var = 'one'
set @st = concat('select id, name from table_t where name = ', '''', @var, '''');
prepare stmt from @st;
execute stmt ;

This is a trivial example but you get the idea of how to use user defined variables. The same technique can be used to build more complex stored procedures and statements that are executed often with different variables.

Cheers,
Shiva




Case Sensitive SQL Search

MySQL on default installation uses the case insensitive configuration meaning the data you stored and searched will not be case sensitive.
Let us first check our current server and database's appropariate variables.

SHOW VARIABLES
WHERE variable_name = 'character_set_server'
> latin1
SHOW VARIABLES
WHERE variable_name = 'collation_database'
> latin1_swedish_ci

Since we are using latin based language settings, the cases are different unlike some languages that don't have cases. And with the database collation set to latin_swedish_ci the string search will be case insensitive (ci).

For this illustration, I have created a table "country" with single column "country_name" and inserted 3 rows.
CREATE TABLE country (
     country_name varchar(32) NOT NULL
);
INSERT INTO country
VALUES ('US'), ('UK'), ('ukraine')
; 
COMMIT;

Google Docs Spreadsheet - Better access control needed

I use Google docs to maintain many documentations for a non-profit organization and this has been a very useful, money & time saving application. In my view, following three features will immediately enhance what is already a excellent collaborative product.  These are low-hanging fruits.
  • User access control at worksheet level to view
  • Copying more than 1000 (one thousand cells) at a time
  • Multi-column sorting
In our non-profit organization we have multiple chapters controlling their own documents/ spreadsheets and some times there are situations where I would like to have a single spreadsheet but each work sheet is visible only to a particular chapter or member. For example, a common spreadsheet with 50 worksheets (one for each US state) should appropriately be visible to these chapters.  A California chapter can view California worksheet only and not others.

Currently, I can control the editing access through "Protect Sheet" but not the viewing. See below.

Best of Google homepage logos over the years

Google modifies their home page by including birthdays of some major personalities around the world or major events. Here are some of the best, unique and presented in more than one country. The list below is not any particular order.

2009.05.20 - Charles Darwin Birthday



2009.11.13 - Water on Moon found


2009.10.02 - Mahatma Gandhi




Introduction and using MySQL Explain

Like in any database query optimization is critical for MySQL data warehouse environment and having a better understanding of the "Explain plan" helps the database application developer avoiding issues with query  performance. Also, DBAs will like your queries and they would be more than happy to help you optimize them.

MySQL's "Explain" statement provides details on query parsing and execution steps and outputs 10 fields -
id, select_type, table, type, possible_keys, key, key_len, ref, rows and Extra columns.

You run the statement by issuing
explain <sql query> #-- Insert your query between < and >. 

Shown below is the Toad's output of explain plan of a self-joined table's query with where clause. The table has around 20million rows. The query took less than 0.6seconds to index through ~70K rows and with "const" and a func (date_add function) to compare between one days data to its previous day data.

SELECT a.ad_date, a.unit_id, a.max_cpc, 
               SUM(coalesce(a.max_cpc, a.max_cpc) - coalesce(b.max_cpc, a.max_cpc)) diff_cpc
       FROM  sem_kw_summary a
       LEFT JOIN  sem_kw_summary b
           ON  date_add(a.ad_date, INTERVAL -1 day)  = b.ad_date
           AND a.unit_id = b.unit_id
       WHERE date_add(CURRENT_DATE, INTERVAL -1 day) = a.ad_date
         AND a.engine = 'google'
       GROUP BY a.ad_date,  a.unit_id