mysql – Terminally Incoherent http://www.terminally-incoherent.com/blog I will not fix your computer. Wed, 05 Jan 2022 03:54:09 +0000 en-US hourly 1 https://wordpress.org/?v=4.7.26 MySQL: Conditional Update http://www.terminally-incoherent.com/blog/2009/10/05/mysql-conditional-update/ http://www.terminally-incoherent.com/blog/2009/10/05/mysql-conditional-update/#comments Mon, 05 Oct 2009 14:15:09 +0000 http://www.terminally-incoherent.com/blog/?p=3893 Continue reading ]]> You learn something new every day. Here is a neat little SQL trick that I just learned. As usual, this post is mostly here for my future reference, and of course the overall good of the humankind. I hope someone will find it helpful. If not, however I apologize for being boring. You know, I think I got into blogging for two reasons. One of these reasons was to have an outlet where I could complain about “the fucking lusers” that I was dealing with on a daily basis. The other reason was to provide a reliable and searchable long term repository for knowledge tidbits I was picking up here and there. You know, like that awesome command line trick that I use once every two years, or some SQL acrobatics that I spent 4 hours assembling together to fit a very specific problem. I found that no matter how obscure a problem is, chances are that it will come up again at some point so it pays to keep notes.

The problem for today goes like this: there is a table in the database, and it has a field foo that holds some information. The field is initially NULL, and there is an update query that changes it to ‘bar’ when the user does something. But we want to update foo only when it’s NULL and leave it alone otherwise. In other words, if it already contains the value ‘baz’ we want to keep it the way it is.

The challenge? Do it without modifying any existing logic, and without introducing a second query to look up the value of foo. How to we accomplish this by simply modifying the existing update query? It’s easy – just use the built in MySQL branching IF statement like this:

UPDATE mytable 
SET foo= IF(foo IS NULL, 'bar', foo)
WHERE id='69'

This will test whether or not foo is NULL, and then set it to ‘bar’ if it is, or re-set it to whatever it is right now otherwise. Now this may seem wasteful (ie. the update on false condition) but imagine this update statement actually sets not just foo but a number of different fields like this:

UPDATE mytable 
SET 
   foo= IF(foo IS NULL, '1', foo),
   bar = '2',
   baz = IF(baz > '10', 'high', 'low')
WHERE id='69'

You can do all kinds of behind-the-scenes magic with a query like that, and make it as simple or as complex as you want.

Anyways, if this post bored you to tears, I apologize. Stuff like this will crop up here every once in a while though. It’s just a fact of life.

]]>
http://www.terminally-incoherent.com/blog/2009/10/05/mysql-conditional-update/feed/ 4
MySQL: Find Duplicate Entries in a Table http://www.terminally-incoherent.com/blog/2007/09/19/mysql-find-duplicate-entries-in-a-table/ http://www.terminally-incoherent.com/blog/2007/09/19/mysql-find-duplicate-entries-in-a-table/#comments Wed, 19 Sep 2007 17:17:28 +0000 http://www.terminally-incoherent.com/blog/2007/09/19/mysql-find-duplicate-entries-in-a-table/ Continue reading ]]> Here is a little background for this issue. The database used to run on ancient copy of MySQL until very recently we upgraded it to 5.0. Not without some headaches of migrating the database, but it worked. Common problem we had with this database was duplicate entries in printed reports. Why did these happen? Mostly because of user error combined with a lack of foreign key constraints.

The two MyIsam tables that were causing the issue were: report and proforma. Both were used for tracking documents through the review process. Report was the actual field audit report that would be submitted, reviewed and sent to the clients, while proforma was the documentation of expenses that our employees were supposed to submit for each assignment. Both would store dates, comments, notes and other info regarding said documents. The proforma had a 1-1 relationship with report (each proforma was tied to a single report entry). But since the old MySQL version did not support Foreign Key constraints this was not enforced (or rather only enforced by the PHP front end).

However users would continuously find ways to submit multiple proformas for the same report – for example by clicking the “submit” button 7 times. Other fun trick for re-submitting proforma was to send it in as TBA (to be annouced). Upon seeing the TBA the clerical staff in the office would manually associate it with appropriate report, usually without checking if another copy is already in the database. And when we locked that down, they would just continuously send bug reports about it forcing us to sort this out at the DB level.

What happened if the non-existent FK constraint was violated? One of the main reporting sections of the site used a complex join across these two tables. If there were two or more proformas per report, that report would show up on the list multiple times. What do people do when they see duplicates on the list? They start deleting them. Problem is – these were not real duplicates, but the same entry repeated several times. Deleting one copy would hose all of them, causing yet more support request for restoring the entry from the nightly DB dump.

