😎

最長の文字列データを取得する方法

2023/10/07に公開

背景

実務でレコードの中であるカラムの文字数が最も多いカラムを持つレコードを取得したい時がありました。

ActiveRecord や ruby のメソッドで取得できないか調べましたが、その方法を見つけるのに時間がかかり、他の人にも共有したいと思い、まとめておきます。

よかったら参考に。

最長の文字列データを取得

文字数が最も多いカラムを持つレコードを取得したい時、結論、orderメソッドの中でSQLのLENGTH関数を実行することで、最長の文字列データを取得することができます。

実行結果は下記の通りです。

# データ数と各データの文字列データの取得
Place.count
=> 5

Place.pluck(:id, :address)
=> [[1, "Paris"], [2, "GeekSalon"], [3, "東京タワー"], [4, "みなとみらい"], [5, "タウマタファカタンギハンガコアウアウオタマテアポカイフェヌアキタナタフ"]]


# 最長の文字列を持つレーコードを取得

Place.order('LENGTH(address) DESC').first

Place Load (3.2ms)  SELECT "places".* FROM "places" ORDER BY LENGTH(address) DESC LIMIT $1  [["LIMIT", 1]]
=> #<Place:0x00007fa2df52d620
 id: 5,
 latitude: nil,
 longitude: nil,
 created_at: Fri, 06 Oct 2023 23:18:22.839865000 UTC +00:00,
 updated_at: Fri, 06 Oct 2023 23:18:22.839865000 UTC +00:00,
 address: "タウマタファカタンギハンガコアウアウオタマテアポカイフェヌアキタナタフ">


# 最長の文字列の文字数を取得

Place.maximum('LENGTH(address)')

Place Maximum (2.1ms)  SELECT MAX(LENGTH(address)) FROM "places"
=> 35


# 最長の文字列とその文字数を配列で取得

Place.order('LENGTH(address) DESC').pluck(:address, 'LENGTH(address)').first

Place Pluck (1.6ms)  SELECT "places"."address", LENGTH(address) FROM "places" ORDER BY LENGTH(address) DESC
=> ["タウマタファカタンギハンガコアウアウオタマテアポカイフェヌアキタナタフ", 35]


# 最長の文字列の値を取得

Place.pluck(:address).max {|a, b| a.length <=> b.length}

Place Pluck (1.1ms)  SELECT "places"."address" FROM "places"
=> "タウマタファカタンギハンガコアウアウオタマテアポカイフェヌアキタナタフ"



ここで注意点が2つあります。

maximum メソッドと order メソッドをLENGTH関数を使用せずに実行した時です。

Place.maximum(:address) では、最長の文字列データを適切に取得できないらしいです。

文字列データに対してmaximum メソッドを使用すると、辞書順(アルファベット順→ひらがな順→カタカナ順→漢字順)に基づいて最大の文字列を取得します。

数値データの場合は通常の最大値が取得されますが、文字列の場合は文字列の辞書順での最大値が取得されます。

なので、下記の場合、maximum メソッドを使用した時、address カラムの値を辞書順にソートした時、一番最後にくる漢字の「東京タワー」という値を取得しています。



また、Place.order(:address) でも最長の文字列を持つレコード順に並び替えることはできないらしいです。

order メソッドの時は、string型(文字列型)のaddressカラムに対して実行すると、addressカラムの値に基づいて辞書順にソートします。



実行結果は下記の通りです。

# maximumメソッドを実行

Place.maximum(:address)

Place Maximum (1.3ms)  SELECT MAX("places"."address") FROM "places"
=> "東京タワー"

# orderメソッドを実行(pluckで見やすく変形)

Place.order(:address).pluck(:id, :address)

=> [[2, "GeekSalon"], [1, "Paris"], [5, "タウマタファカタンギハンガコアウアウオタマテアポカイフェヌアキタナタフ"], [4, "みなとみらい"], [3, "東京タワー"]]


参考

https://stackoverflow.com/questions/14185823/how-can-i-sort-a-list-of-activerecords-by-an-attribute-length

Discussion