SQLをDelphiで勉強します

このエントリーをはてなブックマークに追加
1@
殆ど使わないでD3->D4(Pro)までバージョンアップしたDelphiを使って
SQLをこれから勉強します。 ちなみに制御系の一人請負です。
間違った方向に進んでましたらご指導下さい。
2@:2000/03/07(火) 10:51
まず準備
 BDE Administrator でエリアスを定義しました。
  データベースドライバ名は STANDARD
  エリアス名は MYDB
  デフォルトdriverはPARADOXとし、PATHを定義しました。

 BDE Administrator でエリアスを定義しました。
3@:2000/03/07(火) 11:21
次にDatabase Explorerを使ってテーブルを作ります。
まず、MYDBの所をクリックすると、SQL文の入力が出ました ここに

  DROP TABLE kokyaku
  CREATE TABLE kokyaku
  (
    KCODE CHAR(6)@`
   会社名 CHAR(20)@`
   JIP3 CHAR(3)@` JIP4 CHAR(4)@`
   住所1 CHAR(30)@` 住所2 CHAR(30)@`
   電話1 CHAR(12)@` 電話2 CHAR(12)@`
   締日 SMALLINT@`
   支払日 SMALLINT@`
   支払条件 CHAR(4)@`
   担当 SMALLINT@`
   PRIMARY KEY (KCODE)
  )
 これでkokyaku.dbが出来ました。
 さらに電話番号にindexを付けてみます
 CREATE INDEX 電話1 ON kokyaku (電話1)
 なんかしらんけどファイルが増えました。
4@:2000/03/07(火) 11:33
作ったテーブルに、読みがあった方が良いとだろうと
  ALTER TABLE kokyaku ADD 読み CHAR(10)
 としたら、「テーブルは使用中」と怒られましたが、なんかしたら成功しました。

 これでDDLは終わり・・・・でいけるかな?
5seven:2000/03/07(火) 11:42
フィールド名に2バイト文字を使わない方がよさそうです。
あと、設計時はTTableはDataと接続しないほうがいいです。
indexは、専用のファイルができます。
BDEのエリアスを定義しないで、TDataBaseから直接指定する
こともできます。
DataModuleを使うほうが、あとあと便利かもしれません。
6@:2000/03/07(火) 11:43
ここまでで、わからなかったのは、いくつかの命令を連続して発行する場合です。
たとえば
 CREATE INDEX 電話1 ON kokyaku (電話1)
 CREATE INDEX 電話2 ON kokyaku (電話2)
 と2つのindexを一度につけたい場合、この2行は別けて発行しないといけない
 のでしょうか?
 なにかセパレータがあるのでしょうか?
localsql.hlpを読んでも出来るのかどうかも判りませんでした。
7@>5:2000/03/07(火) 11:47
sevenさんお世話になります。
>フィールド名に2バイト文字を使わない方がよさそうです。
 でも、Paradoxなんかでフィールド名に2バイト文字が使われているし
 今の所問題なさそうだし、チョコッと試したDBGridではそのフィールド名
 がタイトルになるのでこのまま使いたいなと

DataModuleはこれから勉強しますです。
8@:2000/03/07(火) 11:56
>6 TQuery.SQL を読むと、完全な SQL 文を一度に 1 文しか代入できません
  とあるので別けて発行しないと駄目みたいですね。
9@:2000/03/07(火) 12:10
今度はDelphiを起動し、
DataModule に TQuery と TDataSourceを貼り付け
フォームに TDBGridを貼り付け、あちこちプロパティを設定して

TQuery.SQLに
  SELECT * from kokyaku

として Active:=True とすると、 Gridが表示されました。

でも編集は出来ません。枠と項目名が出ているだけの状態です。

これから編集させる方法を調べてみます。
10seven:2000/03/07(火) 12:39
>7 7取られた(笑)
まぁ、仕様上はOKなんだけど、使わない人が多いから、
なにか不具合出たときに、悩みの一つになるかもしれません。
あと、DBの種類によって、SQLが通らなくなるかもしれません。
表とか玉とか六とか使って大丈夫なら、まぁいいのかな。
>9
編集したいのならTTable使うほうが楽です。
Paradoxなら、データ量もたいしたことないのですよね?
11@>10:2000/03/07(火) 14:06
場合によっては使えない場合があるかもしれないから、事前に危険回避
する訳ですね。了解しました。

まあ、直接仕事に使うんじゃなくて、あくまでも 埋込SQLでアプリを書く勉強
なんで、とりあえず枝葉的な部分は後で考える事にします。

>編集したいのならTTable使うほうが楽です
 ふむ。まだ良く分かってはないのですが、今回は勉強ですのであえて
 そちらを使う方針にします。

