3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPとMySQLのソートが一致しなくて禿げた

Posted at

こんにちは。はじめまして。tarokamiakzeです。
PHPのsort系関数の結果と、MySQL のorder by指定を比較する機会がありまして。
記号の扱いが一致しなくて泣きたくなりました。
(PHPUnitで、検索系APIが本当にソートされているか検証したかっただけなのに...)

ので、怒りに任せて記事を書きます。LAMP環境とはなんだったのか!!

再現方法

MySQL編

# MySQL
CREATE TABLE `sort_test` (
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `sort_test`(`name`) VALUES ("0"),("1"),("a"),("_");

SELECT `name` as `MySQL_SORT` FROM `sort_test` ORDER BY `name` ASC;

PHP編

<?php

$arr = ["0","1","a","_"];
// 通常のソート.
sort($arr);
var_dump($arr);

// sort_flag を指定。この例だと、何を指定しても同じだった
sort($arr,SORT_STRING); // see http://php.net/manual/ja/function.sort.php
var_dump($arr);

// "自然順"アルゴリズムで配列をソート
natsort($arr);
var_dump($arr);

結果

MySQL_SORT PHP_SORT
0 "0"
1 "1"
"a" "_"
"_" "a"

"_" と "a" が逆になってますがな!!!

解決方法

MySQLデフォルトのutf8_general_ciだと、どーーーしても一致しないらしい。
ためしにutf8_binに変えてみたら、順番が合った。が、そんなの使いたくない。
よってSELECT時だけCOLLATEを変える

SELECT `name` as `MySQL_SORT` FROM `sort_test` ORDER BY `name` COLLATE utf8_bin ASC;
MySQL_SORT PHP_SORT
0 "0"
1 "1"
"_" "_"
"a" "a"

でも、他に弊害がある気がしてならない。
php側であわせたほうがよさそう。

// see http://stackoverflow.com/questions/21416765/php-sort-filenames-with-an-underscore
function cmp($a, $b) {
  $aTemp = str_replace('_', '0', $a);
  $bTemp = str_replace('_', '0', $b);     
  return strcmp($aTemp,$bTemp);
}

 usort($arr, "cmp");

でも、きっと他の記号もなんかあるんだろうなぁ。辛い。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?