データ作成ツール

 

(8.0.22)
仕様:
パラメータ引数1: データ件数
パラメータ引数2: テーブル名

ディクショナリからテーブル一覧を取得
各テーブルごとに、カラム名、データ型、データ長さを取得
各テーブルごとに、主キー先頭カラム名、主キー現在最大値を取得
データ型に応じてランダム値をセットするinsert文を作成 ※主キー制約の先頭カラムについては重複しない連番をセットする
作成したinsert文を指定回数実行。 ※重複値エラーはメッセージ出力

drop procedure proc_ins;
delimiter //
create procedure proc_ins(in param1 int,in param2 varchar(100) )
begin

declare sql_text varchar(4000);
declare tab_name varchar(30);
declare pcolname varchar(30);
declare maxval varchar(100);
declare colnames varchar(4000);
declare date_flg int;

-- カーソル定義
declare vdone1 int;
declare cur1 cursor for select table_name from information_schema.tables
                        where table_schema=database()
                        and table_name = coalesce(param2,table_name)
                        order by table_name;

declare continue handler for sqlstate '02000' set vdone1 = 1;

set vdone1 = 0;
open cur1;
fetch cur1 into tab_name;
while vdone1 != 1 do
  select tab_name;
  set date_flg = 0;
  
  -- insert文のカラム部分作成
  select group_concat(column_name order by ordinal_position separator ',') into colnames
  from information_schema.columns
  where table_schema = database()
  and table_name = tab_name;

  set sql_text := concat('insert into ',tab_name,'(',colnames,')  select ');

  -- 主キー先頭カラムの取得
  begin
    declare continue handler for sqlstate '02000' set pcolname = NULL ;

    select column_name into pcolname
    from information_schema.statistics
    where table_schema = database()
    and table_name = tab_name
    and index_name = 'PRIMARY'
    order by seq_in_index
    limit 1;
  end;
  select pcolname;

  -- decimal型の場合、numeric_precision - numeric_scale に格納可能な整数部分の桁数が入る
  -- int型の場合、最大値2147483647
  -- bigint型の場合、最大値9223372036854775807
  -- char,varchar型の場合、character_maximum_lengthに格納可能な文字長が入る

  begin
    declare vdone2 int;
    declare v_column_name varchar(64);
    declare v_data_type longtext;
    declare v_character_maximum_length bigint;
    declare v_numeric_precision bigint unsigned;
    declare v_numeric_scale bigint unsigned;

    declare cur2 cursor for select column_name,data_type,character_maximum_length,numeric_precision,numeric_scale
                            from information_schema.columns
                            where table_schema = database()
                            and table_name = tab_name
                            order by ordinal_position;
    declare continue handler for sqlstate '02000' set vdone2 = 1;

    set vdone2 = 0;
    open cur2;
    fetch cur2 into v_column_name,v_data_type,v_character_maximum_length,v_numeric_precision,v_numeric_scale;
    while vdone2 != 1 do

      if pcolname = v_column_name then
        set @maxval := null;
        case
          when v_data_type in ('int','bigint','decimal') then
            set @sql_text := concat('select cast(max(',pcolname,') as char) into @maxval from ', tab_name);
            prepare stmt from @sql_text;
            execute stmt ;
            deallocate prepare stmt;
            set maxval := coalesce(@maxval,'0');
            set sql_text := concat(sql_text,'?,');

          when v_data_type in ('char','varchar') then
            set @sql_text := concat('select cast(max(cast(',pcolname,' as decimal) ) as char) into @maxval from ',tab_name,' where regexp_like(',pcolname,', ''^[0-9]+$'')');
            prepare stmt from @sql_text;
            execute stmt ;
            deallocate prepare stmt;
            set maxval := coalesce(@maxval,'0');
            set sql_text := concat(sql_text,'lpad(?,',v_character_maximum_length,',''0''),');

          when v_data_type in ('date','datetime','timestamp') then
            set @sql_text := concat('select cast(max(UNIX_TIMESTAMP(',pcolname,') ) as char) into @maxval from ',tab_name);
            prepare stmt from @sql_text;
            execute stmt ;
            deallocate prepare stmt;
            set maxval := coalesce(@maxval,'946652400');
            set sql_text := concat(sql_text,'FROM_UNIXTIME(?),');
            if  v_data_type in ('date') then
              set date_flg = 1;
            end if;
            
          else  set sql_text := concat(sql_text,'NULL,');
        end case;

      else

        case
          when v_data_type = 'int' then
            set sql_text := concat(sql_text,'floor(rand() * 2147483647),');
          when v_data_type = 'bigint' then
            set sql_text := concat(sql_text,'floor(rand() * 9223372036854775807),');
          when v_data_type = 'decimal' then
            set sql_text := concat(sql_text,'floor(rand() * power(10,(', cast((v_numeric_precision - v_numeric_scale) as char) ,') ) ),');

          when v_data_type in ('char','varchar') then
            set sql_text := concat(sql_text,'substring(md5(rand() ), 1, ',cast(v_character_maximum_length as char),'),');

          when v_data_type in ('date','datetime','timestamp') then
            set sql_text := concat(sql_text,'date_add(''2000-01-01'', interval floor(7600 * rand() ) day),');

          else  set sql_text := concat(sql_text,'NULL,');
        end case;
      end if;

      fetch cur2 into v_column_name,v_data_type,v_character_maximum_length,v_numeric_precision,v_numeric_scale;
    end while;
    close cur2;
  end;

  set sql_text := substring(sql_text,1, length(sql_text) -1);
  select sql_text;

  -- データ作成ループ
  begin
    declare continue handler for sqlstate '23000' begin select 'ER_DUP_KEY'; end;
    set @i := 1;

    if date_flg = 1 then
      set @maxval := cast((cast(maxval as decimal) + 24*3600) as char);
    else
      set @maxval := cast((cast(maxval as decimal) + 1) as char);
    end if;

    set @sql_text := sql_text;
    while @i <= param1 do
      prepare stmt from @sql_text;

      if pcolname is not null then
        execute stmt using @maxval;
      else
        execute stmt;
      end if;

      deallocate prepare stmt;

      set @i := @i + 1;
      if date_flg = 1 then
        set @maxval := cast((cast(@maxval as decimal) + 24*3600) as char);
      else
        set @maxval := cast((cast(@maxval as decimal) + 1) as char);
      end if;
    end while;
  end;

  fetch cur1 into tab_name;