>Paradoxなら、データ量もたいしたことないのですよね
 客先に見せられるような販売管理的なものをイメージしています。
 客先は中小なので、量は、たぶんたいした事ありません(^^;
 マニュアルにある フラットファイルデータベースTClientDataSet
 が理想だったんですが、これは C/S版Enterprise版のみで残念

今、キャッシュアップデート・トランザクション・セッションの用語
イメージが掴めず 少し停滞中です。
12@:2000/03/07(火) 14:33
試しに TTableをTQueryの代わり使うと確かに編集出来ました。
13陰陽:2000/03/07(火) 14:43
TQueryならRequestLiveってプロパティをTrueにすればOK。
詳細はHelpをどうぞ。
ORDER BYかけたりするとそれでも編集できなくなるので、
TUpdateSQLをはりつけて、関連づけしてSQL文生成しなければ駄目。

キャッシュアップデートはDBのデータをキャッシュに読み込んで置いて、
修正時はそのキャッシュの内容を変更してApplyUpdatesでDBに書き込む。
だからApplyUpdatesかけるまではキー違反なデータでも書き込めちゃう。
14@>13 :2000/03/07(火) 17:29
おお、色々探して判らなかったのに・・・・ありがとう。

用語概念が未だに掴めていませんが、どんどんやっていった方がいいですね。

次は納品書に挑戦します。 納品書の画面イメージを作って、
顧客コードから kokyaku.dbの内容を表示させてみます。

この画面のまま kokyaku.dbが編集出来る方がいいのか、それ
とも別の画面が出て編集出来る方がいいのか・・・・・
15陰陽:2000/03/07(火) 17:48
トランザクションはDB関係の書籍ならだいたい説明してあるから
読んでみてね

kokyaku.dbのフィールド数が多いなら、顧客マスタをつくっておいて
納品書からは「新規顧客作成」とか「顧客データ変更」とかをつくって
登録画面を起動するようにしないと、納品書なのかなんなのか
わかんなくなるよ。

顧客データに住所・Tel・担当者名くらい欲しいでしょ?
16@>15:2000/03/07(火) 22:45
ありがとうございます。勉強になります。

とりあえず、こんな設計にしてみました。

CREATE TABLE kokyakuCREATE TABLE kokyaku
(
 KCODE  CHAR(6)@`
 社名   CHAR(20)@` 読み   CHAR(10)@`
 ZIP3   CHAR(3)@`  ZIP4   CHAR(4)@`
 住所1  CHAR(30)@` 住所2  CHAR(30)@`
 電話1  CHAR(12)@` 電話2  CHAR(12)@`
 締日   CHAR(2)@`  支払日  CHAR(2)@`
 支払条件 CHAR(4)@`
 担当  SMALLINT@`
 PRIMARY KEY (KCODE)
);
CREATE TABLE nohint /*納品書1枚1レコード*/
(
 納品番号 INTEGER@`
 KCODE  CHAR(6)@`/*納品先コード*/
 担当   SMALLINT@`
 納品日  DATE@`
 PRIMARY KEY (納品番号)
) ;
CREATE TABLE nohin /*納品書1行 1レコード*/
(
 納品番号  INTEGER@`
 行番号   SMALLINT@`
 商品コード CHAR(8)@`
 納品数   SMALLINT@`
 単価    MONEY@`
 金額    MONEY@`
 PRIMARY KEY (納品番号@`行番号)
) ;
17名無しさん:2000/03/07(火) 22:47
PASCAL信者ってDOS/VをねたんでいるMACユーザと同じで、
CやC++をねたんでいる僻みっぽいバカばかり。

だからDelphiは消えてくれ
18@:2000/03/07(火) 22:53
Database ExplorerをDelphiから起動すると、ドラッグ&ドロップで
 GridやEditを張り付けられる事が判りました。
