R3Dでできること
目次
1.同一テーブル内でのフィールド間の演算
①フィールド間での四則演算
②自動的に日付をセット
③自動的に売上日をセット
④行番号の自動採番
2.異なるテーブル間の演算
①コード値による名称の自動取得
②同じコードを持つ名称の一斉自動更新
③読出しのみの関数
④条件文を使う
⑤自動集計関数
⑥請求書データの自動作成
3.異なるデータベース間の演算
①他データベースとのデータ同期
②他データベースとの非同期関数
4.異なるサーバ間の演算
①リンクサーバの登録
②R3Dでの異なるサーバの記述
5.自動コード付
6.自動ログ書出し
7.統計データの自動作成
8.データ内容のチェック
9.ストアードプロシージャをR3Dの導出定義文から利用する
10.EXCELとの連携
11・データの依存関係の表示
上記の例は、「合計」が「数量」と「単価」を掛けることによって求められると定義した例です。次に、自動的に計算されるところをコマンドプロンプトからosqlを起動してその様子を見ます。f.はフィールドであることを示しています。
1>select 受注番号,行番号,商品コード,商品名,数量,単価, 合計
2> from 受注明細 where 受注番号=100 order by 行番号
3>go
受注番号 行番号 商品コード 商品名 数量
単価 合計
100 1 A001 マヨネーズ 2 198 369
100 2 A002 納豆 3 98 294
(2件処理されました)
1>insert into 受注明細(受注番号,行番号,商品コード,数量)
2> values(100,0,'A003',5) *1
3>go
(1件処理されました)
1>select 受注番号,行番号,商品コード,商品名,数量,単価,合計
2> from 受注明細 where 受注番号=100 order by 行番号
3>go
受注番号 行番号 商品コード 商品名 数量
単価 合計
100 1 A001 マヨネーズ 2 198 369
100 2 A002 納豆 3 98 294
100 3 A003 砂糖 5 208 1040
(3件処理されました)
1>
テーブル内の任意のフィールドが変更されたときに、日付と時間を「修正日時」に代入するという例です。先ほどの①の例でinsertした商品の「数量」を変更して、「修正日付」に日付と時間が自動的に代入されるところを見ます。なお、「getdate()」は、DBMSの標準関数です。
1>update 受注明細 set 数量=6
2> where 受注番号=100 and 行番号=3
3>go
(1件処理されました)
1>select 受注番号,行番号,商品名,数量,単価,合計,修正日時
2> from 受注明細 where 受注番号=100 order by 行番号
3>go
受注番号 行番号 商品名 数量 単価 合計 修正日時
100 1 マヨネーズ 2 198 369 2007-10-1 12:10:10
100 2 納豆 3 98 294 2007-10-1 12:11:12
100 3 砂糖 6 208 1248 2007-10-2 14:15:17 *1
1>
フィールド:売上合計 = f.売上数*f.単価 |
フィールド:売上日 =
if f.売上合計 is not null { convert(nvarchar(10),getdate(),111) } |
先ほどinsertしたデータに対して「売上数」に値を入れることによって、売上合計を自動的に求め、かつ、売上合計に値が入れられた(nullでない)ことをもって売上日に本日を代入する例です。
1>update 受注明細 set 売上数=6
2> where 受注番号=100 and 行番号=3 *1
3>go
(1件処理されました)
1>select 受注番号,行番号,商品名,単価,売上数,売上合計,売上日
2> from 受注明細 where 受注番号=100 order by 行番号
3>go
受注番号 行番号 商品名 単価 売上数 売上合計 売上日
100 1 マヨネーズ 198
100 2 納豆 98
100 3 砂糖 208 6 1248 2007-10-2 *2
1>
上記の例は、受注明細がinsertされたときは、自動的にその受注番号での行番号の最大値+1を持ってきて、それを行番号に代入しています。
getmaxはR3D関数で最大値を読み出す意味です。
1>insert into 受注明細(受注番号,行番号,商品コード,数量)
2> values(100,0,'A003',5)
3>go
(1件処理されました)
1>select 受注番号,行番号,商品コード,商品名,数量,単価,合計
2> from 受注明細 where 受注番号=100 order by 行番号
3>go
受注番号 行番号 商品コード 商品名 数量
単価 合計
100 1 A001 マヨネーズ 2 198 369
100 2 A002 納豆 3 98 294
100 3 A003 砂糖 5 208 1040 *1
(3件処理されました)
1>
フィールド:商品名 =
val(t.商品マスター.商品名[ where t.商品マスター.商品コード=f.商品コード]) |
フィールド:単価 =
val(t.商品マスター.単価[ where t.商品マスター.商品コード=f.商品コード]) |
商品コードが与えられたときに、商品名や単価が商品マスターから自動的に持って来られて代入される例です。
「t.」はテーブルであることを示しています。
1>select * from 商品マスター *1
2>go
商品コード 商品名 商品種別 単価 単位
在庫数
A001 マヨネーズ 食品 198 本 300
A002 納豆 食品 98 パック 70
A003 砂糖 食品 208 袋 150
A004 バター 食品 168 個 200
(4件処理されました)
1>insert into 受注明細(受注番号,行番号,商品コード,数量)
2> values(100,0,'A003',5) *2
3>go
(1件処理されました)
1>select 受注番号,行番号,商品コード,商品名,数量,単価,合計
2> from 受注明細 where 受注番号=100 order by 行番号 *3
3>go
受注番号 行番号 商品コード 商品名 数量
単価 合計
100 1 A001 マヨネーズ 2 198 369
100 2 A002 納豆 3 98 294
100 3 A003 砂糖 5 208 1040
(3件処理されました)
1>
フィールド:商品名 =
val(t.商品マスター.商品名[ where t.商品マスター.商品コード=f.商品コード]) |
フィールド:単価 =
val(t.商品マスター.単価[ where t.商品マスター.商品コード=f.商品コード]) |
商品マスターの中のコードが「A002」の名称が「納豆」であるところを「自然納豆」に変更します。
そうしますと、受注明細のそのコードを持つデータの名称も一斉に更新される例です。
1>update 商品マスター set 商品名='自然納豆'
2> where 商品コード='A002' *1
3>go
(1件処理されました)
1>select 受注番号,行番号,商品コード,商品名
2> from 受注明細 where 商品コード='A002' *2
3>go
受注番号 行番号 商品コード 商品名
90 1 A002 自然納豆
92 4 A002 自然納豆
100 3 A002 自然納豆
101 1 A002 自然納豆
105 6 A002 自然納豆
(5件処理されました)
1>
フィールド:商品名 =
getval(t.商品マスター.商品名[ where t.商品マスター.商品コード=f.商品コード]) |
フィールド:単価 =
getval(t.商品マスター.単価[ where t.商品マスター.商品コード=f.商品コード]) |
こうすることによって、たとえ商品の単価が変動しても、過去の伝票の内容は変更されません。
もちろん、新規に受注明細データを登録する場合には、その時点での商品マスターに登録されている単価が自動的に持って来られます。
この関数を使うことによって、リアルタイムにデータの同期した更新をせず、
あとでまとめて(バッチで)データ更新をして処理パフォマンスを上げることもできるようになっています。
フィールド:商品名 =
if update(f.商品コード)
{ getval(t.商品マスター.商品名 [where t.商品マスター.商品コード=f.商品コード]) } |
フィールド:単価 =
if update(f.商品コード)
{ getval(t.商品マスター.単価 [where t.商品マスター.商品コード=f.商品コード]) } |
この例は、商品コードが変更された(insertを含みます)ときのみ商品名や、単位を持って来るという記述例です。
例えば、新規に伝票を入力する際、商品コードを指定すれば自動的に商品名が商品マスターから読み出して持って来られますが、
その商品名を自由に書き換えたいときなどに指定します。
もし、このif文の指定がない場合は、商品マスターと同期がとられますので、商品名が変更されても、
その時点で商品マスターから登録されている商品名が再度持って来られその変更に上書きされてしまいます。
逆に、常にマスターの値と同期を取って同じとしたい場合は、if文は不要です。
フィールド:受注額 =
sum(t.受注明細.合計[ where t.受注明細.受注番号=f.受注番号]) |
フィールド:売上額 =
sum(t.受注明細.売上合計[ where t.受注明細.受注番号=f.受注番号]) |
受注明細にデータを追加したら上位テーブルの合計額も自動的に集計されセットされるところを見ます。
1>insert into 受注明細(受注番号,行番号,商品コード,数量)
2> values(100,0,'A003',5) *1
3>go
(1件処理されました)
1>select 受注番号,行番号,商品コード,商品名,数量,単価,合計
2> from 受注明細 where 受注番号=100 order by 行番号
3>go
受注番号 行番号 商品コード 商品名 数量
単価 合計
100 1 A001 マヨネーズ 2 198 369
100 2 A002 納豆 3 98 294
100 3 A003 砂糖 5 208 1040 *2
(3件処理されました)
1>select * from 受注マスター where 受注番号=100
2>go
受注番号 顧客番号 受注日 納期 受注額
100 10 2007-10-1 2007-10-3 1703 *3
(1件処理されました)
1>
テーブル:請求書マスター =
relation R請求書[ to t.受注明細
where t.受注明細.顧客コード=f.顧客番号 and t.受注明細.売上日 between dateadd(m,-1,dateadd(d,1,f.今月締日)) and f.今月締日] |
導出定義文 テーブル=請求書マスター
フィールド:総額 = sum(t.受注明細.売上合計[relation R請求書]) |
顧客番号10番の顧客の締日が毎月20日とします。
2007年9月20付の請求書を作成します。
その場合、売上日が、8月21日~9月20日までの売上額が請求額となります。
1>insert into 請求書マスター
2> (請求書番号,顧客番号,今月締日)
3> values(0,10,'2007-09-20') *1
3>go
(1件処理されました)
1>select * from 請求書マスター
2> where 顧客番号=10 order by 今月締日
3>go
請求書番号 顧客番号 顧客名 今月締日 今月請求額
87 10 ABC商事 2007-08-20 12345
102 10 ABC商事 2007-09-20 14933 *2
(2件処理されました)
1>
テーブル:社員テーブル =
relation R社員M [to d.人事データベース.社員マスター where d.人事データベース.社員マスター.社員番号=f.社員番号] when not found then insert delete me |
導出定義文 テーブル=社員テーブル
フィールド:社員名 =
val(d.人事データベース.社員マスター.社員名 [ relation R社員M]) |
人事データベース内の社員マスターの社員名が変更されたなら販売データベース内の社員名も自動的に更新されます。
「d.」はデータベースであることを示しています。もし新規に人事データベース内の社員マスターに社員が追加されたならば、自動的に追加(insert)されますし、削除されたならば、自動的に削除(delete)されます。
もちろん削除されるときは、外部キー制約が満たされないと削除されません。
1>select * from 社員テーブル
2>go
社員番号 社員名
100 山田太郎
101 井上花子 *1
(2件処理されました)
1>update 人事データベース.dbo.社員マスター
2> set 社員名='山田花子'
3> where 社員番号=101 *2
4>go
(1件処理されました)
1>select * from 社員テーブル
2>go
社員番号 社員名
100 山田太郎
101 山田花子 *3
(2件処理されました)
1>
導出定義文 テーブル=社員テーブル
フィールド:社員名 =
getval(d.人事データベース.社員マスター.社員名 [where d.人事データベース.社員マスター.社員番号=f.社員番号]) |
exec sp_addlinkedserver 'TokyoServer', N'SQL Server' exec sp_addlinkedsrvlogin 'TokyoServer', 'false', NULL,'sa', 'pass777' exec sp_addlinkedserver 'NYServer', N'SQL Server' exec sp_addlinkedsrvlogin 'NYServer', 'false', NULL, 'sa','pass789' |
テーブル:商品マスター =
relation R全社商品M [to s.'TokyoServer'.全社DB.全社商品マスター where s.'TokyoServer'.全社DB.全社商品マスター.商品コード=f.商品コード] when not found then insert delete me |
導出定義文 テーブル=商品マスター
フィールド:商品名 =
val(s.'TokyoServer'.全社DB.全社商品マスター.商品名 [ relation R全社商品M]) |
フィールド:単価 =
val(s.'TokyoServer'.全社DB.全社商品マスター.単価 [ relation R全社商品M]) |
リンクされたサーバを指定する場合は、「s.」と入力しますと、リンクサーバの一覧が表示されますので、その一覧から使用するサーバを選択することができます。
1>select * from 商品マスター
2>go
商品コード 商品名 単価 在庫数 最終入荷日
A001 マユネーズ 298 98 2008-05-11
A002 自然納豆 98 125 2008-05-14 *1
(2件処理されました)
1>update [TokyoServer].全社DB.dbo.商品マスター
2> set 商品名='天然納豆'
3> where 商品コード='A002' *2
4>go
(1件処理されました)
1>select * from 商品マスター
2>go
商品コード 商品名 単価 在庫数 最終入荷日
A001 マユネーズ 298 98 2008-05-11
A002 天然納豆 98 125 2008-05-14 *3
(2件処理されました)
1>
*1 自分のサーバ内の商品マスターテーブルの内容を表示。
*2 TokyoServer内の全社DBの商品マスターの「A002」の「自然納豆」を、「天然納豆」に変更しました。
*3 そうすると、自分のサーバ内の商品マスターテーブルも「自然納豆」から「天然納豆」に変更されました。
フィールド:商品コード =
declare @code nvarchar(20) declare @no int if insert{ if f.商品種別='食品' { set @code=getmax(f.商品コード[where f.商品種別='食品']) set @no=convert(int,right(@code,len(@code)-1))+1 set @code=convert(nvarchar(3),@no) 'A'+replicate('0',3-len(@code))+@code } if f.商品種別='衣料' { set @code=getmax(f.商品コード[where f.商品種別='衣料']) set @no=convert(int,right(@code,len(@code)-1))+1 set @code=convert(nvarchar(3),@no) 'C'+replicate('0',3-len(@code))+@code } if f.商品種別='家具' { set @code=getmax(f.商品コード[where f.商品種別='家具']) set @no=convert(int,right(@code,len(@code)-1))+1 set @code=convert(nvarchar(3),@no) 'F'+replicate('0',3-len(@code))+@code } } |
この例は、商品種別が「食品」のときは、Aから始まる4桁のコードにし、「衣料」のときは、Cから始まり、「家具」のときは、Fから始まるコードの自動作成をしている例です。
自動的にコードがふられるところを見ます。
1>insert into 商品マスター(商品コード,商品名,商品種別)
2> values('0','インスタントラーメン','食品') *1
3>go
(1件処理されました)
1>select 商品コード,商品名,商品種別 from 商品マスター
2>go
商品コード 商品名 商品種別
A001 マヨネーズ 食品
A002 納豆 食品
A003 砂糖 食品
A004 バター 食品
A005 インスタントラーメン 食品 *2
(5件処理されました)
フィールド
|
属性
|
備考
|
主キー |
数値
|
identity で自動番号付与 |
更新日時 |
日付
|
|
商品コード |
文字
|
|
商品名 |
文字
|
|
商品種別 |
文字
|
|
単価 |
数値
|
|
単位 |
文字
|
|
在庫数 |
数値
|
|
履歴ステータス |
文字
|
「登録」「更新」「削除」をセットします。 |
商品マスターが更新されるたびに商品マスター履歴が自動的に格納されるようにします。
関係定義文 データベース=販売データベース
テーブル:商品マスター履歴 =
relation R商品履歴 [to t.商品マスター history ] |
「to テーブル名」のあとにhistory句を指定することによって、「to テーブル名」で指定されたテーブルに変更が加えられたならば、
常に左辺の=の前のテーブルがInsertされるようにすることができます。
この場合主キーは、例えばidentityを指定することによって、自動的に採番されるようにしておけば便利でしょう。
例では、商品マスターに新たなデータがinsertされたときは「登録」を、商品マスターの任意のデータがupdateされたときは「更新」を、
また、商品マスターのデータがdeleteされたときは「削除」を履歴ステータスに代入するように、導出定義文にif 文を使って記述しています。
導出定義文 テーブル=商品マスター履歴
フィールド:更新日時 = getdate() |
フィールド:商品コード = getval(t.商品マスター.商品コード[relation R商品履歴]) |
フィールド:商品名 = getval(t.商品マスター.商品名[relation R商品履歴]) |
フィールド:商品種別 = getval(t.商品マスター.商品種別[relation R商品履歴]) |
フィールド:単価 = getval(t.商品マスター.単価[relation R商品履歴]) |
フィールド:単位 = getval(t.商品マスター.単位[relation R商品履歴]) |
フィールド:在庫数 = getval(t.商品マスター.在庫数[relation R商品履歴]) |
フィールド:履歴ステータス =
if insert(t.商品マスター){ '登録' } if update(t.商品マスター){ '更新' } if delete(t.商品マスター){ '削除' } |
次に、商品マスター履歴が格納されるところを見ます。
1>update 商品マスター set 在庫数=在庫数-2
2> where 商品コード='A002' *1
3>go
(1件処理されました)
1>select 商品コード,商品名,在庫数 from 商品マスター
2> where 商品コード='A002' *2
3>go
商品コード 商品名 在庫数
A002 納豆 68
(1件処理されました)
1>select * from 商品マスター履歴
2> where 商品コード='A002' order by 更新日時 *3
3>go
主キー 更新日時 商品コード 商品名 単価
単位 在庫数 履歴ステータス
123 09/20 09:30:10 A002 納豆 98 パック 120 登録
334 09/25 10:10:15 A002 納豆 98 パック 70 更新
557 10/01 08:55:10 A002 納豆 98 パック 68 更新
(3件処理されました)
1>
年統計
|
月統計 | 日統計 | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
なお、種別には「受注」「売上」「発注」「仕入」などが入るものとします。
でも例では売上だけを扱うものとします。
関係定義文 データベース=販売データベース
テーブル:年統計 =
relation R年[to t.月統計 where t.月統計.年=f.年 and t.月統計.種別=f.種別] when not found then insert me |
テーブル:月統計 =
relation R月[to t.日統計 where t.日統計.年=f.年 and t.日統計.月=f.月 and t.日統計.種別=f.種別] when not found then insert me |
テーブル:日統計 =
relation R日[to t.受注明細 where t.受注明細.売上日=f.日 and f.種別='売上'] when not found and t.受注明細.売上日 is not null then insert me with no key change |
フィールド:年 = val(t.月統計.年[relation R年]when not null) |
フィールド:種別 = val(t.月統計.種別[relation R年]when not null) |
フィールド:金額 = sum(t.月統計.金額[relation R年]) |
フィールド:年 = val(t.日統計.年[relation R月]when not null) |
フィールド:月 = val(t.日統計.月[relation R月]when not null) |
フィールド:種別 = val(t.日統計.種別[relation R月]when not null) |
フィールド:金額 = sum(t.日統計.金額[relation R月]) |
フィールド:年 =
set @売上日=val(t.受注明細.売上日[relation R日]) convert(datetime,convert(nchar(4),year(@売上日))+'/01/01') |
フィールド:月 =
set @売上日=val(t.受注明細.売上日[relation R日]) convert(datetime,convert(nchar(4),year(@売上日))+'/' +convert(nchar(2),month(@売上日))+'/01') |
フィールド:日 = val(t.受注明細.売上日[relation R日]) |
フィールド:種別 = '売上' /* 例では売上のみ */ |
フィールド:金額 = sum(t.受注明細.売上合計[relation R日]) |
1>select * from 日統計 where 月='2007-10-01' *1
2>go
年 月 日 種別 金額
2007-01-01 2007-10-01 2007-10-01 売上 12345
2007-01-01 2007-10-01 2007-10-02 売上 12555
(2件処理されました)
1>insert into 受注明細 (受注番号,行番号,商品コード,
2> 数量,売上数,売上日)values
3> (100,0,'A002',3,3,'2007-10-03') *2
4>go
(1件処理されました)
1>select * from 日統計 where 月='2007-10-01' *3
2>go
年 月 日 種別 金額
2007-01-01 2007-10-01 2007-10-01 売上 12345
2007-01-01 2007-10-01 2007-10-02 売上 12555
2007-01-01 2007-10-01 2007-10-03 売上 294
(3件処理されました)
1>select * from 月統計 where 月='2007-10-01' *4
2>go
年 月 種別 金額
2007-01-01 2007-10-01 売上 25194
(1件処理されました)
1>
フィールド:性別 =
if me<>1 and me<>2 { display '性別がまちがっています。' rollback } |
フィールド:生年月日 =
if me>dateadd(yy,-10,getdate()) { display '10才以下の社員は登録できません。' rollback } |
create procedure P_性別 (@入力 int, @出力 nvarchar(10) output) as set @出力=null select @出力=性別 from コードマスター where コード=@入力 if @出力 is null begin set @出力='性別不正' end return |
フィールド:性別 =
set @性別='' execute P_性別 me,@出力=@性別 output print '性別は'+@性別+'です。' |
この例は、商品種別が「食品」のときは、Aから始まる4桁のコードにし、「衣料」のときは、Cから始まり、「家具」のときは、Fから始まるコードの自動作成をしている例です。
自動的にコードがふられるところを見ます。
1>insert into 社員マスター
2> (社員番号,社員名,性別,生年月日,住所)
3> values(7,'山田太郎',1,'1980-07-07','東京都')
4>go
性別は男です。 *1
(1件処理されました)
1>