Fun times. So after we switched to a DB engine that was actually developed in this century I immediately switched the tables to InnoDB and put a freaking foreign key constraint on that relationship. This way if someone finds a new loophole in the PHP code they will end up seeing a nice MySQL error instead of creating new duplicates.

But guess what – I just got more bug reports about duplicate entries. Apparently the FK constraint is not retroactive, and MySQL will gleefully allow duplicate keys to exist in your FK column when you apply the constraint. I figured that it would start trashing about and keep giving me errors if that was the case, but no – all it cared about was an index on the key column. So I was left with a task to track down all the duplicate entries in the foreign key column in my proforma table. How do I do this? This problem actually got me scratching my head for a bit, until I had a sudden epiphany:

SELECT 
	id, report_id, count(*)
FROM
	proforma
HAVING
	count(*)>1

I found around 17 separate instances of the foreign key (here report_id) being repeated anywhere from 2 to 8 times. All of these were for older entries that no longer show up on the first page of results, so naturally no one noticed. Still, it shows that the problem was more prevalent than we initially suspected.

What I’m really trying to say here is this: use database constraints to enforce table relationships. This is the only proper and effective way to do it. Trying to enforce constraints in software is just asking for trouble as you create multiple points of failure. Different parts of the code will update any given table at different times, and all of them must check this. Failing to implement proper checks in every piece of code that touches that table may lead to duplicate entries in FK columns and similar undesired side effects. A simple constraint on a column will stop this from happening much more effectively, with much less effort.

[tags]mysql, sql, database, database design, foreign key, key, constraint, php[/tags]

]]>
http://www.terminally-incoherent.com/blog/2007/09/19/mysql-find-duplicate-entries-in-a-table/feed/ 4
MySQL Admin 1.0.19: libmysqlx.dll Error http://www.terminally-incoherent.com/blog/2007/09/12/mysql-admin-1019-libmysqlxdll-error/ http://www.terminally-incoherent.com/blog/2007/09/12/mysql-admin-1019-libmysqlxdll-error/#respond Wed, 12 Sep 2007 15:45:22 +0000 http://www.terminally-incoherent.com/blog/2007/09/12/mysql-admin-1019-libmysqlxdll-error/ Continue reading ]]> I noticed that on one of the servers the MySQL Admin was behaving weird. When you tried to inspect the schema of some tables by double clicking on it’s icon it would generate the following error:

Access violation at address [address in hex] in module ‘libmysqlx.dll’. Read of address 00000000

Here is a screenshot of the error dialog:

MySQL Admin Error

Some tables would trigger this error, while some others wouldn’t. Quick investigation revealed that this server was recently upgraded to MySQL Server 5.0. The MySQL Admin apparently was not upgraded and was still at version 1.0.19. I checked the most recent builds of MySQL GUI tools and the version of the Admin application in the bundle was 1.2.12.

I upgraded the package, and the error went away. Apparently the error was caused by some kind of mismatch between what the database was actually doing vs what the old version of Admin expected it to do.

I saw this error being posted in several places online so I figured I will put it here and provide a definite solution: upgrade to the most recent version of MySQL Administrator.

In before “real men use the command line client… On linux!” – I do too. But MySQL Admin is sometimes useful for setting up db dumps, or quickly changing table settings that I don’t remember SQL commands for (like encoding for example). Plus, I can’t stand when shit is not working – even if it’s something I don’t use very often.

[tags]mysql, sql, mysql administrator, mysql gui tools, gui tools[/tags]

]]>
http://www.terminally-incoherent.com/blog/2007/09/12/mysql-admin-1019-libmysqlxdll-error/feed/ 0
MySQL: Error 1005 Can’t create table (errno: 150) http://www.terminally-incoherent.com/blog/2007/07/09/mysql-error-1005-can%e2%80%99t-create-table-errno-150/ http://www.terminally-incoherent.com/blog/2007/07/09/mysql-error-1005-can%e2%80%99t-create-table-errno-150/#comments Mon, 09 Jul 2007 18:57:41 +0000 http://www.terminally-incoherent.com/blog/2007/07/09/mysql-error-1005-can%e2%80%99t-create-table-errno-150/ Continue reading ]]> This error has been driving me insane all morning. Every time I was trying to create a new InnoDB table with a foreign key constraint I would get the following error:

Error 1005 Can’t create table ‘.\mydb\#company.frm’ (errno: 150)

My SQL looked something like this:

CREATE TABLE company (
	`id` int(32) auto_increment NOT NULL,
	`name` varchar(50),
	`cfo` varchar(50),
	`ceo` varchar(50),
	`address` text,
	`tel` varchar(15),
	`fax` varchar(15),
	`email` varchar(50),
	`general_type` enum('broker', 'manufacturer', 'wholesaler', 'service', 'distributor', 'retailer', 'healthcare', 'processor'),
	`specific_type` varchar(50),
	`lender_id` int(32),
	PRIMARY KEY (id),
	CONSTRAINT `fk_lender` FOREIGN KEY (`lender_id`) REFERENCES `client` (`lender_id`) ON UPDATE CASCADE,
  	CONSTRAINT `fk_specific_type` FOREIGN KEY (`specific_type`) REFERENCES `specific_type` (`specific_type`) ON UPDATE CASCADE
) ENGINE = InnoDB

I kept getting that damn error every single time. At first I figured this was a OS level file access permission issue. But this is not the case – it is just a silly, misleading message. I started googling for it and found some good tips on how to avoid this error at VerySimple Dev Blog. I spent over two hours testing all possible solutions listed in that post. Both tables – client and specific_type were InnoDB. The respective keys were the same type. The charset and collate attributes were set to default in both. And then it hit me.

It turns out that my problem was simple – you need to have an index on every field that will be a foreign key. I kinda figured that this would happen automatically, like with primary key, but it doesn’t. You need to create the index manually. My updated query looks like this:

CREATE TABLE `company` (
	`id` int(32) NOT NULL auto_increment,
	`name` varchar(50),
	`cfo` varchar(50),
	`ceo` varchar(50),
	`address` text,
	`city` varchar(50),
	`state` varchar(50),
	`zip` char(2),
	`tel` varchar(15),
	`fax` varchar(15),
	`email` varchar(50),
	`general_type` enum('broker','manufacturer','wholesaler','service','distributor','ret ailer','healthcare','processor') NOT NULL default 'broker',
	`specific_type` varchar(50) NOT NULL,
	`lender_id` int(32) NOT NULL,
	PRIMARY KEY  (`id`),
	KEY `specific_type` (`specific_type`),
	KEY `lender_id` (`lender_id`),
	CONSTRAINT `fk_lender` FOREIGN KEY (`lender_id`) REFERENCES `client` (`id`) ON UPDATE CASCADE,
	CONSTRAINT `fk_specific_type` FOREIGN KEY (`specific_type`) REFERENCES `specific_type` (`specific_type`) ON UPDATE CASCADE
) TYPE=InnoDB

Somehow this escaped my attention. It’s probably because lately was I simply adding foreign key constraints to existing tables after converting them to InnoDB from MyIsam. It worked fine because in most cases these tables already had indexes on the “foreign key” fields – there were just no constraints there.

So next time you are creating a InnoDB table, remember – put index on every field that will become a foreign key, unless of course you like to deal with overly cryptic error messages.

Update 07/09/2007 07:45:04 PM

I just tested this on MySQL 5.0 and the lack of index doesn’t cause this error. So one way to avoid a major headache is to upgrade to 5.0 or higher.

Here is one more tip I discovered when debugging this stuff – whenever you get the 1005 error, run the following SQL statement from the console:

show InnoDB status

You will get a very verbose report on the status of your tables – and one of the sections of this report is LATEST FOREIGN KEY ERROR. Locate that section and you might find out what exactly is wrong with your statement.

[tags]mysql, error 1005, errno 150, can’t create table, database, mysql error, innodb, foreign key[/tags]

]]>
http://www.terminally-incoherent.com/blog/2007/07/09/mysql-error-1005-can%e2%80%99t-create-table-errno-150/feed/ 5
DST Readines Test for MySQL and PHP http://www.terminally-incoherent.com/blog/2007/03/09/dst-readines-test-for-mysql-and-php/ http://www.terminally-incoherent.com/blog/2007/03/09/dst-readines-test-for-mysql-and-php/#comments Fri, 09 Mar 2007 18:00:15 +0000 http://www.terminally-incoherent.com/blog/2007/03/09/dst-readines-test-for-mysql-and-php/ Continue reading ]]> Here is a quick and dirty way to see if the “MP” part of your LAMP or WIMP solution is ready for the DST time change. I tested all the production systems here today, and they seem to be working just fine. Here is what you do.

First let’s test MySQL:

SELECT UNIX_TIMESTAMP('2007-03-11 02:00:00')=UNIX_TIMESTAMP('2007-03-11 03:00:00');