するとTQueryじゃなくてTTableになるのですが、
 TTable.MasterSource MasterFields を設定するだけで、
 やりたい事(納品番号@`KCODEに応じた表示)が出来てしまいました。

私の思い付くレベルでは、TQueryで 埋込SQLでとかする必要も無いですね。

なんか、とってもお手軽、というかコードはまだ全然書いていません。
19seven:2000/03/08(水) 03:12
>18
はい、実装だけなら30分くらいでプロトタイプができてしまいます。
こんな簡単だと、不安を感じませんか?(笑)。
20seven:2000/03/08(水) 03:23
>11
>今、キャッシュアップデート・トランザクション・セッションの用語

このあたりは、ParadoxよりはInterbase使ったほうがいいかも
このペースだと、7日くらいで私のレベルを超えそうですね(笑)>@
21seven:2000/03/08(水) 03:27
あ、印刷まわりは、けっこう苦労するかもしれません。
22@:2000/03/08(水) 12:58
設計したデータベースを新規作成する時便利なよう、こんなの作りました。
16のような;で区切った複数のSQL文が実行出来ます。
// ひとつのSQL文は';'で終わる事
procedure SQLSends(s:TStrings;dbName:string;AOwner:TForm);
var Q:TQuery;
var n@`i:integer;
var w:string;
begin
 i:=0;
 Q:=TQuery.Create(AOwner);
 Try
  Q.DatabaseName:=dbName;
  while(s.Count>i) do begin
   Q.SQL.Clear;
   while(s.Count>i) do begin
   w:=s.Strings[i]; inc(i);
   n:=Pos(';'@`w);
   if(n=0)then Q.SQL.Add(w)
    else begin
     Q.SQL.Add(Copy(w@`1@`n-1) );
     w:=Copy(w@`n+1@`1);

     break;
   end;
   w:='';
  end;
  if(Q.SQL.Count<>0) then begin
   Q.Close;
   try
  if(w[1]='O') then Q.Open
         else Q.ExecSQL;
   except
    on E:Exception do
    ErrMemo(AOwner@`Q.SQL@`E);
   end;
  end;
  end;
 except
  Q.free;
 end;
end;

procedure ErrMemo(w:TForm;s:TStrings;E:Exception);
var m:tMemo;
begin
  m:=tmemo.Create(w);
 Try
   m.Parent:=w;
   m.Align:=alClient;
   m.Lines.AddStrings(s);
   MessageDlg(E.Message@`mtWarning @`[mbAbort]@`0);
  except
  m.free;
  end;
end;
23@>19@`20@`21:2000/03/08(水) 13:05
あ、色々ありがとうございます。
 >こんな簡単だと、不安を感じませんか?(笑)。
  いや、計測関係で少しDelphiを使った事があるので、思った通りと(^^)

 >このあたりは、ParadoxよりはInterbase使ったほうがいいかも
  なるほど。でもInterbaseは配布出来ないのだろうとParadoxにしました。

 >このペースだと、7日くらいで私のレベルを超えそうですね(笑)
  そうなりたいものですが・・・って無理でしょう。 プログラムが
  組めても、そういう業務知識がありませんから。

 >あ、印刷まわりは、けっこう苦労するかもしれません
  Printer.Canvasにゴリゴリとというか普通に書けば良いのだと
  思っていました。 なんとかレポートの類は、使い方を調べるのが面倒
  だからと無視していましたが・・・そっち使った方がよさそう?
24陰陽:2000/03/08(水) 14:41
納品書(と内訳)の一覧、顧客一覧しかないならQuickReportで
勉強する時間入れても1日かからずにできます。
修正とか楽だからQRのほうがいいかも。

顧客ごと月別の集計と年別の集計の両方を出すとかになると
QRそのものの機能だけではむずかしいのでワークテーブルつくってやるか
Printer.Canvasをつかうか。

なんにしてもはじめにキチンと設計してどちらかに統一することが一番・・・・<うちの事
25seven:2000/03/08(水) 16:15
遅くてもいいなら、MS-Excelにデータ渡して印刷するという
方法もあります。
26@>24:2000/03/08(水) 16:17
 ありがとうございます。QuickReportも調べてみます。
 でも Printer.Canvas が自分には一番楽かもしれない。
 なんかコード書いた気になれるし。
27@:2000/03/08(水) 16:20
22のコードは、finally を使うべき所で Exceptを間違って使ってました。

free の直前のExceptはfinallyですね
28@:2000/03/08(水) 16:47
MessageDlgでも複数の行が表示出来るんですね。22のコードで
出来ないと思ってたからわざわざtmemo使ったんだけど、

function ErrMemo(s:TStrings;E:Exception):Word;
var t:string;
var i:integer;
begin
 for i:=0 to s.Count-1 do t:=t+s.Strings[i]+#13+#10;
 t:=t + E.Message;
 Result:=MessageDlg(t@`mtWarning @`[mbAbort]@`0);
end;
29名無しさん:2000/03/08(水) 23:14
Delphi使うやつは氏ね
(うざいスレッドなので終了。書き込むを押しても書き込めません)
30seven:2000/03/08(水) 23:45
あ、そだ、Paradoxなら一次キーの連番の発行は、連番テーブル使うほうがいいかも。
31名無しさん:2000/03/09(木) 03:17
わはは29は放置プレイか
32陰陽:2000/03/09(木) 03:18
使わない方がいいかも。
なんかMLでそんなことをみた覚えがあるので
自前で連番するようにした<うち

Paradoxのへぼいネットワーク機能を使ったときに、
連番だとキー違反がでるとかいろいろ。
でもこれくらいなら更新する直前に番号拾い直してくればOKだなあ。
他DBへの移植が視野にないならいいかもね。

Paradoxはサーバー立ち上げなくてもNetworkできるのはいいと思う。
33陰陽:2000/03/09(木) 03:20
あ、
> でもこれくらいなら更新する直前に番号拾い直してくればOKだなあ。

この処理を書くなら連番フィールドじゃなくても一緒だから
ふつうのFieldを使ったんだった。
34seven:2000/03/09(木) 07:03
>33
うん、自動連番フィールドは、ダメだよね。でお手軽に専用のテーブルを連番発行用に
作るの。
35@:2000/03/09(木) 11:41
指定した納品番号だけ表示するのをTTableの範囲を使いかけましたが、
初心に戻って、TQueryのSQLを使う事にしました。
  SELECT * FROM nohin WHERE
  納品番号 = 100
とすると、目的通り、納品書の項目別テーブルから納品番号100のだけが
取り出せました。 陰陽 さんに押して頂いた RequestLive:=Trueで編集も出来ます。

 このSQL文で納品番号=100の100を変更するには2つの方法があるようです。
 ひとつは、SQL.ADD(format('納品番号=%d'@`[no]));のように毎回SQLを書換える方法
 もう一つは、引数マーカを使う方法みたい。
  どちらが良いか判りませんが、とりあえず、私に理解出来る先の方法を使ってみます。