end while;
close cur1;

end
//
delimiter ;


-- テスト用SQL

select concat('drop table ',table_name,';') from information_schema.tables where table_schema=database();

create table tab11(col1 int primary key,col2 varchar(10),col3 datetime);
create table tab12(col1 varchar(10) primary key,col2 datetime,col3 int);
create table tab13(col1 datetime primary key,col2 int,col3 varchar(10) );
create table tab14(col1 datetime primary key,col2 int,col3 varchar(10) );
create table tab15(col1 date primary key,col2 int,col3 varchar(10) );

create table tab21(col1 int,col2 varchar(10),col3 datetime);
create table tab22(col1 varchar(10),col2 datetime,col3 int);
create table tab23(col1 datetime,col2 int,col3 varchar(10) );

create table tab31(col1 int,col2 varchar(10),col3 datetime);
alter table tab31 add constraint tab31pk primary key(col1,col2);

create table tab41(
col1 int,
col2 bigint,
col3 decimal(10),
col4 decimal(10,2),
col5 varchar(10),
col6 char(10),
col7 date,
col8 datetime,
col9 timestamp,
col10 blob,
col11 text);


call proc_ins(10,null);
call proc_ins(10,'tab11');

select * from tab11;
select * from tab12;
select * from tab13;
select * from tab14;
select * from tab15;

select * from tab21;
select * from tab22;
select * from tab23;

select * from tab31;
select * from tab41;

insert into tab12 values('AAA',CURDATE(),1);
insert into tab12 values('4444444',CURDATE(),1);
call proc_ins(10,null);
call proc_ins(300,null);

 

(19c)

仕様:
パラメータ引数1: データ件数
パラメータ引数2: テーブル名

ディクショナリからテーブル一覧を取得
各テーブルごとに、カラム名、データ型、データ長さを取得
各テーブルごとに、主キー先頭カラム名、主キー現在最大値を取得
データ型に応じてランダム値をセットするinsert文を作成 ※主キー制約の先頭カラムについては重複しない連番をセットする
作成したinsert文を指定回数実行。 ※重複値エラーはメッセージ出力

 


set serveroutput on 
create or replace procedure proc_ins(param1 in number default 100,param2 in varchar2 default null)
authid current_user
as
sql_text varchar2(4000);