The two timestamps should be identical, because of the DST change. So this query should return 1 (one, uno, jeden). If you get anything else, your MySQL is b0rked and you need to patch it.

Same method can be applied for PHP. Paste this code in somewhere and then look at the page:

<?php echo mktime(2, 0, 0, 3, 11, 2007) == mktime(3, 0, 0, 3, 11, 2007); ?>

If you get 1, you are good. Anything else, and you are in a need of a patch.

Note, by default both MySQL and PHP will grab the time from OS so unless you specifically messed with their configuration to change this, chances are you will be just fine. Still, it’s always good idea to check.

[tags]dst, mysql, php, daylight saving time, time change, timestamp[/tags]

]]>
http://www.terminally-incoherent.com/blog/2007/03/09/dst-readines-test-for-mysql-and-php/feed/ 3
MySQL no Longer Provides Free Binaries http://www.terminally-incoherent.com/blog/2006/12/30/mysql-no-longer-provides-free-binaries/ http://www.terminally-incoherent.com/blog/2006/12/30/mysql-no-longer-provides-free-binaries/#comments Sun, 31 Dec 2006 01:40:48 +0000 http://www.terminally-incoherent.com/blog/2006/12/30/mysql-no-longer-provides-free-binaries/ Continue reading ]]> This is really sad, but it appears that MySQL will no longer provide free binaries for their Community branch.

From what I understand, the Community version will continue to be released as normal, and distributed under GPL, but MySQL will not provide binaries for download on their own site. Precompiled binaries should still be available in the form of packages from various linux vendors if they choose to include them in their package trees.

In other words nothing really changes for hosts of linux users out there (especially for apt and yum users who can rely on rich repositories to always contain the newest releases). On the other hand Windows users should be relatively upset about this because it means they will need to build from source each time a new version is released.

That is, unless someone takes it upon them to provide windows MySQL binaries to the masses and build some nice installers for them. I imagine that whoever manages to establish themselves as a trustworthy source can probably expect some good traffic and hence add revenue. I’m actually tempted to buy mysql4win.com – if nothing else, just to see if anyone really wants it. :P

found via homo-adminus blog

[tags]mysq, binaries, windows, linux, databases[/tags]

]]>
http://www.terminally-incoherent.com/blog/2006/12/30/mysql-no-longer-provides-free-binaries/feed/ 7
MySQL: How to get the key of last inerted row in PHP http://www.terminally-incoherent.com/blog/2006/12/04/mysql-how-to-get-the-key-of-last-inerted-row-in-php/ http://www.terminally-incoherent.com/blog/2006/12/04/mysql-how-to-get-the-key-of-last-inerted-row-in-php/#comments Tue, 05 Dec 2006 03:17:23 +0000 http://www.terminally-incoherent.com/blog/2006/12/04/mysql-how-to-get-the-key-of-last-inerted-row-in-php/ Continue reading ]]> I like to let MySQL generate unique keys for most of my tables by making them numerical and using the AUTO_INCREMENT feature. It is both an easy and convenient way to deal with primary keys. It has one disadvantage though.

Since the key is generated upon insertion of a new row, you can never know its value before the SQL statement is executed. Furthermore, it can be problematic to insert a new row into a table, and then use its key as a foreign key in another table. One could potentially follow the insert statement with a selection, but unfortunately it is possible that the primary key is the only unique value that distinguishes several rows. We can never be a 100% sure that we are getting the right one, using a selection statement.

MySQL provides us with a nifty feature that does precisely what we need:

SELECT LAST_INSERT_ID()

Lets say we have two tables tab1(id, value) and tab2(id, value, tab1_id). To insert a new row to tab1, and then new row to tab2 while referencing tab1 we can do this:

INSERT INTO tab1 (name) VALUES ('some value')
INSERT INTO tab2 (value, tab1_id) VALUES ('another value', LAST_INSERT_ID())

If you are working with PHP, this whole thing becomes even easier. The mysql module contains a great function that lets you get the id of the last inserted row:

$last_inserted_row = mysql_insert_id($dblink)

Here, $dblink is a database connection identifier variable (the one returned by mysql_connect statement). The returned key is found based on your unique connection, you can safely assume you are getting the correct value, even in a multi-user server environment. Other users, connecting to the db at the same time will get last unique id’s that match their connection.