さて、RequestLive:=True では、変更してしまうと元に戻せない事が判りました。
 ここでどうやらキャッシュアップデートの登場のように思います。

36さげ:2000/03/09(木) 11:45
JaZ FTP!
37@:2000/03/09(木) 11:57
>sevenさん 陰陽さんお世話になります

連番テーブルってのがあるんですね。でもヘルプで探せなかった。
PARADOX専用なんですか?
 ならいいや、そんなに大変じゃないし、勉強が目的だから。
38@>29:2000/03/09(木) 11:57
うざいですか?
 俺も勉強が捗るし、これを覗いた奴も勉強になるかなと思って始めたんだけど。
39@:2000/03/09(木) 14:03
TQueryでキャッシュアップデートするには
 TUpdateSQL の DeleteSQLとかの3つのプロパテイに
  DELETE FROM nohin I
  WHERE (I.納品番号=:OLD_納品番号) AND (I.行番号=:OLD_行番号)
  とか全部用意した上で、
 TQuery.UpdateObject:=TUpdateSQL
 TQuery.ChashedUpdate:=True;
  とすれば良いようですが、DeleteSQLはまだしも、InsertSQLなど
 いちいち書いてたら大変、データベースを少しでも変更するとまた
 大変という事で、やるならそれを自動化けするコンポでも作らない
 とこりゃダメだという気がしてきました。
 そこで、納品書1行ファイルの中間ファイルを作って、編集する時は
 一旦中間ファイルにコピーし、更新は中間ファイルからBatchMoveを
 使ったらと考え直しました。(考えただけでこれから試してみます)

 どうからここでトランザクションの用語が関係するような気がします。
40seven:2000/03/09(木) 14:28
>37
いや、テーブルを一つ作って、そこにカウンタ値を格納しとく
だけです。Editしてる間はロックが掛かって、他の端末から変更
できなくなるわけですね。

ParadoxでのSQLでの更新の流行は、
一度closeして、再びopenするんじゃ無かったっけ?
41陰陽:2000/03/09(木) 16:52
キャッシュアップデートは
TQueryのCachedUpdateプロパティをTrueにするだけです。
更新するときはApplyUpdatesを呼出
キャンセルするならCancelUpdatesを呼ぶだけ。

トランザクションかけておけばキャッシュアップデートしなくても
ロールバックでいけるよ
42@>40:2000/03/09(木) 17:24
 sevenさんありがとうございます。
 データベースファイルに保存してしまえという事ですね?
 こういう事でしょうか?

CREATE TABLE "RenBan.DB" ( Number INTEGER ) というテーブルがあるとして

function RenBan(tbname:string;AOwner:TForm):integer;
var Table1 : TTable;
begin
Result:=-1; //失敗したら負数を返す
  Table1 := TTable.Create(AOwner); {テーブルを用意して}
 try
  with Table1 do begin
   DatabaseName:= 'MYDB' ;
   TableName :=tbname;
   ReadOnly :=false;
  end;
  try
  with Table1 do begin
   Open; //開いて
   first;//頭にカーソルを持っていって
   edit; //編集モードに
   if state=dsEdit then //編集モードになれば番号+1
    Result := Fields.Fields[0].AsInteger+1
   else begin Append; Result:=1000;end; //でなければ初期値を与える

   Fields.Fields[0].AsInteger:=Result;
   Post;
   Close;
  end;
  except
  Result:=-1; //失敗したら負数を返す
  end;
 finally
  Table1.free;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 caption:=format('%d'@`[RenBan('RenBan.DB'@`form1) ]);
end;
43@:2000/03/09(木) 17:49
しかし、この読み出しと書込みの間に他のプロセスが書込みした場合に
問題が出るように思います。トランザクションを使えば排他処理が出来
るのかと思っていましたが、
 >他のトランザクションによるデータベースへのコミットされていない変更
 >内容を読み出せる。コミットされていない変更内容は永続的なものではな
 >く,いつでもロールバック(取り消し)できる。

 というのは、同じ値が読み出し出来るという事でしょうか?

まあ、今の所、ネットワークで使用するつもりは無いのですが。
44@>41:2000/03/09(木) 19:37
>陰陽さん重ね重ねお世話になります。
 >更新するときはApplyUpdatesを呼出
  おお、出来ました。

>トランザクションかけておけばキャッシュアップデートしなくても
>ロールバックでいけるよ
  おお、 Query1.Database.TransIsolation:= tiDirtyRead;
      Query1.Database.StartTransaction;
  して、その間の変更が
  Query1.Database.Rollback;で元に戻るのを確認しました。