pcolname varchar2(30);
maxval varchar2(100);
sql_text2 varchar2(4000);

int_flg int;
char_flg int;
date_flg int;
timestamp_flg int;

cursor cur1 is select table_name
               from user_tables
               where table_name not like 'SYS%'
               and table_name = nvl(param2,table_name)
               order by table_name;
cursor cur2(vparam1 in varchar2) is select column_name,data_type,data_length,data_precision,data_scale
                                    from user_tab_columns where table_name = vparam1 order by column_id;

begin
  for c1 in cur1 loop
    dbms_output.put_line(c1.table_name);
    int_flg := 0;
    char_flg := 0;
    date_flg := 0;
    timestamp_flg := 0;
    sql_text :='insert into ' || c1.table_name || '(';

    for c2 in cur2(c1.table_name) loop
      sql_text := sql_text || c2.column_name || ',';
    end loop;

    sql_text := substr(sql_text,1, length(sql_text) -1) || ') select ' ;

    begin
      select T2.column_name into pcolname
      from user_constraints T1
      inner join user_ind_columns T2
      on T1.index_name = T2.index_name
      where T1.constraint_type = 'P'
      and T2.column_position = 1
      and T1.table_name = c1.table_name
      ;
    exception
      when others then
        pcolname := NULL;
    end;
    dbms_output.put_line('pcolname='||pcolname);

    -- number型の場合、data_precision - data_scale に格納可能な整数部分の桁数が入る
    -- char,varchar2型の場合、data_lengthに格納可能なバイト長が入る
    -- nchar,nvarchar2型の場合、data_lengthに格納可能なバイト長が入る。これを1/2した値が最大文字長となる。

    for c2 in cur2(c1.table_name) loop
      if pcolname = c2.column_name then
        maxval := NULL;
        case
          when c2.data_type = 'NUMBER' then
            sql_text2 := 'select to_char(max(' || pcolname || ') ) from ' || c1.table_name;
            begin
              execute immediate sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '0';
            end if;
            sql_text := sql_text || 'to_char(:maxval),';
            int_flg := 1;

          when c2.data_type in ('CHAR','VARCHAR2','NCHAR','NVARCHAR2') then
            sql_text2 := 'select to_char(max(to_number(' || pcolname || ') ) ) from ' || c1.table_name || ' where  regexp_like( ' || pcolname || ',''^[0-9]+$'')';
            begin
              execute immediate sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '0';
            end if;
            if c2.data_type in ('CHAR','VARCHAR2') then
              sql_text := sql_text || 'lpad(:maxval,'||c2.data_length||',''0''),';
            else
              sql_text := sql_text || 'lpad(:maxval,'||c2.data_length/2||',''0''),';
            end if;
            char_flg := 1;

          when c2.data_type = 'DATE' then
            sql_text2 := 'select max(to_char(' || pcolname || ',''YYYYMMDD'') ) from ' || c1.table_name;
            begin
              execute immediate sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '20200101';
            end if;
            sql_text := sql_text || 'to_date(:maxval,''YYYYMMDD''),';
            date_flg := 1;

          when c2.data_type like 'TIMESTAMP%' then
            sql_text2 := 'select max(to_char(' || pcolname || ',''YYYYMMDDHH24MISS'') ) from ' || c1.table_name;
            begin
              execute immediate sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '20200101000000';
            end if;
            sql_text := sql_text || 'to_date(:maxval,''YYYYMMDDHH24MISS''),';
            timestamp_flg := 1;

          else  sql_text := sql_text ||  'NULL,';
        end case;

      else

        case
          when c2.data_type = 'NUMBER' then
            sql_text := sql_text ||  'floor(dbms_random.value(1, power(10,'|| to_char(nvl(c2.data_precision,9) - nvl(c2.data_scale,0) ) ||') ) ),';
          when c2.data_type in ('CHAR','VARCHAR2','NCHAR','NVARCHAR2') then
            sql_text := sql_text ||  'substr(standard_hash(dbms_random.value(), ''MD5''),1,'|| 
            case when c2.data_type in ('NCHAR','NVARCHAR2') then to_char(nvl(c2.data_length/2,1) ) else to_char(nvl(c2.data_length,1) ) end 
            ||'),';
          when c2.data_type = 'DATE' or  c2.data_type like 'TIMESTAMP%' then
            sql_text := sql_text ||  'to_date(''20000101'',''yyyymmdd'') + floor(dbms_random.value(0, 7600) ),';
          else  sql_text := sql_text ||  'NULL,';
        end case;
      end if;

    end loop;

    sql_text := substr(sql_text,1, length(sql_text) -1) || ' from dual' ;
    dbms_output.put_line(sql_text);

    for i in 1..param1 loop
      if pcolname is not null then
        -- データ型に応じたインクリメント
        if int_flg = 1 then
          maxval := to_char(to_number(maxval) + 1);
        elsif char_flg = 1 then
          maxval := to_char(to_number(maxval) + 1);
        elsif date_flg = 1 then
          maxval := to_char((to_date(maxval,'YYYYMMDD') + 1),'YYYYMMDD');
        elsif timestamp_flg = 1 then
          maxval := to_char((to_date(maxval,'YYYYMMDDHH24MISS') + 1/24/3600),'YYYYMMDDHH24MISS');
        end if;
      end if;
      begin
        if pcolname is not null and ( int_flg = 1 or char_flg = 1 or date_flg = 1 or timestamp_flg = 1 ) then
          execute immediate sql_text using maxval;
        else
          execute immediate sql_text;
        end if;
      exception
        when DUP_VAL_ON_INDEX then
        dbms_output.put_line('DUP_VAL_ON_INDEX !');
      when others then
        raise;
      end;
    end loop;

    commit;
  end loop;
