- SQL
- データベース
- 技術 💻
SQLでグループごとに最新の1件を取得|6方式をDB別に100万件で実測
グループごとに最新の1件を取るなら、まず ROW_NUMBER() で「グループの中で新しい順に番号を振り、1番だけ残す」書き方を使います。 MySQL 8.0 以降・PostgreSQL・SQLite・SQL Server・Oracle のどれでもほぼ同じ形で動き、同じ日時が2件あっても必ず1件に絞れます。
SELECT id, member_id, ordered_at, amount
FROM (
SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC) AS rn
FROM orders o
) t
WHERE rn = 1;
ただし、データが多いときに最速なのは DB ごとに違います。この記事では6つの書き方を同じデータで実行し、結果の違い(同時刻の行が2件出るかどうか)と、100万件での速度を MySQL と PostgreSQL で測りました。「どれを使えばいいか」は早見表の1行目から選べます。
確認環境:Ubuntu 24.04・2コア・メモリ7GB。MySQL 8.0.46、PostgreSQL 16.15、SQLite 3.45.1、DuckDB 1.5.6 で実行(確認日 2026年10月10日)。SQL Server と Oracle の構文は各社の公式リファレンスで確認しています。
どの書き方を使うか:早見表
| 状況 | おすすめの書き方 | 同時刻が2件あるとき |
|---|---|---|
| 迷ったら(MySQL 8.0以降・PostgreSQL・SQLite・SQL Server・Oracle) | ① ROW_NUMBER() |
1件に絞れる(ORDER BY に id を足す) |
| 同時刻の行を全部出したい | ⑤ RANK() |
全部出る |
| MySQL 5.7 など窓関数が無い | ③ GROUP BY+JOIN |
全部出る(必要なら外側で絞る) |
| PostgreSQL で短く書きたい | ⑥ DISTINCT ON |
1件に絞れる |
| グループの一覧表(会員マスタなど)があり、件数が多い | ⑦ LATERAL(SQL Server は CROSS APPLY) |
1件に絞れる |
| 注文が無い会員も行として出したい | ⑦ LEFT JOIN LATERAL(OUTER APPLY) |
1件に絞れる |
| BigQuery・Snowflake・DuckDB | QUALIFY ROW_NUMBER() ... = 1 |
1件に絞れる |
100万件での結論:PostgreSQL では LATERAL が最速(47〜75ms)、MySQL では GROUP BY+JOIN が最速(44ms)でした。相関サブクエリ(②)と NOT EXISTS(④)は、どちらの DB でも数秒〜18秒かかりました。詳しくは「100万件で速度を比べた結果」に載せています。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「SQLでグループごとに最新の1件を取得|6方式をDB別に100万件で実測」
サンプルデータ
会員(member_id)ごとに注文がある表です。会員102は 同じ日時の注文が2件(id 4 と 5) あるようにしてあります。最新1件の書き方の違いは、ここで結果に出ます。
CREATE TABLE orders (
id INT PRIMARY KEY,
member_id INT NOT NULL,
ordered_at TIMESTAMP NOT NULL,
amount INT NOT NULL
);
INSERT INTO orders VALUES
(1, 101, '2026-10-01 09:00:00', 1200),
(2, 101, '2026-10-03 18:30:00', 3400),
(3, 102, '2026-10-02 12:00:00', 800),
(4, 102, '2026-10-05 08:15:00', 2500),
(5, 102, '2026-10-05 08:15:00', 1900),
(6, 103, '2026-09-28 20:00:00', 5600);
欲しい結果は「会員101は id 2、会員102は id 4 か 5 のどちらか1件、会員103は id 6」です。
よくある間違い:GROUP BY だけで取ろうとする
最初に書きがちなのが次の SQL です。
SELECT member_id, id, MAX(ordered_at) AS max_at
FROM orders
GROUP BY member_id;
DB によって結果がまったく違います。
-- MySQL 8.0
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and
contains nonaggregated column 'ts.orders.id' which is not functionally dependent
on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
-- PostgreSQL 16
ERROR: column "orders.id" must appear in the GROUP BY clause or be used in an aggregate function
-- SQLite 3.45(エラーにならず、MAX の行の id が返る)
member_id id max_at
101 2 2026-10-03 18:30:00
102 4 2026-10-05 08:15:00
103 6 2026-09-28 20:00:00
GROUP BY は「グループを1行にまとめる」ための構文で、「グループの中の1行を選ぶ」構文ではありません。 MySQL と PostgreSQL は id をどの行から取るか決められないのでエラーにします。SQLite は MAX() が1つだけのときに限り、その行の値を返す独自の動きをしますが、他の DB に持っていくと動きません。MySQL で sql_mode から ONLY_FULL_GROUP_BY を外すとエラーは消えますが、id は MAX の行と一致する保証が無くなります。以下の6方式のどれかで書き換えます。
① ROW_NUMBER():いちばん汎用的な書き方
SELECT id, member_id, ordered_at, amount
FROM (
SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC) AS rn
FROM orders o
) t
WHERE rn = 1
ORDER BY member_id;
id | member_id | ordered_at | amount
----+-----------+---------------------+--------
2 | 101 | 2026-10-03 18:30:00 | 3400
5 | 102 | 2026-10-05 08:15:00 | 1900
6 | 103 | 2026-09-28 20:00:00 | 5600
(3 rows)
PARTITION BY member_id:会員ごとに番号を振り直すORDER BY ordered_at DESC, id DESC:新しい順。同時刻なら id の大きいほうを1番にする- 外側の
WHERE rn = 1:各会員の1番だけ残す
ORDER BY に id DESC を足さないと、同時刻の id 4 と 5 のどちらが1番になるかは実行のたびに変わる可能性があります。並び順が一意になる列(主キーなど)を最後に足すのが決まりごとです。
窓関数の結果は WHERE に直接書けないので、サブクエリで包みます。WITH 句で書いても同じです。
WITH ranked AS (
SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC) AS rn
FROM orders o
)
SELECT id, member_id, ordered_at, amount
FROM ranked
WHERE rn = 1;
最新3件にしたいときは WHERE rn <= 3、最古の1件なら ORDER BY ordered_at ASC に変えるだけです。
② 相関サブクエリ(MAX):短いが、同時刻は2件出る
SELECT id, member_id, ordered_at, amount
FROM orders o
WHERE ordered_at = (
SELECT MAX(ordered_at) FROM orders x
WHERE x.member_id = o.member_id
)
ORDER BY member_id, id;
id | member_id | ordered_at | amount
----+-----------+---------------------+--------
2 | 101 | 2026-10-03 18:30:00 | 3400
4 | 102 | 2026-10-05 08:15:00 | 2500
5 | 102 | 2026-10-05 08:15:00 | 1900
6 | 103 | 2026-09-28 20:00:00 | 5600
(4 rows)
窓関数が無い DB でも動きますが、同じ日時の行はすべて残るので会員102が2行になります。また、行ごとにサブクエリを評価するため、件数が多いと遅くなりやすい書き方です(100万件で MySQL 18.6秒、PostgreSQL 4.6〜9.7秒)。
③ GROUP BY+JOIN:MySQL 5.7 でも使え、MySQL では最速
SELECT o.id, o.member_id, o.ordered_at, o.amount
FROM orders o
JOIN (
SELECT member_id, MAX(ordered_at) AS max_at
FROM orders
GROUP BY member_id
) m ON o.member_id = m.member_id
AND o.ordered_at = m.max_at
ORDER BY o.member_id, o.id;
id | member_id | ordered_at | amount
----+-----------+---------------------+--------
2 | 101 | 2026-10-03 18:30:00 | 3400
4 | 102 | 2026-10-05 08:15:00 | 2500
5 | 102 | 2026-10-05 08:15:00 | 1900
6 | 103 | 2026-09-28 20:00:00 | 5600
(4 rows)
まず会員ごとの最新日時を求め、その日時に一致する行を元の表から取ります。②と同じく同時刻は2件出ます。1件に絞りたい場合は、同時刻の中でさらに MAX(id) を取る段をもう1つ重ねるか、①を使います。
MySQL では (member_id, ordered_at) の順の索引があると、GROUP BY ... MAX() を索引の飛ばし読み(実行計画で Covering index skip scan for grouping)で処理するため、100万件でも 44ms でした。
④ NOT EXISTS:「自分より新しい行が無い行」を残す
SELECT id, member_id, ordered_at, amount
FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM orders x
WHERE x.member_id = o.member_id
AND (x.ordered_at > o.ordered_at
OR (x.ordered_at = o.ordered_at AND x.id > o.id))
)
ORDER BY member_id;
id | member_id | ordered_at | amount
----+-----------+---------------------+--------
2 | 101 | 2026-10-03 18:30:00 | 3400
5 | 102 | 2026-10-05 08:15:00 | 1900
6 | 103 | 2026-09-28 20:00:00 | 5600
(3 rows)
同時刻の扱いを id で書き込めるので1件に絞れ、窓関数の無い DB でも動きます。ただし100万件では MySQL 約12秒、PostgreSQL 約1.1秒と、①③⑥⑦より遅い結果でした。
⑤ RANK():同時刻の行を全部出したいとき
SELECT id, member_id, ordered_at, amount
FROM (
SELECT o.*,
RANK() OVER (PARTITION BY member_id ORDER BY ordered_at DESC) AS rk
FROM orders o
) t
WHERE rk = 1
ORDER BY member_id, id;
id | member_id | ordered_at | amount
----+-----------+---------------------+--------
2 | 101 | 2026-10-03 18:30:00 | 3400
4 | 102 | 2026-10-05 08:15:00 | 2500
5 | 102 | 2026-10-05 08:15:00 | 1900
6 | 103 | 2026-09-28 20:00:00 | 5600
(4 rows)
| 関数 | 同じ値のとき | 最新1件の用途 |
|---|---|---|
ROW_NUMBER() |
必ず別の番号(1, 2, 3…) | 1件だけ欲しい |
RANK() |
同じ番号、次は飛ぶ(1, 1, 3…) | 同時刻を全部欲しい |
DENSE_RANK() |
同じ番号、次は飛ばない(1, 1, 2…) | 「最新の日付の行すべて」など |
⑥ DISTINCT ON:PostgreSQL 専用の短い書き方
SELECT DISTINCT ON (member_id) id, member_id, ordered_at, amount
FROM orders
ORDER BY member_id, ordered_at DESC, id DESC;
id | member_id | ordered_at | amount
----+-----------+---------------------+--------
2 | 101 | 2026-10-03 18:30:00 | 3400
5 | 102 | 2026-10-05 08:15:00 | 1900
6 | 103 | 2026-09-28 20:00:00 | 5600
(3 rows)
DISTINCT ON (member_id) は「member_id ごとに、ORDER BY の順で最初の1行だけ残す」という PostgreSQL の拡張構文です。ORDER BY の先頭は DISTINCT ON の列と同じにする決まりがあります。MySQL・SQLite・SQL Server・Oracle にはありません。
⑦ LATERAL(SQL Server は CROSS APPLY):会員の一覧から引く
会員マスタのような「グループの一覧表」があるなら、会員1人ずつに「新しい順の先頭1件」を取りに行く書き方ができます。注文が無い会員も行として残せるのが他の書き方との違いです。
SELECT m.member_id, m.name, l.id, l.ordered_at, l.amount
FROM members m
LEFT JOIN LATERAL (
SELECT id, ordered_at, amount
FROM orders o
WHERE o.member_id = m.member_id
ORDER BY ordered_at DESC, id DESC
LIMIT 1
) l ON TRUE
ORDER BY m.member_id;
member_id | name | id | ordered_at | amount
-----------+------+----+---------------------+--------
101 | 佐藤 | 2 | 2026-10-03 18:30:00 | 3400
102 | 鈴木 | 5 | 2026-10-05 08:15:00 | 1900
103 | 高橋 | 6 | 2026-09-28 20:00:00 | 5600
104 | 田中 | | |
(4 rows)
会員104(注文なし)も1行で出ています。注文がある会員だけでよければ CROSS JOIN LATERAL (...) l にします。MySQL は 8.0.14 以降で同じ構文が動きます(上の結果は PostgreSQL。MySQL 8.0.46 でも同じ4行でした)。
索引 (member_id, ordered_at DESC, id DESC) があると、会員1人あたり索引を1回たどるだけで済むため、PostgreSQL では6方式で最速でした。
100万件で速度を比べた結果
注文100万件・会員1万人(1人あたり約100件)のデータで、各方式を2回ずつ実行しました。索引は CREATE INDEX idx_bo ON big_orders(member_id, ordered_at DESC, id DESC); の1本です。
| 方式 | MySQL 8.0.46 | PostgreSQL 16.15 | 同時刻 |
|---|---|---|---|
| ① ROW_NUMBER | 2,423〜2,647ms | 309〜830ms | 1件 |
| ② 相関サブクエリ(MAX) | 18,589〜18,842ms | 4,584〜9,696ms | 複数 |
| ③ GROUP BY+JOIN | 43〜44ms | 280〜303ms | 複数 |
| ④ NOT EXISTS | 11,885〜12,286ms | 1,043〜1,110ms | 1件 |
| ⑥ DISTINCT ON | (構文なし) | 297〜306ms | 1件 |
| ⑦ LATERAL(会員表から) | 264〜282ms | 47〜75ms | 1件 |
1回目と2回目の差はキャッシュの影響です。2コアの小さな環境の数字なので、絶対値より「方式どうしの差」を見てください。
読み方は3つです。
- ②と④は件数が増えると急に遅くなる。 PostgreSQL の実行計画では、②は表全体を読みながら1行ごとにサブクエリを動かしています(
Seq Scan+SubPlan)。少量なら問題ありませんが、本番の表では避けたほうが無難です。 - MySQL は③、PostgreSQL は⑦が速い。 MySQL は
GROUP BY ... MAX()を索引で飛ばし読みできるのが強く、PostgreSQL はLATERALの中でLIMIT 1を索引1回で解決できるのが強い、という DB ごとの得意の差です。 - ①は「どの DB でも同じ書き方で、そこそこ速い」。 最速ではありませんが、同時刻を1件に絞れて移植しやすいので、最初の1本としてはこれが扱いやすい選択です。速度が問題になったら③や⑦に置き換えます。
MySQL の③の実行計画(EXPLAIN FORMAT=TREE)は次のとおりです。
-> Nested loop inner join (cost=12081 rows=9967)
-> Filter: (g.m is not null) (cost=6554..1124 rows=9967)
-> Table scan on g (cost=6555..6682 rows=9967)
-> Materialize (cost=6555..6555 rows=9967)
-> Covering index skip scan for grouping on big_orders using idx_bo (cost=5558 rows=9967)
-> Covering index lookup on o using idx_bo (member_id=g.member_id, ordered_at=g.m) (cost=0.999 rows=1)
PostgreSQL の⑦の実行計画は、会員1人ごとに索引だけで1件を取っています。
Nested Loop (cost=0.43..5125.00 rows=10000 width=4)
-> Function Scan on generate_series m (cost=0.00..100.00 rows=10000 width=4)
-> Limit (cost=0.42..0.48 rows=1 width=12)
-> Index Only Scan using idx_bo on big_orders o (cost=0.42..6.17 rows=100 width=12)
Index Cond: (member_id = m.member_id)
索引の付け方
| 方式 | 効く索引 |
|---|---|
| ① ⑥ ⑦ | (グループ列, 日時列 DESC, 主キー DESC) |
| ③ | (グループ列, 日時列) |
| 共通 | WHERE で絞る列(例:status)があるなら、グループ列の前か後ろに足すかを実行計画で確かめる |
索引が使われているかは、MySQL は EXPLAIN FORMAT=TREE、PostgreSQL は EXPLAIN ANALYZE で確かめられます。
DB 別の対応表
| DB | ① ROW_NUMBER | ③ GROUP BY+JOIN | 専用の書き方 |
|---|---|---|---|
| MySQL 8.0以降 | ○ | ○(最速になりやすい) | LATERAL(8.0.14以降) |
| MySQL 5.7 | ×(窓関数なし) | ○ | なし(②③④で書く) |
| PostgreSQL | ○ | ○ | DISTINCT ON、LATERAL |
| SQLite 3.25以降 | ○ | ○ | MAX() 1つのときの裸の列(独自仕様) |
| SQL Server | ○ | ○ | CROSS APPLY/OUTER APPLY、TOP 1 WITH TIES |
| Oracle 12c以降 | ○ | ○ | FETCH FIRST、KEEP (DENSE_RANK LAST ...) |
| BigQuery・Snowflake・DuckDB | ○ | ○ | QUALIFY |
SQL Server(T-SQL)の書き方
LATERAL に当たるのが CROSS APPLY(注文が無い会員も残すなら OUTER APPLY)で、LIMIT 1 は TOP (1) です。
SELECT m.member_id, l.id, l.ordered_at, l.amount
FROM members m
OUTER APPLY (
SELECT TOP (1) id, ordered_at, amount
FROM orders o
WHERE o.member_id = m.member_id
ORDER BY ordered_at DESC, id DESC
) l;
TOP (1) WITH TIES と ROW_NUMBER() を組み合わせると、サブクエリ無しで書けます。
SELECT TOP (1) WITH TIES id, member_id, ordered_at, amount
FROM orders
ORDER BY ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC);
Oracle の書き方
①はそのまま動きます。集計関数の KEEP (DENSE_RANK LAST ORDER BY ...) を使うと、GROUP BY だけで「最新日時の行の値」を取れます。
SELECT member_id,
MAX(id) KEEP (DENSE_RANK LAST ORDER BY ordered_at) AS latest_id,
MAX(amount) KEEP (DENSE_RANK LAST ORDER BY ordered_at) AS latest_amount,
MAX(ordered_at) AS latest_at
FROM orders
GROUP BY member_id;
同時刻が複数あるとき、KEEP の中で残った行から MAX(id) が選ばれます。列ごとに別の行が選ばれないよう、同時刻を1件に絞りたいなら ORDER BY ordered_at, id と主キーまで並べます。
QUALIFY(BigQuery・Snowflake・DuckDB)
窓関数の結果で直接絞り込める構文です。DuckDB 1.5.6 で実行しました。
SELECT id, member_id, ordered_at, amount
FROM orders
QUALIFY ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC) = 1
ORDER BY member_id;
┌───────┬───────────┬─────────────────────┬────────┐
│ id │ member_id │ ordered_at │ amount │
├───────┼───────────┼─────────────────────┼────────┤
│ 2 │ 101 │ 2026-10-03 18:30:00 │ 3400 │
│ 5 │ 102 │ 2026-10-05 08:15:00 │ 1900 │
│ 6 │ 103 │ 2026-09-28 20:00:00 │ 5600 │
└───────┴───────────┴─────────────────────┴────────┘
よくある応用
条件付きの最新1件(例:出荷済みの注文だけ)
WHERE は窓関数より先に効くので、内側に書きます。外側に書くと「全注文の最新が出荷済みでない会員」が消えてしまいます。
SELECT * FROM (
SELECT o.*,
ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC) AS rn
FROM orders o
WHERE status = 'SHIPPED' -- 内側で絞る
) t
WHERE rn = 1;
最新1件と、1つ前の値を並べる
LAG() を使うと、同じ行に前回の値を出せます。
SELECT * FROM (
SELECT o.*,
LAG(amount) OVER (PARTITION BY member_id ORDER BY ordered_at, id) AS prev_amount,
ROW_NUMBER() OVER (PARTITION BY member_id
ORDER BY ordered_at DESC, id DESC) AS rn
FROM orders o
) t
WHERE rn = 1;
日時が NULL の行があるとき
ORDER BY ordered_at DESC で NULL がどこに来るかは DB で違います。PostgreSQL と Oracle は降順で NULL が先頭(=最新扱い)、MySQL と SQLite と SQL Server は降順で NULL が末尾です。NULL を最新にしたくないなら、PostgreSQL・Oracle では ORDER BY ordered_at DESC NULLS LAST を明示します。
よくある質問
Q. MySQL 5.7 で ROW_NUMBER が使えません。
A. MySQL の窓関数は 8.0 からです。5.7 では③(GROUP BY+JOIN)を使い、同時刻を1件に絞る必要があれば GROUP BY をもう1段重ねて MAX(id) を取ります。
Q. ROW_NUMBER と RANK のどちらを使うべきですか。
A. 「会員ごとに必ず1行」が欲しいなら ROW_NUMBER()、「同じ日時なら全部」欲しいなら RANK() です。画面表示や後続の結合で1行を前提にするなら ROW_NUMBER() が安全です。
Q. ORDER BY に id を足す理由は何ですか。 A. 同じ日時の行がある場合、どちらを1番にするかを SQL が決められず、実行のたびに結果が変わる可能性があるためです。主キーのような一意な列を最後に足すと、結果が毎回同じになります。
Q. 最新の1件で UPDATE や DELETE をしたいです。
A. まず SELECT で①を書いて対象の id が合っているかを確かめ、その id を WHERE id IN (...) に渡すと安全です。MySQL は同じ表を更新しながらサブクエリで参照する書き方に制約があるため、一時テーブルか JOIN を使う形にします。
Q. どの書き方が一番速いですか。
A. 今回の100万件では MySQL が③、PostgreSQL が⑦でした。ただしデータの偏りや索引で変わるので、本番に近い件数で EXPLAIN を見て決めるのが確実です。
まとめ
- 基本は
ROW_NUMBER() OVER (PARTITION BY グループ ORDER BY 日時 DESC, 主キー DESC)でrn = 1を残す GROUP BYだけでは「グループの中の1行」は選べない。MySQL と PostgreSQL はエラー、SQLite は独自の動き- 同時刻を全部出したいなら
RANK()、1件に絞るならORDER BYに主キーを足したROW_NUMBER() - ②相関サブクエリと④NOT EXISTSは、100万件で数秒〜18秒。本番の大きな表では避ける
- 速さは DB の得意で決まる:MySQL は③
GROUP BY+JOIN(44ms)、PostgreSQL は⑦LATERAL(47〜75ms) - 索引は
(グループ列, 日時列 DESC, 主キー DESC)を1本作ると、①⑥⑦がまとめて速くなる
参考・出典
確認日はいずれも 2026年10月10日です。
- MySQL 8.0 Reference Manual「Window Functions」:https://dev.mysql.com/doc/refman/8.0/en/window-functions.html
- MySQL 8.0 Reference Manual「MySQL Handling of GROUP BY」:https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
- MySQL 8.0 Reference Manual「Lateral Derived Tables」:https://dev.mysql.com/doc/refman/8.0/en/lateral-derived-tables.html
- PostgreSQL 16 文書「SELECT(DISTINCT 句・LATERAL)」:https://www.postgresql.org/docs/16/sql-select.html
- PostgreSQL 16 文書「Window Functions」:https://www.postgresql.org/docs/16/functions-window.html
- SQLite「SELECT(Bare columns in an aggregate query)」:https://www.sqlite.org/lang_select.html
- Microsoft Learn「FROM 句と JOIN、APPLY」「TOP (Transact-SQL)」:https://learn.microsoft.com/ja-jp/sql/t-sql/queries/from-transact-sql 、https://learn.microsoft.com/ja-jp/sql/t-sql/queries/top-transact-sql
- Oracle Database SQL Language Reference「FIRST / LAST(KEEP)」:https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/FIRST.html
- DuckDB「QUALIFY Clause」:https://duckdb.org/docs/sql/query_syntax/qualify
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「SQLでグループごとに最新の1件を取得|6方式をDB別に100万件で実測」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。