- PR -

ユニークなIDの自動生成

投稿者投稿内容
忠犬
大ベテラン
会議室デビュー日: 2006/05/01
投稿数: 109
投稿日時: 2007-09-06 15:09
空いている中で、最小のIDを知りたいなら、以下のSQLで拾えると思います。

コード:
select
  max(ID)+1 as empty_ID
 from 
  (select 0 as ID
   union
   select ID from t1) as z
 where ID<(
           select min(ID) as ID
            from(
                 select
                   (select count(*) from t1 where ID<=x.ID) as rownum,
                   ID
                  from t1 as x
                ) as y
            where rownum<>ID
          )



拾ったIDでinsertするには、次のようなSQLで可能です。

コード:
insert into t1
 select
   max(ID)+1 as empty_ID,  -- ID列の挿入値
   'AA'                    -- NAME列の挿入値
  from 
   (select 0 as ID
    union
    select ID from t1) as z
  where ID<(
            select min(ID) as ID
             from(
                  select
                    (select count(*) from t1 where ID<=x.ID) as rownum,
                    ID
                   from t1 as x
                ) as y
             where rownum<>ID
           )

忠犬
大ベテラン
会議室デビュー日: 2006/05/01
投稿数: 109
投稿日時: 2007-09-07 13:30
前回提示したSQLは、もっと簡単にできました。

コード:
select min(rownum) as empty_ID
 from(
      select
        (select count(*) from t1 where ID<=x.ID) as rownum,
        ID
       from t1 as x
     ) as y
       where rownum<ID



これを、insertに利用すると、以下のようなSQLになります。

コード:
insert into t1
select
  min(rownum) as empty_ID,     -- IDへの挿入値
  'aa'                         -- NAMEへの挿入値
 from(
      select
        (select count(*) from t1 where ID<=x.ID) as rownum,
        ID
       from t1 as x
     ) as y
       where rownum<ID


ひろ
会議室デビュー日: 2007/07/31
投稿数: 9
投稿日時: 2007-09-10 14:41
>shimixさん
むぅ、コピーとは違うのですか・・・
なにか似て非なる(まったく違う?)概念があるのですね。
変に理解せずちゃんと調べます。

>よっしーさん
追加・更新・削除は今のところ一箇所からしかしない仕様に
なっているので大丈夫です。
でも同時書き込みができるように拡張するとなるとなると
色々と気を使うことは多いようですね。気をつけます。

>忠犬さん
例示ありがとうございます。
試してみます。
ひろ
会議室デビュー日: 2007/07/31
投稿数: 9
投稿日時: 2007-09-13 11:37
忠犬さんのselect文はIDに抜けがない場合にnullが返ってきてしまったので、
結果がnullだった場合は、(IDの最大値)+1を返すように改良してみました。
一応、報告させていただきます。
なにかご指摘があればお願いします。

コード:

select
(case when z.emp_ID is null then (select max(ID+1) from t1) else z.emp_KEY end) as final_emp_ID
from (
select min(y.rownum) as emp_ID
from (
select (select count(*) from t1 where ID<=x.ID) as rownum, ID from t1 as x
) as y
where y.rownum < y.ID
) as z;



[ メッセージ編集済み 編集者: ひろ 編集日時 2007-09-13 12:52 ]
よっしー
大ベテラン
会議室デビュー日: 2007/05/17
投稿数: 143
投稿日時: 2007-09-13 12:45
件数が0件のときは1が返るようになっていますか?
ひろ
会議室デビュー日: 2007/07/31
投稿数: 9
投稿日時: 2007-09-13 13:02
引用:

よっしーさんの書き込み (2007-09-13 12:45) より:
件数が0件のときは1が返るようになっていますか?



返って・・・きませんね。
もう一まわりたして、
select (case when final_tmp_id is null then 1 else final_tmp_id end)
from(<↑のSQL文>)as a;
ってやったらできるんでしょうけど、もう少しスマートな書き方はないもんですかね・・・

[ メッセージ編集済み 編集者: ひろ 編集日時 2007-09-13 13:05 ]
よっしー
大ベテラン
会議室デビュー日: 2007/05/17
投稿数: 143
投稿日時: 2007-09-13 13:52
is nullでなく、isnullを使うとか。
忠犬
大ベテラン
会議室デビュー日: 2006/05/01
投稿数: 109
投稿日時: 2007-09-13 23:08
次の2点に対応しました。

(1)1件も格納されていない場合→1を返す
(2)1件以上格納されているが、空がない場合→max(ID)+1を返す

具体的には、coalesce関数で対応しています。
コード:
coalesce(min(rownum),(select max(ID)+1 from t1),1) 



<訂正版SQL>
コード:
select
  coalesce(min(rownum),(select max(ID)+1 from t1),1) as empty_ID
 from(
      select
        (select count(*) from t1 where ID<=x.ID) as rownum,
        ID
       from t1 as x
     ) as y
       where rownum<ID

スキルアップ/キャリアアップ(JOB@IT)