end;
/
show error;

 

-- テスト用SQL

select 'drop table ' || table_name || ' purge;' from user_tables;

create table tab11(col1 int primary key,col2 varchar2(10),col3 timestamp);
create table tab12(col1 varchar2(10) primary key,col2 timestamp,col3 int);
create table tab13(col1 timestamp primary key,col2 int,col3 varchar2(10) );
create table tab14(col1 date primary key,col2 int,col3 varchar2(10) );

create table tab21(col1 int,col2 varchar2(10),col3 timestamp);
create table tab22(col1 varchar2(10),col2 timestamp,col3 int);
create table tab23(col1 timestamp,col2 int,col3 varchar2(10) );

create table tab31(col1 int,col2 varchar2(10),col3 timestamp);
alter table tab31 add constraint tab31pk primary key(col1,col2);

create table tab41(
col1 int,
col2 number(10),
col3 number(10,2),
col4 varchar2(10),
col5 char(10),
col6 nvarchar2(10),
col7 nchar(10),
col8 date,
col9 timestamp,
col10 blob,
col11 clob);

exec proc_ins();
exec proc_ins(10);
exec proc_ins(10,NULL);
exec proc_ins(10,'TAB11');

select * from tab11;
select * from tab12;
select * from tab13;
select * from tab14;

select * from tab21;
select * from tab22;
select * from tab23;

select * from tab31;
select * from tab41;

insert into tab12 values('AAA',sysdate,1);
insert into tab12 values('4444444',sysdate,1);
exec proc_ins(10,NULL);
exec proc_ins(300,NULL);

 

(13)
仕様:
パラメータ引数1: データ件数
パラメータ引数2: テーブル名

ディクショナリからテーブル一覧を取得
各テーブルごとに、カラム名、データ型、データ長さを取得
各テーブルごとに、主キー先頭カラム名、主キー現在最大値を取得
データ型に応じてランダム値をセットするinsert文を作成 ※主キー制約の先頭カラムについては重複しない連番をセットする
作成したinsert文を指定回数実行。 ※重複値エラーはメッセージ出力

 

create or replace procedure proc_ins(param1 in int default 100, param2 in varchar(100) default null)
language plpgsql
as $$
declare

sql_text varchar(4000);

pcolname varchar(30);
maxval varchar(100);
sql_text2 varchar(4000);

int_flg int;
char_flg int;
date_flg int;
timestamp_flg int;

cur1 cursor for select tablename from pg_tables
                where schemaname = 'public'
                and tablename = coalesce(param2,tablename)
                order by tablename;
cur2 cursor(vparam1 varchar) for select column_name,data_type,character_maximum_length,numeric_precision,numeric_scale
                             from information_schema.columns
                             where table_schema = 'public'
                             and table_name = vparam1
                             order by ordinal_position;