この2つの方法の違いは、
 キャッシュアップは変更中の値は他のアプリから読めない
 トランザクションでは変更中の状態が他のアプリから見える
という違いがあるようです。

 いや、独習では、たぶんどツボにはまって、今ごろシコシコ自作
 の無意味なコードを書き連ねようとし始めてたに違いないです。
 感謝、感謝です。
45@:2000/03/09(木) 19:46
テーブルの排他処理は、Exclusive で出来るようです。

>42の open前に Exclusive:=True;を入れれば排他的に処理出来そうです。
46@:2000/03/09(木) 23:31
今日のまとめです。
 出来た事:1行1レコードのデータベースから、納品番号で
      指定したデータだけを編集、書換える
QueryとDataSourceとDbGridを張り付けて適当にプロパテイを設定し
----------------------------------------------------------
TQueryでキャッシュアップデートを使う
 ncodeに納品番号を入れて、以下のようにして開く。
 Query1.Close; //してもエラーにはならない
 Query1.CachedUpdates:=True;
 Query1.RequestLive:=True;
 Query1.SQL.Clear;
 Query1.SQL.Add('SELECT * FROM nohin WHERE 納品番号 = '+ncode );
 Query1.Open;
  これで、Grid等で編集した後、操作により
   それまでの処理を有効にする:Query1.ApplyUpdates;
   それまでの処理を無効にする:Query1.CancelUpdates;
---------------------------------------------------
トランザクションの場合:
  Query1.Close; //してもエラーにはならない
  Query1.Database.TransIsolation:= tiDirtyRead;
  Query1.Database.StartTransaction;
  Query1.RequestLive:=True;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT * FROM nohin WHERE 納品番号 = '+ncode );
  Query1.Open;
   それまでの処理を有効にする:  Query1.Database.Commit;
   それまでの処理を無効にする:  Query1.Database.Rollback;
47スゲーなおい:2000/03/10(金) 00:00


っていうか、ここまで展開するならMLで聞いてよってカンジ・・。
48エロリ・ザ・男爵:2000/03/10(金) 04:49
Delphiには興味ないけど、
こーゆースレッドもあっていいと思うよ。
49seven:2000/03/10(金) 05:39
>47
たしかに、このレベルは、かなりの財産になるね。
50陰陽:2000/03/10(金) 09:31
MLでいちいち業務経過報告されたらたまらんわ
次の初心者の為に@さんがまとめてWebにあげるのが
最良形かと
51zo100:2000/03/10(金) 09:55
ふむふむ
このあたりのやり取り、結構参考になります。
便乗質問なんですが、TTableを使って
連番 ← 内部的に持たせる値なので見せたくない
データ1 ← 編集項目
データ2 ← 編集項目
データ3 ← 編集項目
計算結果1 ← データによって自動設定される値なので見せたくない

といった場合、見せたくないけどテーブルに持たせるような場合は
どんな感じで処理させるといいですか?


52@>51:2000/03/10(金) 10:53
Gridの場合は、グリッドの上でマウス右=>カラムの設定で見せないように出来ます

内部で計算する項目は TDBEditとかの Fieldじゃなくて
TTableのFieldValuesで操作すれば良いように思います。

