sql hacks using mysql server 5.0 ralfe poisson
DESCRIPTION
Retrieving SQL-Generated Data Some Usefule Static Functions in SQL mysql> SELECT CURRENT_USER, CURRENT_DATE, CURRENT_TIMESTAMP, VERSION(), RAND() ; Example | CURRENT_USER | CURRENT_DATE | CURRENT_TIMESTAMP | VERSION() | RAND() | | | | :56:09 | log | |TRANSCRIPT
SQL Hacks
Using MySQL Server 5.0
Ralfe Poisson http://www.ralfepoisson.com
Overview• Retrieving Structural Information
• Retrieving SQL-Generated Data
• Paging Output
• Calculating distance from GPS co-ordinates
• Generate All Possible Permutations
• Generate a Random Permutations
• Creating ASCII Graphs with pure SQL
• Creating a Calendar with pure SQL
• Google-Like Search Results
Retrieving SQL-Generated Data
Some Usefule Static Functions in SQL
mysql> SELECT CURRENT_USER, CURRENT_DATE, CURRENT_TIMESTAMP, VERSION(), RAND() ; Example
+--------------+--------------+---------------------+------------+-----------------+| CURRENT_USER | CURRENT_DATE | CURRENT_TIMESTAMP | VERSION() | RAND() |+--------------+--------------+---------------------+------------+-----------------+| ralfe@% | 2008-11-25 | 2008-11-25 09:56:09 | 5.0.44-log | 0.5004263757732 |+--------------+--------------+---------------------+------------+-----------------+
Getting Structural Information
MySQL makes provision for simple output of structural information:
• Listing Databases SHOW DATABASES
• Listing Tables SHOW TABLES
• Table Structure DESCRIBE `tablename`
• Command Used to Create Table SHOW CREATE TABLE `tablename`
Paging Output
It is possible to page the output of a SQL command by specifying an external tool. This can be a standard UNIX tool, or a custom script. You may also pass parameters to the tool/script.
Example
mysql> pager less ;
Calculating Distance from GPS data.
If we have a table of GPS co-ordinates, we can calculate the distance between them.
Step 1
CREATE TABLE `gps` ( `name` varchar(255) NOT NULL default '', `latitude` decimal(10,4) NOT NULL default 0, `longitude` decimal(10,4) NOT NULL default 0, PRIMARY KEY (`name`));
INSERT INTO `gps` VALUES ('Cybertek', 31.002010, -29.492991);INSERT INTO `gps` VALUES ('Pavilion', 30.560729, -29.505736);INSERT INTO `gps` VALUES ('Sydney', 151.133607, -33.514144);
Calculating Distance from GPS data
Step 2
Once we have set up our GPS co-oridnates in a table, we need to convert them to radians and store the Earth's radius as a constant. To do this we use a View:
CREATE VIEW `gps_rad` AS SELECT `name`, 3.14159265359 * `latitude` / 180 as 'lat', 3.14159265359 * `longitude` / 180 as 'lon', 6378 as 'R' FROM `gps`;
Calculating Distance from GPS data
Step 3
Using our friend, the Pytagorean Theorem, we can calculate the distance in kilometers..... MAGIC.
SELECT SQRT(dx * dx + dy * dy) FROM ( SELECT p1.R * (p2.lon - p1.lon) * COS(p1.lat) AS dx, p1.R * (p2.lat - p1.lat) AS dy FROM `gps_rad` p1 JOIN `gps_rad` p2 ON (p1.`name` = 'location 1' AND p2.`name` = 'location 2') ) t;
Calculating Distance from GPS data
End Result .... msyql> SELECT SQRT(dx * dx + dy * dy) AS distance FROM ( SELECT p1.R * (p2.lon - p1.lon) * COS(p1.lat) AS dx, p1.R * (p2.lat - p1.lat) AS dy FROM `gps_rad` p1 JOIN `gps_rad` p2 ON (p1.`name` = 'Cybertek' AND p2.`name` = 'Sydney') ) t ;
+-----------------+| distance |+-----------------+| 13378.204147479 |+-----------------+
Get all possible permutations
By using a cross-join (often done accidentally), SQL can generate all possible permutations of list items.
Example
You have two lists of names, and you want to setup a members schedule for Fight Club:
mysql> SELECT `names1`.`name` AS 'member', 'vs.', `names2`.`name` AS 'opponent' FROM `names1`, `names2`;
Generate a Random Permutation
Sometimes you want to generate a random pairing of field values.
Example
You suddenly need a random dance-off to get the party started:
Step 1 : Create a view of random entries
mysql> CREATE VIEW `rand_villians` AS SELECT `name` FROM `names2` ORDER BY RAND() LIMIT 5 ;
Generate a Random Permutation
Step 2 : Pair up the standard list with the random list.
mysql> SELECT `names1`.`name` AS 'member', 'vs.', `rand_villians`.`name` AS 'opponent' FROM `names1`, `rand_villians` GROUP BY `names1`.`name` ORDER BY RAND() LIMIT 1;
Sample Output
+--------+-----+-----------+| member | vs. | opponent |+--------+-----+-----------+| Edd | vs. | Brad Pitt |+--------+-----+-----------+
ASCII Art - Graphing with SQLWith a bit of (not-so-clever) trickery, we can generate vertical bar graphs of simple data sets using the REPEAT() function.
Example
mysql> SELECT `name`, REPEAT('#', `time`) FROM `race_times` ; +-----------+----------------------+| name | race_time |+-----------+----------------------+| Ralfe | ######## || Edd | #################### || Rodney | ########### || Matt | ###### || Karl | ##### || Richard | ##### |+-----------+----------------------+
Sorting Email
Sometimes, it is handy to group email addresses by their domain names. This would enable to, for example, allow you to see all email addresses from a particular company.
Example
msyql> SELECT SUBSTRING(`e` FROM POSITION('@' IN `e`) + 1) as domain, SUBSTRING(`e` FROM 1 FOR POSITION('@' IN `e`) -1) as account FROM `email` ORDER BY domain, account ;
SQL Calendar
In this more advanced hack, we will use a table of events to output a nicely formatted tabular calendar using only SQL.
Step 1
Create the table that holds the event data.
mysql> CREATE TABLE `bookings` ( `date` date, `name` varchar(30)) ;
INSERT INTO `bookings` VALUES('2008-11-28', "Ralfe") ;INSERT INTO `bookings` VALUES('2008-11-29', "Karl") ;
SQL Calendar
Step 2
– Setup a view with the first day of the month (to use as a reference point).
CREATE VIEW dayOne AS SELECT DATE '2008-11-01' AS first;
– Create a table with all days of the month in it.
CREATE TABLE `cal` (`d` DATE);– Create a VIEW with the week beginings.
CREATE VIEW weekBeginning ASSELECT DAYOFMONTH(`d`) - DAYOFWEEK(`d`) AS wkFROM `cal` JOIN dayOneON (MONTH(`d`) = MONTH(first))GROUP BY wk;
SQL Calendar
Step 3
Create a Calendar Grid in the form of a VIEW
mysql> CREATE VIEW `calGrid` AS SELECT wk, first + INTERVAL wk + 0 DAY AS Sun, first + INTERVAL wk + 1 DAY AS Mon, first + INTERVAL wk + 2 DAY AS Tue, first + INTERVAL wk + 3 DAY AS Wed, first + INTERVAL wk + 4 DAY AS Thu, first + INTERVAL wk + 5 DAY AS Fri, first + INTERVAL wk + 6 DAY AS Sat FROM `weekBeginning` CROSS JOIN `dayOne` ;
SQL CalendarStep 4 (the last one, I promise)
Overlay the event data over your calendar grid.
mysql> SELECTCOALESCE((SELECT name FROM bookings WHERE date=Sun),DAYOFMONTH(Sun)) AS Sun,COALESCE((SELECT name FROM bookings WHERE date=Mon),DAYOFMONTH(Mon)) AS Mon,COALESCE((SELECT name FROM bookings WHERE date=Tue),DAYOFMONTH(Tue)) AS Tue,COALESCE((SELECT name FROM bookings WHERE date=Wed),DAYOFMONTH(Wed)) AS Wed,COALESCE((SELECT name FROM bookings WHERE date=Thu),DAYOFMONTH(Thu)) AS Thu,COALESCE((SELECT name FROM bookings WHERE date=Fri),DAYOFMONTH(Fri)) AS Fri,COALESCE((SELECT name FROM bookings WHERE date=Sat),DAYOFMONTH(Sat)) AS SatFROM `calGrid`ORDER BY `wk` ;
SQL Calendar
The End Result ...
+------+------+------+------+------+-------+------+| Sun | Mon | Tue | Wed | Thu | Fri | Sat |+------+------+------+------+------+-------+------+| 26 | 27 | 28 | 29 | 30 | 31 | 1 || 2 | 3 | 4 | 5 | 6 | 7 | 8 || 9 | 10 | 11 | 12 | 13 | 14 | 15 || 16 | 17 | 18 | 19 | 20 | 21 | 22 || 23 | 24 | 25 | 26 | 27 | Ralfe | Karl || 30 | 1 | 2 | 3 | 4 | 5 | 6 |+------+------+------+------+------+-------+------+
Magical
Google-like Search Rankings
Returning results from a string comparison can be quite meaningless most of the time.
Often, there is little or no meaning implied within the result set.
Introducing the wonders of SQL
MATCH() AGAINS()
Google-like Search Results
Step 1
Set up your data table.
myqsl> CREATE TABLE `books` ( `author` varchar(100), `blerb` varchar(1000) ) ;
Google-like Search Results
Step 2
In order to do a FULLTEXT pattern match in MySQL, we will first need to create a FULLTEXT index on the field we want to match against. Examplemysql> ALTER TABLE `books` ADD FULLTEXT(`blerb`) ;
Coogle-like Search Results
Step 3
Construct Your Search Query.
Example
Searching for "database systems"
mysql> SELECT `author`, MATCH (`blerb`) AGAINST ('database systems')FROM `books`ORDER BY 2 DESC;
Google-like Search Results
The End Result ....
+---------------------+-----------------+| author | relevance |+---------------------+-----------------+| Atzeni | 1.3253291845322 || Adams | 0 || Russell and Cumming | 0 |+---------------------+-----------------+
References
Cumming, A. and Russel, G, 2007. "SQL Hacks: Tips & Tools for Digging into Your Data"Mike Chirico, "MySQL Tips", 2007,http://souptonuts.sourceforge.net/readme_mysql.htm
"Code Idol", 2008,http://codeidol.com/sql/sql-hack/Number-Crunching/Calculate-the-Distance-Between-GPS-Locations/