• ベストアンサー

年と月が別カラムの場合のSQL

あるテーブルから、指定した期間のデータを抽出したいのですが、うまく取れません。 テーブル:RecData SortID iYear iMonths Amount --------------------------------------------  1   2002  3   100  1   2002  4   113  :    :   :   :  1   2008  7   112  1   2008  8   102  2   2002  3   40  2   2002  4   34  :    :   :   :  2   2008  7   43  2   2008  8   41 上記のようなテーブルがあるのですが、すべて数値型です。 このテーブルから、「SortIDが1で、2002年5月から2003年4月のデータ」を検索するにはどのようにしたら良いでしょうか? 「Select * from RecData Where SortID = 1 And iYear = 2002 And iMonths >= 5 Or SortID = 1 And iYear = 2003 And iMonths <= 4」 のようなやり方だと、「2002/04から2005/03」のような期間は正しく取れません。 その場合は1年づつループしなければ取れないでしょうか。 よろしくお願い致します。 使用しているDBはSQLServer2000 で、VBからSQL文を作成しています。  

質問者が選んだベストアンサー

  • ベストアンサー
noname#7749
noname#7749
回答No.3

# 現在手元にSQL Serverの環境もリファレンスもないので、検証できない状態ですが....。 厳密に日付型として評価させたいなら、CASTを使用して WHERE CAST(CAST(iYear AS VARCHAR) + '/' + CAST(iMonths AS VARCHAR)+ '/01' AS DATETIME) BETWEEN 2002/05/01 AND 2003/04/30 のようにする必要がありそうです。 それよりは、日付型に拘らずに、 WHERE (iYear * 100 + iMonths) BETWEEN 200205 AND 200304 と数値型で処理した方が簡単です。 (No.2さんの案とほとんど同じですが....) この方法なら、四則演算以外の知識を必要としないので、小学生でも実装が可能という利点があります。 # いずれにせよ、WHERE句の左辺で演算を行うので、途轍もなく遅そうなSQLですが....。 > 1年づつループしなければ取れないでしょうか。 お金が毟れる客が相手なら、最初は意図的に性能の悪い作りにしておいて、「チューニング」と称して後から予算を請求する戦略も考えられます。

Ulrika
質問者

お礼

どんな評価方法でも取れれば良いです。 なのでCASTより四則演算の方が簡単ですね。 しかもConvertも使わなくてすむし…。 実際に書いてやってみましたが、四則演算で取れてしまうし。 今まで取れなかった数年にまたがった期間もバッチリですね。 チューニングと称して予算を請求する戦略で、設計時に年と月が別で日付型にしなかったなんてことは…ないよなぁ…。今から「チューニング」するとVB側のSQL文を全部書き直しになるから違うでしょうねぇ。 ありがとうございます。

その他の回答 (6)

noname#7749
noname#7749
回答No.7

VBでSQL文を生成する、とのことですので、If条件で場合訳をする必要がありそうです。 # WHERE句にORが多い場合、UNIONで繋いだほうがパフォーマンスが高いかも....。(邪道??)

Ulrika
質問者

お礼

何度もありがとうございます。 やはりVB側の分岐条件でバグを作りこむ方が不安なもので 今回はパフォーマンスは見送る事にします。(~_~;)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.6

>が、やはり「2002年から2005年」のように、終了年が開始年の翌年で無い場合は >「iYear = 2002」「iYear = 2003」を「iYear >= 2002」「iYear <= 2003」にしても >ダメですよね where SortID = 1 And ((iYear = 2002 And iMonths >= 5) or (iYear = 2005 And iMonths <= 4) or (iYear > 2002 And iYear < 2005 And ))

Ulrika
質問者

お礼

何度もありがとうございます。 やはりOR でつなげていくんですね。 指定期間によってはVB側の分岐が複雑になりそうなので 今回はパフォーマンスは無視する事にいたします。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.5

>冷静に見直してみると、No.1のSQLが最速のように見えます。 というか、最速です。 ちなみに#1のSQL以外は、iYearやiMonthsにインデックスをはっても効果がありません。 つまり、チューニングもできません。 #SortID、iYear、iMonthsの組が主キーだったらコストベースならインデックス勝手に使ってくれるかも 検索条件において、フィールドに対して関数を使ったり演算を行った場合、インデックスはそのフィールドに存在しても使用されません。 関数を使ったり、演算するのは最後の手段です。

Ulrika
質問者

お礼

え…?!チューニングもできないのですか?! 検索条件で演算しちゃうと、インデックスは無意味ですか。 複雑なSQLで1度で取るか、何度かSelect文を発行するか悩む時もありますが。 やろうとしてることは最後の手段だったのですね。 参考になりました。 ありがとうございます。

noname#7749
noname#7749
回答No.4

冷静に見直してみると、No.1のSQLが最速のように見えます。

Ulrika
質問者

お礼

最速、ですか。 これで数年にわたって簡単に取れるなら問題なかったんですが。 うーん、なんであーいうテーブル設計になっているのかナゾです。 この際、ノロくてもヨイです。(~_~;) 助かりました。m(_ _)m

回答No.2

convert を使用して文字列にしてから連結して 200203 200204 200205 のような形にしたものに対して範囲指定してやればいいんじゃないでしょうか。

Ulrika
質問者

お礼

sql初心者なもので、convert がよく判っていないのですが… 文字連結してから数値に戻して大小比較ですか? おお、いいかもしれません。 convert のお勉強をいたします。 ありがとうです。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

where SortID = 1 And ((iYear = 2002 And iMonths >= 5) or (iYear = 2003 And iMonths <= 4))

Ulrika
質問者

お礼

この方法で試してみたところ、「2002/5~2003/4」は ちゃんと取得できました。 が、やはり「2002年から2005年」のように、終了年が開始年の翌年で無い場合は「iYear = 2002」「iYear = 2003」を「iYear >= 2002」「iYear <= 2003」にしてもダメですよね…。

関連するQ&A