[tags]php, mysql, database, primary key, foreign key, sql, insert, last inserted id[/tags]

]]>
http://www.terminally-incoherent.com/blog/2006/12/04/mysql-how-to-get-the-key-of-last-inerted-row-in-php/feed/ 7
MySQL Performance Tips http://www.terminally-incoherent.com/blog/2006/11/14/mysql-performance-tips/ http://www.terminally-incoherent.com/blog/2006/11/14/mysql-performance-tips/#respond Wed, 15 Nov 2006 03:12:26 +0000 http://www.terminally-incoherent.com/blog/2006/11/14/mysql-performance-tips/ Continue reading ]]> I found this list today via Homo-Adminus, and I think it’s really worth sharing: 84 MySQL performance tips.

Some of these are common sense (eg. index stuff, but don’t index everything), while other are little nuggets of awesome DBA knowledge that only come with experience and expertise.

It’s something you should definitely check out if you work with MySQL.

[tags]mysql, performace, database, dba, administration, tips[/tags]

]]>
http://www.terminally-incoherent.com/blog/2006/11/14/mysql-performance-tips/feed/ 0
MySQL: find week start/end given week number http://www.terminally-incoherent.com/blog/2006/09/22/mysql-find-week-startend-based-on-week-number/ http://www.terminally-incoherent.com/blog/2006/09/22/mysql-find-week-startend-based-on-week-number/#comments Fri, 22 Sep 2006 20:39:41 +0000 http://www.terminally-incoherent.com/blog/2006/09/22/mysql-find-week-startend-based-on-week-number/ Continue reading ]]> I have a table with some dated records. I wanted to do some weekly reports on this data. MySQL has a nifty function dubbed WEEK() which will return a week number. It allows you to break your data into week long intervals very easily. For example, the following query will tell me how many records came in each week:

SELECT COUNT(*), WEEK(mydate)
FROM mytable
GROUP BY WEEK(mydate)

The problem here is, that the output is totally meaningless to me as I do not have a clue what does week 36 mean. What I really want is to have on the screen is a nice, human readable date interval – the beginning and ending date of any given week.

Surprisingly, this turns out the be a major pain in the ass. There is no simple function that will yield a week interval (or start/end date of a week) given a week number. You have to find these dates manually. Here is how I did it:

SELECT
    COUNT(*) AS reports_in_week,
    DATE_ADD(mydate, INTERVAL(1-DAYOFWEEK(mydate)) DAY),
    DATE_ADD(mydate, INTERVAL(7-DAYOFWEEK(mydate)) DAY)
FROM
    mytable
GROUP BY
    WEEK(mydate)

How does it work? The DAYOFWEEK() function returns an integer ranging from 1 (Sunday) to 7 (Saturday). So if mydate happens to be Tuesday we get the following statements:

DATE_ADD(mydate, INTERVAL -2 DAY)

which essentially means “subtract 2 days from mydate (which is that week’s Sunday) and also:

DATE_ADD(mydate, INTERVAL 4 DAY)

which yields the date of that week’s Friday.

One would think that there would be a function to accomplish this automatically, but alas there is none. I think this is as simple as it gets. I hope this helps someone, because it took me quite a while to figure this out.

[tags]mysql, weekly, weekly reports, time functions, sql, databases[/tags]

]]>
http://www.terminally-incoherent.com/blog/2006/09/22/mysql-find-week-startend-based-on-week-number/feed/ 46
Dump MySQL table into CSV file http://www.terminally-incoherent.com/blog/2006/07/20/dump-mysql-table-into-csv-file/ http://www.terminally-incoherent.com/blog/2006/07/20/dump-mysql-table-into-csv-file/#comments Thu, 20 Jul 2006 19:49:52 +0000 http://www.terminally-incoherent.com/blog/2006/07/20/dump-mysql-table-into-csv-file/ Continue reading ]]> I needed to quickly dump bunch of MySQL tables into Excel so that our directors can play around with the data. It does make sense, believe me. It would take me at least a day or two to implement, test, and integrate the statistical analysis they want to do on the data into our web application. Meanwhile they can perform the same calculations on an excel sheet in the next 15 minutes. So I get to add bunch of items to my todo list, and they get bunch of data to play around with. Everyone wins :)

And yes, they specifically asked for Excel format, and the future reports must have “export to Excel” feature.

Anyways, here is why I love MySQL:

SELECT * INTO OUTFILE 'result.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM my_table;

You get a CSV file formated nicely for Excel. Now you can just open it, and save it as xls file if that is what you need.

If your table is to big for Excel you can of course use a WHY clause to cut down the number of results.

[tags]mysql, excel, mysql export, sql, databases[/tags]

]]>
http://www.terminally-incoherent.com/blog/2006/07/20/dump-mysql-table-into-csv-file/feed/ 14