CHARおよびVARCHARの小さな機能

背景





標準LAMPが実行される小さなサーバーがあります。 それはすべて、QAが私にやって来て、「トピックがあります。ユーザー登録を再確認する必要があります。古いアカウントを削除できますか?」、「質問はありません」という事実から始まりました。 一番下の行は、私たちとの入り口はソーシャルネットワークを介してのみ行われます。 アカウントを削除してデータベースの整合性を侵害しないようにするため、テーブル内のUID (特定のソーシャルネットワークのユーザーID)を取得して名前を変更することにしました。

全員が異なるUID(vk、facebook、google ...-数値UID、linkedin-ストリングUID)を持っているため、ストレージにVARCHARが使用されました。 その結果、アンダースコア文字「_」を行に追加しましたが、落ち着いた魂はサブスクライブされていません:「Check ...」。



画像







「アカウントを削除しただけですか、それ以外の場合は古いアカウントが表示されましたか?」と聞いたとき、私はとても驚きました。

小規模な調査の過程で、矛盾する場所が見つかりました。



/** * @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]; }
      
      







すなわち:

$ where = 'providerUserId =?';




UIDは数値であるため、「_」を追加してもサンプルに影響はありませんでした。

実験中に、次のデータが得られました。



ソースデータ
-- --------------------------------------------------------

-- 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 */;













テスト番号1:



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)









テスト番号2:



mysql> select * from t where `string` = '123456';

+----+--------+

| id | string |

+----+--------+

| 1 | 123456 |

+----+--------+

1 row in set (0.00 sec)









通常のCHARを確認する必要があります(さて、インデックスを追加しましょう。

テスト番号3:



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)









テスト番号4:



mysql> select * from t2 where `string` = '123456';

+----+--------+

| id | string |

+----+--------+

| 1 | 123456 |

+----+--------+

1 row in set (0.00 sec)









公式ページに行くと、そのようなものは見つかりませんでした。 その結果、UIDが数字ではなく文字列として認識されるように、リクエストを修正する必要がありました。



PS。 何かを削除する必要があるときは、前に `_`を追加します:)

PPS: ellrionによるこのチップの説明へのリンク



All Articles