カテゴリ:データベース( 12 )

e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

データベースが有る時だけCREATEができない!!

osql にて、バッチ処理を途中で止める事が困難な事!
DBの存在を確認して、有ったら、、、、

なにでバッチを終了したらよいのか。。。
EXIT? QUIT? RETURN?
どれもうまくいかない。

EXITとQUITは、その文字列が書かれた行がosqlで処理された時点で、
osqlが終了してしまう。

RETURN は、次のGOまでの処理はスキップしてくれるけど、
GOの次からまた処理が再開してしまう。

しょうがないので、T-SQLの外で制御するようにした。

最初にDBの存在確認スクリプトを実行して、
その結果を標準出力から取得して、
データベース名が含まれるかどうか評価。

それによって、DBのインストールスクリプトを実行したりスキップしたり。
ああ、、面倒。
もっとスマートな方法が有るはずなのに、、、

' install_db.vbs
Option Explicit

Dim shell, output, pipe, pos, fso, ofile
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("Wscript.Shell")
Set pipe = shell.Exec("osql -E -i check_db.sql")
output = pipe.Stdout.ReadAll
pos = InStr(output, "DBNAME")
If IsNull(pos) Or pos = 0 Then
' 存在しない場合は作成
shell.Run "%ComSpec% /c osql -E -i c:\xxxx\db\create_database.sql > c:\install_db.log", , True
Else
' 既に存在する場合は、作成しない
Set ofile = fso.CreateTextFile("c:\install_dicom_db.log")
ofile.WriteLine "データベースが既に存在します"
ofile.WriteLine "データベースの作成をスキップしました"
ofile.Close
End If

Set pipe = Nothing
Set shell = Nothing
Set fso = Nothing



' check_db.sql
use master
GO
SELECT name FROM master.sys.databases WHERE name = N'DBNAME'
GO

[PR]
by isoq | 2008-11-14 14:30 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

ストアドプロシージャのアップデート

SQLデータベースを使用するアプリケーションを書いていると困る事がある。
パフォーマンスの向上のためにストアドプロシージャを使用する事があるが、このストアドプロシージャが有るが為に、プログラムのアップデートが困難になる事があるためだ。

ちゃんとしたパッケージでインストーラがしっかりしていれば、インストール中にデータベースのアップデートを行えば良いのだろけど、そんなにしっかりしていないので、Exeだけ更新したらデータベースもそれに勝手に対応してしまってほしいのだ。

この解決方法を2つ考えた。
1つは、暗黙的にストアドプロシージャのバージョンを確認する機能をC++のストアドプロシージャオブジェクトに持たせ、プロシージャの実行の前にバージョンを確認してバージョンが違っている場合は、自動的に ALTER PROCEDURE を実行する。(無い場合は、CREATE する。)

2つ目は、バージョンごとにストアドプロシージャの名称を変更して、どんどん追加してしまう。
無ければ、Exeが持つ最新版を追加。。。

どちらかというと、2つ目の解決方法の方が簡単そうなので、テストしてみようかな。
[PR]
by isoq | 2008-05-29 19:17 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

一時テーブルで検索範囲を指定して高速にページング

-- 一時テーブルを作成
CREATE TABLE #temp( x INT PRIMARY KEY IDENTITY, id int)
GO

-- 一時テーブルにインデックスと商品IDを記録
INSERT INTO #temp(id) SELECT [商品ID] FROM [商品]
GO

-- 一時テーブルでインデックスを制限して、特定範囲の商品を検索
SELECT #temp.x, [商品].* FROM #temp, [商品] WHERE x > @min AND x < @max AND #temp.id = [商品].[商品ID]
GO