begin
  for c1 in cur1 loop
    raise notice 'c1.tablename=%', c1.tablename;
    int_flg := 0;
    char_flg := 0;
    date_flg := 0;
    timestamp_flg := 0;
    sql_text :='insert into ' || c1.tablename || '(';

    for c2 in cur2(c1.tablename) loop
      sql_text := sql_text || c2.column_name || ',';
    end loop;

    sql_text := substr(sql_text,1, length(sql_text) -1) || ') select ' ;

    begin
      select 
      case
        when position(',' in T1.indexdef) > 0 then
          substring(T1.indexdef from (position('(' in T1.indexdef) )+1 for (position(',' in T1.indexdef) - position('(' in T1.indexdef)-1) ) 
        else
          substring(T1.indexdef from (position('(' in T1.indexdef) )+1 for (position(')' in T1.indexdef) - position('(' in T1.indexdef)-1) )
      end into pcolname
      from pg_indexes T1
      inner join information_schema.table_constraints T2
      on T1.schemaname = T2.table_schema
      and T1.tablename = T2.table_name
      and T2.constraint_type = 'PRIMARY KEY'
      and T1.indexname = T2.constraint_name
      where T1.schemaname = 'public'
      and T1.tablename = c1.tablename
      ;

    exception
      when others then
        pcolname := NULL;
    end;
    raise notice 'pcolname=%', pcolname;

    -- numeric型の場合、numeric_precision - numeric_scale に格納可能な整数部分の桁数が入る
    -- integer型の場合、最大値2147483647
    -- bigint型の場合、最大値9223372036854775807
    -- char,varchar型の場合、character_maximum_lengthに格納可能な文字長が入る

    for c2 in cur2(c1.tablename) loop
      if pcolname = c2.column_name then
        maxval := null;
        case
          when c2.data_type in ('integer','bigint','numeric') then
            sql_text2 := 'select max(' || pcolname || ') from ' || c1.tablename;
            begin
              execute sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '0';
            end if;
            
            sql_text := sql_text || '$1::bigint,';
            int_flg = 1;
          when c2.data_type like 'character%' then
            sql_text2 := 'select (max(' || pcolname || '::numeric) )::varchar from ' || c1.tablename || ' where ' || pcolname || ' ~ ''^[0-9]+$''';
            begin
              execute sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '0';
            end if;
            sql_text := sql_text || 'lpad($1,' ||c2.character_maximum_length ||',''0''),';
            char_flg = 1;

          when c2.data_type = 'date'  then
            sql_text2 := 'select max(to_char(' || pcolname || ',''YYYY/MM/DD'') ) from ' || c1.tablename;
            begin
              execute sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '2020/01/01';
            end if;
            sql_text := sql_text || '$1::date,';
            date_flg = 1;
          when c2.data_type like 'timestamp%' then
            sql_text2 := 'select max(to_char(' || pcolname || ',''YYYY/MM/DD HH24:MI:SS'') ) from ' || c1.tablename;
            begin
              execute sql_text2 into maxval;
            exception
              when others then
                raise;
            end;
            if maxval is null then
              maxval := '2020/01/01/ 00:00:00';
            end if;
            sql_text := sql_text || '$1::timestamp,';
            timestamp_flg=1;
          else  sql_text := sql_text ||  'NULL,';
            
        end case;
        
      else
      
        case
          when c2.data_type = 'integer' then
            sql_text := sql_text ||  'floor(random() * 2147483647),';
          when c2.data_type = 'bigint' then
            sql_text := sql_text ||  'floor(random() * 9223372036854775807),';
          when c2.data_type = 'numeric' then
            sql_text := sql_text ||  'floor(random() * power(10, ' || (c2.numeric_precision - c2.numeric_scale)::varchar || ') ),';
          when c2.data_type like 'character%' then
            sql_text := sql_text ||  'substr(md5(random()::text), 1, ' || c2.character_maximum_length::varchar || '),';
          when c2.data_type = 'date' or  c2.data_type like 'timestamp%' then
            sql_text := sql_text ||  '''2000-01-01''::date + CAST( floor(7600 * random() ) || ''days'' AS interval),';
          else  sql_text := sql_text ||  'NULL,';
        end case;
      end if;
      
    end loop;

    sql_text := substr(sql_text,1, length(sql_text) -1);
    raise notice 'sql_text=%', sql_text;

    for i in 1..param1 loop
      if pcolname is not null then
        -- データ型に応じたインクリメント
        if int_flg = 1 then
          maxval := (maxval::bigint + 1)::varchar;
        elseif char_flg = 1 then
          maxval := (maxval::bigint + 1)::varchar;
        elseif date_flg = 1 then
          maxval := (maxval::date + '1 day'::interval)::varchar;
        elseif timestamp_flg = 1 then
          maxval := (maxval::timestamp + '1 sec'::interval)::varchar;
        end if;
      end if;
      
      begin
        if pcolname is not null and ( int_flg = 1 or char_flg= 1 or date_flg = 1 or timestamp_flg = 1 ) then
          execute sql_text using maxval;
        else
          execute sql_text;
        end if;
      exception
        when unique_violation then
          raise notice 'unique_violation !';
        when others then
          raise;
      end;
    end loop;

    commit;
  end loop;

end;
$$;


-- テスト用SQL

select 'drop table ' || tablename || ' ;' from pg_tables where schemaname = 'public';

create table tab11(col1 int primary key,col2 varchar(10),col3 timestamp);
create table tab12(col1 varchar(10) primary key,col2 timestamp,col3 int);
create table tab13(col1 timestamp primary key,col2 int,col3 varchar(10) );
create table tab14(col1 date primary key,col2 int,col3 varchar(10) );

create table tab21(col1 int,col2 varchar(10),col3 timestamp);
create table tab22(col1 varchar(10),col2 timestamp,col3 int);
create table tab23(col1 timestamp,col2 int,col3 varchar(10) );

create table tab31(col1 int,col2 varchar(10),col3 timestamp);
alter table tab31 add constraint tab31pk primary key(col1,col2);

create table tab41(
col1 int,
col2 bigint,
col3 numeric(10),
col4 numeric(10,2),
col5 varchar(10),
col6 char(10),
col7 date,
col8 timestamp,
col9 bytea,
col10 text);

call proc_ins();
call proc_ins(10);
call proc_ins(10,null);
call proc_ins(10,'tab11');

select * from tab11;
select * from tab12;
select * from tab13;
select * from tab14;

select * from tab21;
select * from tab22;
select * from tab23;

select * from tab31;
select * from tab41;


insert into tab12 values('AAA',clock_timestamp(),1);
insert into tab12 values('4444444',clock_timestamp(),1);
call proc_ins(10,null);
call proc_ins(300,null);

 

 

(2019)
仕様:
パラメータ引数1: データ件数
パラメータ引数2: テーブル名

ディクショナリからテーブル一覧を取得
各テーブルごとに、カラム名、データ型、データ長さを取得
各テーブルごとに、主キー先頭カラム名、主キー現在最大値を取得
データ型に応じてランダム値をセットするinsert文を作成 ※主キー制約の先頭カラムについては重複しない連番をセットする
作成したinsert文を指定回数実行。 ※重複値エラーはメッセージ出力


create or alter procedure proc_ins(@param1 int = 100,@param2 varchar(100) = null)
as
begin
set nocount on;

declare @sql_text nvarchar(4000);

declare @pcolname varchar(30);
declare @sql_text2 nvarchar(4000);
declare @params nvarchar(4000);

declare @tab_name varchar(30);
declare @colnames varchar(4000);
declare @i bigint;

declare @int_flg int;
declare @char_flg int;
declare @date_flg int;
declare @datetime2_flg int;

declare @maxval_int bigint;
declare @maxval_char varchar(100);
declare @maxval_date date;
declare @maxval_datetime2 datetime2;

declare cur1 cursor for select name from sys.tables where name = coalesce(@param2,name) order by name;


open cur1;
fetch next from cur1 into @tab_name;
while @@fetch_status = 0
  begin
    print @tab_name;
    set @int_flg = 0;
    set @char_flg = 0;
    set @date_flg = 0;
    set @datetime2_flg = 0;
    -- insert文のカラム部分作成
    set @colnames = ( select string_agg( name ,',') within group ( order by column_id ) 
                      from sys.columns
                      where object_name(object_id) = @tab_name
                      );
    set @sql_text = 'insert into '+@tab_name+'('+@colnames+') select ';

    -- 主キー先頭カラムの取得
    set @pcolname = ( select top 1 col_name(B.object_id,B.column_id)
                      from sys.indexes A  
                      inner join sys.index_columns B
                      on A.object_id = B.object_id 
                      and A.index_id = B.index_id  
                      where object_name(A.object_id) = @tab_name
                      and A.is_primary_key = 1
                      );
    print @pcolname;

    -- decimal,numeric型の場合、presicion - scale に格納可能な整数部分の桁数が入る
    -- int型の場合、最大値2147483647
    -- bigint型の場合、最大値9223372036854775807
    -- char,varchar型の場合、max_lengthに格納可能なバイト長が入る(ただし、maxの場合は-1)
    -- nchar,nvarchar型の場合、max_lengthに格納可能なバイト長が入る。これを1/2した値が最大文字長となる。(ただし、maxの場合は-1)

    begin
      declare @colname varchar(100);
      declare @system_type_id int;
      declare @max_length int;
      declare @precision int;
      declare @scale int;
      declare @max_length2 int;

      declare cur2 cursor for select name,system_type_id,max_length,precision,scale
                              from sys.columns
                              where object_name(object_id)  = @tab_name
                              order by column_id

      open cur2;
      fetch next from cur2 into @colname,@system_type_id,@max_length,@precision,@scale;
      while @@fetch_status = 0
        begin
        -- int-> 56   bigint-> 127 numeric-> 108 decimal-> 106
        -- char-> 175 varchar-> 167  nchar-> 239 nvarchar-> 231
        -- date-> 40  datetime2-> 42

        if @pcolname = @colname

          begin
            set @maxval_int = null;
            set @maxval_char = null;
            set @maxval_date = null;
            set @maxval_datetime2 = null;
            if @system_type_id in (56,127,108,106) 
              begin
                set @sql_text2 = 'select @maxval_int = max('+@pcolname+') from '+@tab_name;
                set @params = '@maxval_int varchar(100) OUT';
                execute sp_executesql @sql_text2, @params, @maxval_int OUT;

                set @maxval_int = coalesce(@maxval_int,0);
                set @sql_text = @sql_text + '@maxval_int,';
                set @int_flg = 1;
              end

            else if   @system_type_id in (175,167,239,231) 
              begin
                set @sql_text2 = 'select @maxval_char = cast(max(cast('+@pcolname+' as bigint) ) as varchar) from '+ @tab_name +' where ' + @pcolname +' not like ''%[^0-9]%''';
                set @params = '@maxval_char varchar(100) OUT';
                execute sp_executesql @sql_text2, @params, @maxval_char OUT;

                set @maxval_char = coalesce(@maxval_char,'0');
                set @sql_text = @sql_text + 'right(''000000000000000000000000000000''+@maxval_char,'+cast(@max_length as varchar)+'),';
                set @char_flg = 1;
              end

            else if   @system_type_id = 40
              begin
                set @sql_text2 = 'select @maxval_date = max('+@pcolname+') from '+@tab_name
                set @params = '@maxval_date varchar(100) OUT';
                execute sp_executesql @sql_text2, @params, @maxval_date OUT;

                set @maxval_date = coalesce(@maxval_date,cast('20000101' as date) );
                set @sql_text = @sql_text + '@maxval_date,';
                set @date_flg = 1;
              end

            else if   @system_type_id =42
              begin
                set @sql_text2 = 'select @maxval_datetime2 = max('+@pcolname+') from '+@tab_name
                set @params = '@maxval_datetime2 varchar(100) OUT';
                execute sp_executesql @sql_text2, @params, @maxval_datetime2 OUT;

                set @maxval_datetime2 = coalesce(@maxval_datetime2,cast('20000101 00:00:00' as datetime2) );
                set @sql_text = @sql_text + '@maxval_datetime2,';
                set @datetime2_flg = 1;
              end
              
            else set @sql_text = @sql_text+'NULL,';
          end;

        else

          begin
            if   @system_type_id = 56 
              set @sql_text = @sql_text + 'floor(rand() * 2147483647),';
            else if   @system_type_id = 127 
              set @sql_text = @sql_text + 'floor(rand() * 9223372036854775807),';
            else if   @system_type_id in (108,106) 
              set @sql_text = @sql_text + 'floor(rand() * power(cast(10 as bigint),cast(' + cast((@precision - @scale) as varchar) + ' as bigint) ) ),';
            else if   @system_type_id in (175,167,239,231) 
              begin
                if  @max_length = -1
                  set @max_length2 = 1000;
                else if @system_type_id in (239,231) 
                  set @max_length2 = @max_length/2;
                else  set @max_length2 = @max_length;

                set @sql_text = @sql_text + 'substring(master.dbo.fn_varbintohexstr(HASHBYTES(''MD5'',cast(rand() as varchar) ) ),3,' + cast(@max_length2 as varchar) + '),';
              end;
            else if   @system_type_id in (40,42) 
              set @sql_text = @sql_text + 'dateadd(day,floor(7600 * rand() ),''2000-01-01''),';
            else  set @sql_text = @sql_text+'NULL,';

          end;

      fetch next from cur2 into @colname,@system_type_id,@max_length,@precision,@scale;

      end
      close cur2;
      deallocate cur2;
    end;


    set @sql_text = substring(@sql_text,1,len(@sql_text)-1);
    print @sql_text;

    -- データ作成ループ

    set @i = 1;
    while (@i <= @param1)
      begin
        if @pcolname is not null
          begin
            -- データ型に応じたインクリメント
            if @int_flg = 1
              begin
                set @params = '@maxval_int bigint';
                set @maxval_int = @maxval_int + 1;
              end;
            else if @char_flg = 1
              begin
                set @params = '@maxval_char varchar(100)';
                set @maxval_char = cast((cast(@maxval_char as bigint) + 1) as varchar);
              end;
            else if @date_flg = 1
              begin
                set @params = '@maxval_date date';
                set @maxval_date = dateadd(day,1,@maxval_date);
              end;
            else if @datetime2_flg = 1
              begin
                set @params = '@maxval_datetime2 datetime2';
                set @maxval_datetime2 = dateadd(second,1,@maxval_datetime2);
              end;
          end;
        
        begin try
          if @pcolname is not null
            begin
              if @int_flg = 1
                begin
                  execute sp_executesql @sql_text, @params, @maxval_int;
                end;
              else if @char_flg = 1
                begin
                  execute sp_executesql @sql_text, @params, @maxval_char;
                end;
              else if @date_flg = 1
                begin
                  execute sp_executesql @sql_text, @params, @maxval_date;
                end;
              else if @datetime2_flg = 1
                begin
                  execute sp_executesql @sql_text, @params, @maxval_datetime2;
                end;
              else
                begin
                  execute (@sql_text)
                end;
            end;

          else
            begin
              execute (@sql_text)
            end;
        end try
        begin catch
          if error_number() = 2627
            print 'primary key violation';
          else throw;
        end catch;
        set @i = @i + 1;
      end;

    fetch next from cur1 into @tab_name;
  end
