【数字の昇順】→「文字順」で取得したい。
単純に文字順にしてしまうのは 1,10,11,2,3,4 になるのでだめなパターン。
QuerySet APIの distinct はPostgreSQLでしかサポートされていないので、
DBのViewを書いた。
create view app_view1 as select distinct col1, case when length(col1) = 0 then 0 when cast(col1 as UNSIGNED INTEGER) > 0 then cast(col1 as UNSIGNED INTEGER) else 2147483647 end as sort from table1
ちなみに本題とはあまり関係ないけどModelはこんな感じ。
文字はsortを十分に大きくしておいた上でsort昇順→col1昇順にすればいいはず。class View1(models.Model): col1 = models.CharField(max_length=10,blank=True,primary_key=True) sort = models.IntegerField() class Meta: app_label="app" ordering=["sort","col1"] managed=False
MySQL Workbenchからだとゴキゲンに動作する。
実際に実行する。タイトルのような文字列を叫んで憤死する。
原因としては、実際にはMySQL内で実行した際にcastで「Truncated incorrect INTEGER value:'【文字列】'」というwarningが出ており、
それをMySQLdbモジュールが拾おうとしてしまって、【文字列】部分がUnicodeになっているせいでUnicodeEncodeErrorになるという
余計な事すんなよというもの。
何とかする方法を考える。
・MySQLdbをいじる(UnicodeEncodeErrorを吐かないようにする)→できればやりたくない
・Djangoをいじる(warningを拾わないようにする)→できればやりたくない
・継承で何とかする→djangoのdb backendを作れば何とか出来るんだろうができればやりたくない
・MySQLでWarningを出さないようにできないか→MySQL Suppress Warningとかでググる。死屍累々。
・あきらめてPython上で並べ替えをする→今回はいいがこんな感じので大量のデータに対してやろうとしたらどうするよ
SQLに立ち戻る。
要は数字だけ以外の場合に、CASTさえしなければよい。
MySQLにはREGEXPがあった。
create view app_view1 as select distinct col1, case when length(col1) = 0 then 0 when col1 REGEXP '^[[:digit:]]+$' then cast(col1 as UNSIGNED INTEGER) else 2147483647 end as sort from table1
何とか逃げ延びた。
^と$が入っていなかったので修正。
返信削除それがないと意味がない…。