SQL文でのFormat関数について

タグの編集
投稿者 河童  (社会人) 投稿日時 2011/3/3 21:00:17
VB 2008 Express

こんばんは。
いつも大変お世話になっております。

SQL文でのFormat関数について教えて下さい。

D_請求というテーブルには
年月日(2011/03/01)で登録されている日付のフィールドがあります。

データの取得時の条件として
日付を年月で抽出したいと考えています。

なぜかというと
2011/03/01から2011/03/31の
データを取得したいからです。

下記のようにSQLを記述したのですが、
「FOMAT という関数は組み込まれていません」
というエラーが発生してしまいます。

SQL文にFORMAT関数を組み込むには
どのようにすればいいですか?

よろしくお願い致します。

'wYMDには年月日が代入されています
Dim sDate As String = Format(wYMD, "yyyy/MM")

' データ取得
Dim strSql As String = "SELECT S.日付,"
strSql &= " S.伝票区分,"
strSql &= " S.返品,"
strSql &= " S.値引,"
strSql &= " S.今回請求支払額,"
strSql &= " FROM "
strSql &= " D_請求 AS S 
strSql &= " WHERE"
strSql &= " FORMAT(S.日付,'yyyy/MM') = '" & sDate & "'"
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2011/3/3 22:30:48
SQLは、データベースによって「方言」があります。

たとえば JET データベースの場合、SQL 中では Format 関数を使えません。
Access VBA から利用する場合は、VBA 側の関数を使う事ができるのですが、
VB.NET から利用する場合は、VBA や VB.NET の関数を呼び出せません。

河童さんは、何というデータベースをお使いなのでしょうか?

> 2011/03/01から2011/03/31の
> データを取得したいからです。
日付列が「文字列」型の場合は、
 WHERE 日付 LIKE '2011/03/%'
のように、LIKE 演算子を使うという手もあります。


また、相手が日付型の場合には、
 WHERE FORMAT(S.日付,'yyyy/MM') = '2011/03' 
ではなく、
 WHERE 日付 >= '2011/03/01' AND 日付 < '2011/04/01' 
のような問い合わせを行った方が良いでしょう。
(実際には、日付データをSQLに埋め込まず、パラメータ化して問い合わせた方が良いですが)

データ件数が多い場合、前者の処理ではデータ全件に対して FORMAT 変換が必要ですが、
後者では、日付列にインデックスがあればそれを使って範囲抽出する事ができるため
パフォーマンスが向上します。

ただし日付リテラルはDB によって異なるため、上記の問い合わせは
 WHERE 日付 >= #3/1/2011# AND 日付 < #4/1/2011#
 WHERE 日付 >= DATE '2011-03-01' AND 日付 < DATE '2011-04-01'
 WHERE 日付 >= TO_DATE('20110301', 'YYYYMMDD') AND 日付 < TO_DATE('20110401', 'YYYYMMDD')
などといった、実際のデータベースに沿った記述方式で書く必要があります。
投稿者 shu  (社会人) 投稿日時 2011/3/4 07:40:47
> strSql &= " S.今回請求支払額,"
ここの最後の『,』はいらないです。
投稿者 河童  (社会人) 投稿日時 2011/3/4 11:58:41
こんにちは。

魔界の仮面弁士さん、shuさん、
お返事ありがとうございます。

SQL Server 2005 Express という
無償版のデータベースを使用しています。

日付型の列に対して、
WHERE 日付 >= '2011/03/01' AND 日付 < '2011/04/01'
のように問い合わせを行った方が良いというアドバイスを元に
下記のように修正しました。

抽出条件は1日から月末までなので、
simeYMD(テキストボックスに入力されている日付)から
開始日と終了日を計算します。

開始日は、
simeYMDからその年月をMid関数で取得し「/01」を付け加えます。

終了日は、
開始日に1ケ月加えた後に1日引いてその月の月末を求めます。

'開始日
Dim strYMD As Date = DateTime.Parse(Mid(simeYMD, 1, 7) & "/01")
'終了日
Dim endYMD As Date = DateAdd(DateInterval.Day, -1, DateAdd(DateInterval.Month, 1, strYMD))

'SQL文のWHERE条件
strSql &= " S.日付 >='" & strYMD & "' AND "
strSql &= " S.日付 <='" & endYMD & "' "

この条件で1日から月末までのデータを取得することが出来ました。

後学のため教えて頂きたいことがあります。 
>(実際には、日付データをSQLに埋め込まず、パラメータ化して問い合わせた方が良いですが)
パラメータ化して問い合せるとはどういうことですか?

もしかしてストアド プロシージャというものを作成して
開始日と終了日をパラメータとして渡すというものですか?
 
>> strSql &= " S.今回請求支払額,"
>ここの最後の『,』はいらないです。 
ご指摘ありがとうございます。
コードを確認してみると、
投稿するときのタイプミスでした。

 
投稿者 よねKEN  (社会人) 投稿日時 2011/3/4 12:40:12
> 'SQL文のWHERE条件
> strSql &= " S.日付 >='" & strYMD & "' AND "
> strSql &= " S.日付 <='" & endYMD & "' "

この"日付"項目は時分秒は持っていない(00:00:00で持っている)のでしょうか?
※ SQLの内容からすると用途的には時分秒はいらないと想像はしますが。

date型を使っているなら問題なさそうです。(日付型とおっしゃっているのがそのままdate型であれば問題なしです)
もしdatetime型を使っているなら、データを登録する側の処理の作りがまずいと
時分秒を持ってしまっているようなケースも考えられます。

> WHERE 日付 >= '2011/03/01' AND 日付 < '2011/04/01'

魔界の仮面弁士さんがこのように書かれているのには理由があって、
例えば「3/31 23:59:59」というデータが入っていても大丈夫なように書かれています。

時分秒が00:00:00などの決まった値で持っている場合以外では、

日付 >= '2011/03/01' AND 日付 < '2011/04/01'  -- 2011/03/31 23:59:59頃まで(4/01のほんのほんのちょっと前まで)



日付 >= '2011/03/01' AND 日付 <= '2011/03/31'   -- 2011/03/31 00:00:00まで

の2つは意味が違ってきます。
投稿者 河童  (社会人) 投稿日時 2011/3/4 15:39:13
こんにちは。
よねKEN さん、お返事ありがとうございます。

なるほど。
日付 >= '2011/03/01' AND 日付 < '2011/04/01' 

日付 >= '2011/03/01' AND 日付 <= '2011/03/31'   
では意味が違ってくるんですね。
勉強になりました。

今回は時分秒は持っていないので
「00:00:00」となっています。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2011/3/5 00:10:38
> Dim strYMD As Date = DateTime.Parse(Mid(simeYMD, 1, 7) & "/01")
> Dim endYMD As Date = DateAdd(DateInterval.Day, -1, DateAdd(DateInterval.Month, 1, strYMD))

こんな方法もあります。考え方は同じですが。
Dim dt As Date = Date.ParseExact(simeYMD, "yyyy\/MM\/dd", CultureInfo.InvariantCulture)
Dim dtFrom As New Date(dt.Year, dt.Month, 1)
Dim dtTo As Date = dtFrom.AddMonths(1).AddDays(-1)



> パラメータ化して問い合せるとはどういうことですか?
ざっくり書くと、TableAdapter もしくは DataAdapter に
 SELECT * WHERE 日付 >= @f AND 日付 < @t
な SQL を渡して、Parameter クラス経由でデータを渡すというものです。