close cur1;
deallocate cur1;


end
go


-- テスト用SQL

select 'drop table ' + name + ' ;' from sys.tables;


create table tab11(col1 int primary key,col2 varchar(10),col3 datetime2);
create table tab12(col1 varchar(10) primary key,col2 datetime2,col3 int);
create table tab13(col1 datetime2 primary key,col2 int,col3 varchar(10) );
create table tab14(col1 date primary key,col2 int,col3 varchar(10) );

create table tab21(col1 int,col2 varchar(10),col3 datetime2);
create table tab22(col1 varchar(10),col2 datetime2,col3 int);
create table tab23(col1 datetime2,col2 int,col3 varchar(10) );

create table tab31(col1 int not null,col2 varchar(10) not null,col3 datetime2);
alter table tab31 add constraint tab31pk primary key(col1,col2);

create table tab41(
col1 int,
col2 bigint,
col3 numeric(10),
col4 numeric(10,2),
col5 decimal(10),
col6 decimal(10,2),
col7 varchar(10),
col8 char(10),
col9 nvarchar(10),
col10 nchar(10),
col11 date,
col12 datetime2,
col13 binary(10),
col14 varbinary(10),
col15 varchar(max),
col16 varbinary(max)
);

exec proc_ins;
exec proc_ins 10;
exec proc_ins 10, null;
exec proc_ins 10, 'tab11';


select * from tab11;
select * from tab12;
select * from tab13;
select * from tab14;

select * from tab21;
select * from tab22;
select * from tab23;

select * from tab31;
select * from tab41;

insert into tab12 values('AAA',GETDATE(),1);
insert into tab12 values('4444444',GETDATE(),1);

exec proc_ins 10, null;
exec proc_ins 300, null;