53@:2000/03/10(金) 12:47
今日は、カレンダコンポから選んだ日付に発行した納品書一覧
をコンボボックスとかで選択出来るようにしてみました。
 ハマリそうだったのは、SQL文で日付を渡す点です。
 画面表示が YY/MM/DDだったのでそのまま渡したらエラーになりました
  FormatDateTime('d/m/yyyy'@`MonthCalendar1.Date);
 とやって解決しました。
 あとは、DBLookUpのプロパテイをListSorce ListFiled KeyFiled
 と設定すれば表示されました。
54zo100:2000/03/10(金) 16:21
>画面表示が YY/MM/DDだったのでそのまま渡したらエラーになりました
SQL1.ParamByname('Date1').AsDate := MonthCalender1.Date
でいけると思います。
55@:2000/03/11(土) 13:33
納品書のKCODEから会社名を持ったテーブルが欲しくて色々試した結果
SELECT * FROM nohint M @`kokyaku K WHERE M.KCODE=k.KCODE
で出来ましたが、これで良いのでしょうか?
 これを利用して、指定した日付の納品書番号と納品先が
 表示されるようにしたのが以下の通りです。

var ncode:string;
var s:string;
var d:tstrings;
begin
d:=ComboBox1.items;
d.Clear;
ncode:=FormatDateTime('m/d/yyyy'@`MonthCalendar1.Date);
 with Query1 do begin
 Close; //してもエラーにはならない
 with SQL do begin
   Clear;
   Add('SELECT M.納品番号 @` K.社名 FROM nohint M @`kokyaku K ');
   Add('WHERE M.KCODE=k.KCODE ');
   Add(  'AND M.納品日="'+ncode+'"' );
 END;
 Open ;
 first;//頭にカーソルを持っていって
  while not eof do begin
   s:= FieldValues['納品番号'];
   s:=s+':'+FieldValues['社名'];
   d.Add( s);
   next;
  end;
 end;
end;
56>55:2000/03/11(土) 21:36
あっています。

WHERE テーブル1.カラム名=テーブル2.カラム名
のようなのを「相関」といい。基本的な手法です。
57>56:2000/03/11(土) 22:12
55の KとかMを相関名(エリアス)っていうのは知ってるけど、それホントに相関ていうの?

こっちじゃ 結合(JOIN)って呼んでるぞ
ほれ
 http://www.netlaputa.ne.jp/~mkoba/sql/sql07.htm
 http://www.reitaku-u.ac.jp/infosci/rdb/rdb05.html
58陰陽:2000/03/12(日) 02:37
相関というかはしらんけど、
FROMに2個テーブルを書くようなのは結合って言ってる。うちでは。

ちなみにそれだと会社名マスタを修正すると
データを引いてこなくなるので外部結合したほうがいい。
Paradoxの外部結合めんどくさいから気をつけてね
ORACLEなら
SELECT M.納品番号 @` K.社名
FROM nohint M @`kokyaku K
WHERE M.KCODE=k.KCODE(+)
これをParadoxでかくと
SELECT M.納品番号 @` K.社名
FROM nohint M
   LEFT OUTER JOIN kokyaku K ON (M.KCODE=k.KCODE)
です。移植とか大変なので
TQueryを画面に2つはりつけて項目コンポーネントで
参照項目を新規作成したほうがいい。

Paradoxの文法についてのヘルプは
スタートメニューのBDEのヘルプのなかに入ってる
Local SQL Helpをどうぞ

5988>:2000/03/12(日) 03:18
参照項目はTQuery2個はっつけて、
それぞれSQLをSELECT * FROM kokyakut@`SELECT * FROM nouhint
にして納品の方のTQueryをDblClick。
そうすると項目コンポーネントエディタっていうのが開くから
右クリックしてまず「すべての項目を追加」。
もう一回右クリックして「新規項目作成」。
名前決めて参照にして、キーはKCODE、参照テーブルは
kokyakutのTQuery@`参照キーはKCODE@`データは社名ね。
こっちは普通にHelp引けるから。
60@:2000/03/12(日) 11:50
みなさんありがとうございます。

 名前についてはLocalSQL.hlpで検索すると
 55のようなのは"等結合"とありました。他に、
 >INNER JOIN これはまだ良く判らない
 >OUTER JOIN >58陰陽 さんが教えて下さっている方法(まだ理解していない)
 >直積結合  全部の組合わせが出る(最初これ知らずやって驚いたけど意味あるの?)
 >UNION結合 後ろにデータを追加する

というのがあるようです。これから勉強します。
61@:2000/03/12(日) 14:28
SQLの参考書が古いようで、等結合以外は LocalSQL.hlpだけが頼りです。
 で 色々試した結果、
1,等結合とINNTER JOIN は殆ど同じ

2、OUTER JOIN は、一致しない項目があっても残る点が INNTER JOINと違う

3、55のコードのような等結合では、顧客マスタとの不一致が起きると選択不能になる
  (これが 58の陰陽さんの教えと理解しました)

ただ、OUTER JOIN の表記方法はSQL1に無いので、方言が存在する場合あり

 OUTER JOIN を使わずに等結合の問題を防ぐには、顧客マスターに必ず
 納品書に含まれる顧客コードが存在するようにすれば良い。

という事で、納品書に無い顧客コードを抽出する SQL文を考えてみます。
62@:2000/03/12(日) 14:46
>納品書に無い顧客コードを抽出する SQL文

これは簡単に出来ました。 SUB SELECT というらしいです。

SELECT KCODE FROM nohint
WHERE NOT KCODE IN( SELECT KCODE FROM kokyaku )

 そろそろ SQL 初心者レベルには達したと慢心しかけています。
63@:2000/03/12(日) 16:40
で、結局、何か操作する前に、以下のような関数を使うと顧客番号だけの項目追加
が出来るようにしました。
BatchAppend('kokyaku'@`
  'SELECT KCODE FROM nohint '+
  'WHERE NOT KCODE IN( SELECT KCODE FROM kokyaku )' @`form1);

関数の定義は、以下の通りです。

//テーブル名を与えて Tableを一時的に作り BatchMoveを実行する
function BDEBatchMove(tbname:string; src:TBDEDataSet):longint;
var Table1 : TTable;
begin
 Result:=0;
 Table1 := TTable.Create(src); {テーブルを用意して}
 try
  with Table1 do begin
   DatabaseName:= 'MYDB' ;
   TableName :=tbname;
  Result:=BatchMove(src@`batAppendUpdate);
  end;
 finally
  Table1.free;
 end;
end;
//指定したテーブルに指定したSQL抽出結果を追加する
function BatchAppend(tbname:string; s:string;Owner:TComponent):longint;
var Query1 : TQuery;
begin
 Result:=0;
 Query1 :=TQuery.Create(Owner);
 try
  with Query1 do begin
   DatabaseName:= 'MYDB' ;
   SQL.Clear;
   SQL.Add(s);
   Open;
  end;
  Result:=BDEBatchMove(tbname@`Query1);
 finally
  Query1.free;
 end;
end;
64陰陽:2000/03/12(日) 18:41
項目コンポーネントは勉強しといた方がいいよ
63でやってることならあっという間に
できるから

DisplayFormatとかの便利なプロパティもあるし
65@>64:2000/03/12(日) 19:51
>陰陽さんたびたびお世話になります。
 題目が”SQLを 勉強”なので、SQLに拘っておりした。
 もちろん、59の参照項目もTQuery・TTableの両方で試してみました。
 とてもお手軽なのを体験する事が出来ました。
 たぶん、実際にプログラムを作る時は、そちらのやり方になると思います。

 ただ、項目コンポを使う方法は設計時にはお手軽ですが、関数化する場合
 は逆に手間が増えそうです。
 (というか参照項目をコードで追加する方法が判らなかった)

 まあ、なんでも関数化しようとするのは悪いクセなのかもしれませんが
66陰陽:2000/03/12(日) 20:23
DelphiではデータモジュールにQueryをいくつもはりつけておいて、
使いそうなLookupは全部つくっちゃって各フォームからusesして使う、
というのが便利そうなのでそうやってます。
これなら各アプリケーションで設計時に1回やるだけだから。

確かに関数化はできないかもね。

SQLってどの辺までが初心者なのかな。
かくいう私もSELECTを憶えてから1年もたってないもので
67@:2000/03/13(月) 23:56
今朝一番の電話で、本業がいきなり全開状態になりました。
 もちろん勉強は続けますが、今までのペースは当然無理です。
みなさまのおかげで、効率良く勉強が出来ました。
ありがとうございました。
68age:2000/03/15(水) 12:58
まあまあ下げずにBorland製品+DBの勉強スレッドということで
69名無しさん:2000/03/15(水) 15:21
@さんの64のように、コンポーネントを一時的に利用する場合、
Ownerを渡さずないで清まそうとすると何をCreateの引数に渡せば
いいでしょうか?
Application かなあ?

 関数内だけ限定で存在するオブジェクトがあればそれを親にしとけば
 Try finally 使わなくてすむので楽なんですが
70陰陽:2000/03/15(水) 17:05
Delphiではオブジェクトは暗黙にポインタなので
自分でCreateしたものは自分でFreeがいいかも。

引数にはnilを渡して必ずFreeすると。
ちなみに俺流では例外を呼出元に通知しない
(メッセージを自分で出して、親へは戻り値Booelanにて通知)
なのでtry-exceptですべての例外を処理して、最後にFreeです。

ちょっと古い(というより例外の機能を使い切れてない)けど、
例外の補足し忘れとかは無くなるので。あ、コンポーネントは別ね。
7169>70:2000/03/15(水) 17:22
あ、@さんの63の間違いでした。他の誤字もごめんなさい

nilですか。試した事なかったので試してみます。

ヘルプには
>Create を呼び出してオーナーのコンポーネントを AOwner パラメータ
>に渡します。オーナーを破棄するとコンポーネントは破棄されます。
>コンポーネントが所有されていないときは,Free を呼び出してそのコ
>ンポーネントを破棄できます。

ってあったので、何かコンポーネントを渡さないといけないと思ってました。
72>71:2000/03/15(水) 21:30
私の場合は、63の例だといちいち変数を定義せずに withを使って

function BDEBatchMove(tbname:string; src:TBDEDataSet):longint;
begin
 Result:=0;
with TTable.Create(nil) do { と臨時にテーブルを作成して }
 try             { Tryブロックでうけて }
  DatabaseName:= 'MYDB' ;
  TableName :=tbname;
  Result:=BatchMove(src@`batAppendUpdate);
  end;
 finally free; end; { この1セットで受けて開放する}
end;

こうやります。 奇麗だし、タイプも楽でしょ?
7372:2000/03/16(木) 09:31
 今みたら、finallyの前の endは不要でした
74陰陽:2000/03/16(木) 12:34
例外処理よりも変数生成せずにwithできることに驚き
いやあ勉強になります
75@:2000/03/18(土) 17:46
本業の合間に、
連番を複数使えるよう名前を付けて取り出せるように工夫してみました
さっそく、72さんの方法も使ってみました。 ただ、完全に変数を使わな
いとデバック中に値を見たりするのが出来なくて、結局デバックの為だけ
にtblという変数名を使いました。


function RenBan(TblName@`uName:string):integer;
var i:integer;
function xRenBan:integer;
var tbl:TTable;
begin
    tbl:=TTable.Create(nil); {テーブルを用意して}
 with tbl do
  try
   DatabaseName:= 'MYDB'; //エリアス名を設定
   TableName :=TblName;  //テーブル名を設定
   ReadOnly :=false;   //書換える事を指示
  try
   Exclusive :=True;    //排他ファイルとして
   Open;          //開いて
   if findKey([uName]) then //検索した名前があれば
   begin
    edit;          //編集モードに
    Result := Fields.Fields[1].AsInteger+1;
   end else begin
    Append;        //名前が無ければ挿入モードに
     Result:=1000;     //初期値を1000とする
    Fields.Fields[0].AsString :=uName;
   end;
   Fields.Fields[1].AsInteger:=Result;
   Post;
   Close;
  except
  Result:=-1; //失敗したら負数を返す
  end;
 finally
  free;
 end;
end;
 begin
 result:=xRenBan;
 i:=0;
 while(Result<0) do
 begin
  if(i>100)then exit;
  inc(i);
  Sleep(100);
  result:=xRenBan;
 end;
end;
////////////////////////////////////////////
//連番用テーブルをコードから作成する場合です
procedure RenBanInit(TblName:string);
var s:TStringList;
begin
s:=TStringList.create;
 with TTable.Create(nil) do
 try
  Session.GetTableNames('MYDB'@`TblName@`false@`false@`s);
  if s.Count=0 then
   DatabaseName:= 'MYDB';
   TableName :=TblName;
    with FieldDefs do begin
    Clear;
    Add('NAME'@`ftString@`16@`false);
    Add('Number'@`ftSmallint@`0@`false);
    end;
    CreateTable;
    AddIndex('NAME'@`'NAME'@`[ixPrimary]);
  finally
  s.free;
  end;
end;
76ビッケ:2000/03/21(火) 18:49
(割り込んですみません。「DDL」というスレッドにも
書いたのですが、分かる方がいたら教えて下さい。)
DDLは(1)Data Description Languageの略だと
思っていたのですが、Oracleの本を見ると
(2)Data Definition Languageと書いてあります。
(1)@`(2)は同じものなのか、同じものだとすると
(2)はOracle独自の用語なのか何なのか、
違うものだとすると何が違うのか、教えて頂ける
とありがたいです。
77>76:2000/03/21(火) 19:15
Data Description Language = データ記述言語。
Data Definition Language データ定義言語。
SQLのDDLの意味的には Definition がそれらしいけど

レポート課題かなんかですか?

78ビッケ:2000/03/22(水) 00:40
>77
お返事ありがとうございます。
> SQLのDDLの意味的には Definition がそれらしいけど
実際、日本語訳は「データ定義言語」と書いてある文書が
多いんですよね。それでよけいに混乱しています。
会社の後輩に聞かれて調べたのですが私も分からなくて、
泥沼にはまってしまいました。
どなたか御存じでしたら御教授下さい。
79名無しさん:2000/03/22(水) 07:36
確かにOracleだけが Definition だね。直接聞いてみたら?
80>78:2000/03/22(水) 08:01
後輩に良い顔見せたいなら、その場でOracleに電話して見せれば良かったのに
81陰陽:2000/03/22(水) 10:33
73のコードだけど、RenBanの方で
例外を全部exceptで処理されるので、
一個目のtry〜finallyはいらないよ
except〜endのあとで普通にfreeすればいいだけ

RenBanInitの方では例外を処理せずに呼出元へ
返してしまうので、「例外を生成する可能性のある関数だよ」
というのが(関数名などから)わかる方がいいと思うんだけど
どうかな?VCLとかはヘルプに記載してあるだけだし、
ドキュメントをきちんと整える癖のある人ならいいけど。

つーかドキュメントはきちんと整えなさい>おれ
82名無しさん:2000/03/22(水) 13:56
75は、最後に free (TTableの)を忘れていると思う
83名無しさん:2000/03/27(月) 17:03
age
84割り込んですみません:2000/03/31(金) 17:43
プリンタの話が途中あったので ついでと言ってはなんですが
http://www.inprise.co.jp/tips/delphi/dh010/index.html

を参考に印刷(ドットインパクト)しようと思います
このTextOutとかは紙の場合、左上から順に出力しなくても
常に自動的に並べ直して貰えるものなのでしょうか?
8584:2000/03/31(金) 18:18
まあ試せばすぐ判るのでしょうが、レーザとファックスしか手元にないので
86陰陽:2000/03/31(金) 18:24
Printer.EndDoc
してから書き込みにいくので大丈夫でしょう
8784>86:2000/04/01(土) 11:30
ありがとうございます。 昔みたいに紙が逆送りされるなんて事はないですよね。

ついでに、このスレッドで気付いた事。

53の
FormatDateTime('d/m/yyyy'@`MonthCalendar1.Date); は
FormatDateTime('m/d/yyyy'@`MonthCalendar1.Date); が正しいと思います

それから TTableのFilterを使う場合は
Filter:='納品日 <= '''+formatDateTime('yyyy/m/d'@`Date)+'''';
のような順になります。また"ではなく'で囲む必要があるようです
8884
プリンター制御にはNkPrinterのお世話になっています
入手方法はGooで NkPrinterで 検索すると判ると思います

TPrinterの代わりに使え、紙サイズ等もプログラムで設定出来ます