A small feature of CHAR and VARCHAR
Background
There is a small server on which the standard LAMP runs . It all started with the fact that QA comes up to me and says: “There is a topic, I need to double-check user registration, can you delete the old account?”, “No question,” I replied. The bottom line is, the entrance with us is made only through social networks. In order not to violate the integrity of the database by deleting the account, I decided to just take and rename the UID (user ID in a particular social network) in the table.
Since everyone has different UIDs (vk, facebook, google ... - numeric UID, linkedin - string UID) VARCHAR was used for storage. As a result, I added the underscore character `_` to the line, and with a calm soul unsubscribed:" Check ... ".

I was very surprised when I heard: "Did you just delete the account, otherwise my old one is displayed?"
In the course of a mini investigation, a place of inconsistency was found.
/**
* @param string $providerUserId
* @param string|null $provider
*
* @return ent\UserSocial|null
*/
public function getByProviderUserId($providerUserId, $provider = null)
{
$where = 'providerUserId = ?';
if ($provider) {
$where .= ' AND provider = "' . $provider . '"';
}
$res = $this->fetchObjects($where, [$providerUserId]);
if (empty($res)) {
return null;
}
return $res[0];
}
Namely:
$ where = 'providerUserId =?';
The addition of `_` turned out to have no effect on the sample, since the UID was a number.
During the experiments, the following data were obtained:
Initial data
-- --------------------------------------------------------
-- Host: localhost
-- Server version: 5.5.49-0+deb8u1 - (Debian)
-- Server OS: debian-linux-gnu
-- HeidiSQL Version: 8.3.0.4694
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Dumping database structure for test
CREATE DATABASE IF NOT EXISTS `test` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `test`;
-- Dumping structure for table test.t
CREATE TABLE IF NOT EXISTS `t` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`string` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
-- Dumping data for table test.t: ~5 rows (approximately)
/*!40000 ALTER TABLE `t` DISABLE KEYS */;
INSERT INTO `t` (`id`, `string`) VALUES
(1, '123456'),
(2, '123456_'),
(3, '123456a'),
(4, '1234567'),
(5, '123456_a');
/*!40000 ALTER TABLE `t` ENABLE KEYS */;
-- Dumping structure for table test.t2
CREATE TABLE IF NOT EXISTS `t2` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`string` char(50) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `string` (`string`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
-- Dumping data for table test.t2: ~5 rows (approximately)
/*!40000 ALTER TABLE `t2` DISABLE KEYS */;
INSERT INTO `t2` (`id`, `string`) VALUES
(1, '123456'),
(2, '1234567'),
(3, '123456a'),
(4, '123456_'),
(5, '123456_a');
/*!40000 ALTER TABLE `t2` ENABLE KEYS */;
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
Test No. 1: Test No. 2: We need to check the usual CHAR (well, we’ll add the index, it’s not enough ...) Test No. 3: Test No. 4: Having visited the official on the page , I did not find anything similar. As a result, I had to correct the request so that the UID was perceived as a string, and not as a number. PS. Now when you need to delete something , I add `_` in front :) PPS: Link by ellrion to the description of this chip.
mysql> select * from t where `string` = 123456;
+----+----------+
| id | string |
+----+----------+
| 1 | 123456 |
| 2 | 123456_ |
| 3 | 123456a |
| 5 | 123456_a |
+----+----------+
4 rows in set, 2 warnings (0.00 sec)
mysql> select * from t where `string` = '123456';
+----+--------+
| id | string |
+----+--------+
| 1 | 123456 |
+----+--------+
1 row in set (0.00 sec)
mysql> select * from t2 where `string` = 123456;
+----+----------+
| id | string |
+----+----------+
| 1 | 123456 |
| 3 | 123456a |
| 4 | 123456_ |
| 5 | 123456_a |
+----+----------+
4 rows in set, 3 warnings (0.00 sec)
mysql> select * from t2 where `string` = '123456';
+----+--------+
| id | string |
+----+--------+
| 1 | 123456 |
+----+--------+
1 row in set (0.00 sec)