-- 一時テーブルを削除(不要)
drop table [dbo].[#temp]
GO


@min と @max はあらかじめ作成しておいた変数。
[PR]
by isoq | 2007-01-04 15:25 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

NEWID() から ランダムの Integer を生成する SQL Server

SQLサーバーのランダム関数って、全くなってない。
毎回同じ値しか入ってこないし(seedが同じ場合)、ms(ミリ秒)などを利用して毎ミリ秒ごとに別のseedが入るようにしても、同じINSERT/UPDATE文の中では、(何分かかろうが)同じ値が入ってしまうみたい。。。まどろっこしい。

通常、SQL Serverでアイテムをランダムに並び替えるには、newid() を使いますが、INT型でランダム値がほしいこともあります。
こんな感じで、達成できました。
convert(int, convert(varbinary(4), newid()))

[PR]
by isoq | 2006-05-18 23:17 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

VCからADOの戻り値を取得する

VCからADOで発行したSQLコマンドの戻り値を取得するのにちょっと苦労したので、書き留めておく。

CString strStoredProcedureName; // ストアドプロシージャ名
int ERROR_VALUE;        // エラーの時に返す値

try
{
    // 戻り値パラメータの設定
    _ParameterPtr pParam;
    VARIANT varReturn;
    varReturn.vt = VT_I4;
    varReturn.lVal = 0;
    pParam = m_pCommand->CreateParameter(_bstr_t("@ReturnValue"), adInteger, adParamReturnValue, 4, varReturn);
    m_pCommand->Parameters->Append(pParam);
    
    // 他のパラメータの設定
    
    m_pCommand->CommandText = _bstr_t(strStoredProcedureName);
    m_pCommand->Execute(NULL, NULL, adCmdStoredProc);
    
    // コマンドの戻り値を取得
    return m_pCommand->GetParameters()->Item[_bstr_t("@ReturnValue")]->Value.lVal;
}
catch(_com_error &e)
{
    // エラー処理
    return ERROR_VALUE;
}


戻り値の取得が奇々怪々。
しかも、戻り値のパラメータは、パラメータリストの先頭に配置しないといけないという決まりがある。
先頭以外のところに戻り値パラメータを渡しても、値が返ってこない。
つまり、最初のパラメータ登録は、戻り値にする必要がある。
戻り値が不要の場合は、指定しなくて良い。
[PR]
by isoq | 2006-02-21 12:56 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

クエリアナライザ(QueryAnalizer)を便利にする

クエリアナライザは、起動してから接続先を選んで、接続してからDBを選んで、SQL文を書いて、、、と、何度もやっていると面倒になってきます。

そんなときには、こんなショートカットを作れば、楽できます。

isqlw.exe -S server-name -d db-name -E -f 


こんなショートカットをファイル名としてデータベース名を付けて保存しておいて、T-SQLのスクリプトファイル(.sql)をドラッグアンドドロップすると、、、ちゃんと接続して、ファイルが開けてしまうんです。
あとは、実行ボタンを押すだけ。
便利じゃん。

接続までで、SQLは毎回最初から書くんだよ!と言う人は、
isqlw.exe -S server-name -d db-name -E

でOKです。

コマンドライン引数を確認するには、コマンドプロンプトから、
isqlw.exe -?

と入力します。
[PR]
by isoq | 2005-07-15 14:23 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

ADO Recordset.MoveFirst で '80040e18' "行セットの位置は再開できません。" エラー

ADO + ASP で次のように書いたら、'80040e18' "行セットの位置は再開できません。" エラーが発生した。
Dim conn, rs, cmd
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open CONN_STRING
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = "sp_nantara"
cmd.CommandType = adCmdStoreProc
cmd.Parameters.Append cmd.CreateParameter("@param1", adVarChar, adParamInput, 255, "param1")
Set rs = cmd.Execute()
Do While Not rs.EOF
  itemCount = itemCount + 1
  rs.MoveNext
Loop
rs.MoveFirst

このエラーは、rsのカーソルタイプが前方スクロールカーソルの場合に発生する。
Command.Execute を使用した場合は、カーソルタイプの設定出来ない。
(というか私が知らないだけ?)

なので、もう一度SQLクエリを発行して新しいレコードセットを取得しちゃうと言う、ちょっと強引な解決方法で、エラーを回避した。
'rs.MoveFirst
Set rs = cmd.Execute() 

でも、これでは、以前のレコードと同じ物は取得できない可能性がある。
つまり、2回のSQL発行の間に更新された場合は不整合なデータを取得してしまう事になる。
更新されないデータベースや、更新のタイミングを決められる場合だけ、これで解決できる。

肝心のカーソルタイプの変更方法は、、、
まだ解明できていません。 ^^;
[PR]
by isoq | 2005-07-12 11:34 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

パラメータクエリ(ADO + VBS + MSSQL)

ここでは、商品カテゴリーをクエリパラメータとして受け取り、
それをそのままパラメータとしてDBを検索する方法を説明。
また、商品はランダムに並び替える。

コマンドパラメータの設定方法を覚えるために、ここに記す。
対象は、ADO + VBS + MSSQL。

<%
Dim conn, cmd, rs, strCategory

' カテゴリ文字列をとりあえず配列に
strCategory = Request("category")
If strCategory = "" Then
    Response.Write "Bad Request: カテゴリが指定されていません."
    Response.End
End If

Set conn = Server.CreateObject("ADODB.Connection")
conn.Open CONN_STRING    ' 環境に合わせて適切な接続文字列を使用する
If Err.Number <> 0 Then
    Response.Write "DB Error: データベースが開けません."
    Response.End
End If

Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn
cmd.CommandText = "get_category_items"    ' ストアドプロシージャ名
cmd.CommandType = adCmdStoredProc    ' ストアドプロシージャをコール(4)
cmd.Parameters.Append cmd.CreateParameter("@category", 200, adParamInput, 255, strCategory)
Set rs = cmd.Execute()

Do While Not rs.EOF
    If Not Response.IsClientConnected Then
        Response.End
    End If
    Response.Write "<div>"
    Response.Write "ID: " & rs("id") & "<br>"
    Response.Write "Name: " & rs("name") & "<br>"
    Response.Write "Price: " & FormatCarancy(rs("price")) & "<br>"
    Response.Write "</div>"
    rs.MoveNext
Loop
rs.Close
%>

このスクリプトは、次のようなストアドプロシージャが
登録されている事を前提としている。

CREATE PROCEDURE dbo.get_category_items
    @category varchar(255)
AS

SELECT * FROM Products WHERE [category] = @category ORDER BY NewID()
GO

[PR]
by isoq | 2005-05-26 16:22 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

Microsoft SQL Server でランダムSELECT

MSSQLで、レコードの先頭n行だけ、選択したいときには、
SELECT TOP n * FROM Products

のようにしますが、
ランダムに10行だけを抽出したい場合には、
次のようにする事で実現できます。
SELECT TOP 10 * FROM Products ORDER BY NEWID()

[PR]
by isoq | 2005-05-25 13:45 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇

Accessのデータベースファイル (*.mdb)でデータベース その2

Accessデータベース(MDB)ファイルをADOで更新したが、実際の更新が遅く、他の場所で更新後に取得した値に更新が適用されていないという話の続き。

Tracked baack from Accessのデータベースファイル (*.mdb)でデータベース その1

その後、よく調べてみると、JetEngine というオブジェクトがあり、MDBファイルへのフラッシュ(RefreshCache)操作ができるらしい。
これを実装すれば、確実に読み取りができるはずだ。
が、今回は時間がないので、また今度。
できたら報告します。

参照:
JetEngine の使い方
HOWTO: Compact Microsoft Access Database Through ADO
[PR]
by isoq | 2004-02-12 19:20 | データベース
e87.com(千趣会イイハナ) 花を贈るなら日比谷花壇