• ベストアンサー

年と月が別カラムの場合の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

  • SQL文について

    開発言語:VB2010 DB:SqlServer2005 及び ACCESS2007 SQLサーバーのテーブルをAccessのテーブルへINSERTしたいのですが、 一文で行う事は可能でしょうか? (テーブルの構造は全く同じです) 同じDB内であれば、下記のような感じで出来ると思うんですが。 +----------------------------------+ INSERT into Atest_ACCESS SELECT * FROM Btest_SQL Where OperationDate => 2011/09/05 +----------------------------------+ 出来るのあればどのようにすれば良いのが教えて頂けると幸いです。 よろしくお願い致します。

  • SQLのSELECT文教えてください。

    VB5.0で、DBはSqlServer2000です。 SQL文のSELECT文で質問です。 ○A_TABLEの構成(概略) ・・・担当コード1・・・担当コード2 ○TANTO_TABLE 担当コード/担当名 (質問)TANTO_TABLEからA_TABLEの担当コード1と担当コード2の担当名を抽出したいのです。 次のSQLだと担当コード1のみしか抽出できません。 効率よく担当コード1と2の担当名を抽出するSQLを教えてください。お願いします。 SELECT 担当名 FROM A_TABLE,TANTO_TABLE WHERE A_TABLE.担当コード1 = TANTO_TABLE.担当コード

  • 複雑な抽出条件のSQL文

    まだまだ初心者ですがよろしくお願いします。 以下の条件でDBからデータを抽出したい場合のSQLを 教えていただきたいです。 ・テーブルAがありカラムがA、Bとある。 ・Aは重複できないようになっているがBは重複可。 ・Bが重複しているレコードのAの値が欲しい。 環境はSQLServer2000+VB6.0です 情報が足りないかも知れませんがよろしくお願いいたします。

  • データがあれば○○なければのSQL

    基本的なことなのかもしれませんが・・・ AとBというテーブルがあり、あるタイミングでAを元にBを作成します。つまりBはデータがある場合とない場合があります。また、2つは関連番号で紐づいています。 Aテーブルを抽出したい時に、抽出条件は以下です。 ・Bテーブルのステータスが1であれば抽出 ・Bテーブルのステータスが0であれば非抽出 ・Bテーブルにデータがなければ抽出 INNER JOINだとデータがない時に抽出できないし、 WHERE句にCASE句を入れればいいのかなと思いましたが、テーブルにデータがあればなんて条件書けないしで詰まりました。 SELECTした結果に対して条件つけて抽出する手も思いつきましたが もっと美しいSQLがあれば教えてもらえないでしょうか。 環境はSQLServerです。よろしくお願いします。

  • SQL文について

    テーブルの結合について教えてください。 (DBはオラクルです) select * from table1,table2 where table1.カラム名=table2.カラム名; で、結合が出来ることは分かりました。 やりたいことはテーブルの結合と、ある期間のデータを持ってきたいのです。 select カラム名 from table1 where カラム名 between '20020213' and '20020218'; で期間を決めて引き出すやり方も分かっています。 一度に結合と期間を決めて引き出すやりかたってどうすればよいですか? それとも不可能ですか? 教えてください。

  • mysqlで年と月を別々のカラムに収納しています

    mysql5.1を利用してデータベースを作成しています。 テーブルに年と月を別々で収納しているのですが、 そのテーブルの中のデータから「今月を過ぎていなければ」という条件で抽出したいのですが、 SQLの書き方がわかりません。 私のSQLの基礎の基礎しか教えてもらっておらず、 あとは独学で、現在のレベルはようやく少しサブクエリを書き出した(学びだした)レベルです。 しかもwindows上のNavicat Lite(アプリ)上で書いてる状態です。 自分のイメージ的には下記のような感じなのですが、動きません。 どなたか教えていただけないでしょうか。 よろしくお願いします。 hoge_tblテーブルからBカラムが'hoge'かつ、 hoge_tblテーブル内のYEARカラムとMONTHカラムの値を今月と比較して、 「今月を過ぎていなければ」といった条件を付けたいと考えております。 select A from hoge_tbl where B = 'hoge' and (select date_format(now(),'%Y%m') as NOW) < (select date_format('(select YEAR,MONTH from hoge_tbl )’,'%Y%m') as END)

    • ベストアンサー
    • MySQL
  • SQLの構文で質問です。

    いつもお世話になっております。 SQLの構文で質問です。 テーブルを開いて、データの中から日付を絞って抽出したいのですが、 whereの後にどのような記述をすればいいのかわかりません。 なんとなく『>』を使ってやってみましたがうまく抽出できませんでした。 例えば、2008/12/01~2008/12/31の絞りで抽出できるようにしたいのですが。 SELECT * FROM 日付 WHERE (日付   2008 / 12 / 01    2008 / 12 / 31) すみません、SQLを使い始めて間もなく本を見てはいるのですがうまくいかないもので。 宜しくお願いします。

  • SQL SERVER の Where条件

    初めて質問させて頂きます。 VB内でSQL文を作成し、それをSqlServerに送り実行させているのですが、 VB内でSQL文を作成する時に、Whereの条件を入れたり入れなかったりします。 その時、都度、WhereをつけるのかAndをつけるのか判断してプログラムを書くのが億劫なので Dim SqlString as string SqlString = "SELECT * FROM テーブルA WHERE 0 = 0" IF txtA.text <> "" then SqlString = SqlString & " AND 項目A = " & txtA.text END IF IF txtB.text <> "" then SqlString = SqlString & " AND 項目B = " & txtB.text END IF こういうズボラをしてるのですが、これってSqlの実行スピードに影響したりしますか? 思うようにインデックス使ってくれなかったりしますか? ご存知の方がご教授下さい。 よろしくお願いします。

  • 仕様が難しくてSQL文が作れません(新人プログラマ

    予約明細テーブルと貸出明細テーブルの2つがあります。 この2つのテーブルから以下の項目を抽出するSQL文がわかりません 貸出先:予約明細と貸出明細のうち直近(システム日付からの)の貸出先 ※予約明細と貸出明細には貸出期間開始日と貸出期間終了日があります。 貸出期間:上記明細の貸出期間(貸出先で抽出した貸出期間開始日、貸出期間終了日) 会場:予約明細の時のみ上記明細の会場 担当 上記明細の登録担当者 という項目を抽出するSQL文がわかりません 自分なりに考えた結果が以下のSQL文です。新人プログラマのため間違っていると思うので ご指摘願います。 SELECT 貸出先, 貸出期間開始日~貸出期間終了日 AS 貸出期間, 会場, 担当 FROM 商品 LEFT JOIN 予約明細 ON 商品コード = 商品コード (商品テーブルと予約明細テーブルは商品コードで結合します) LEFT JOIN 貸出明細 ON 商品コード = 商品コード (商品テーブルと貸出明細テーブルは商品コードで結合します) WHERE ここからがまったくわかりません。 SQL文だけでは抽出する事は不可能なのでしょうか VB.netで開発しているのですがVB側で処理しなければいけない 項目もありますでしょうか SQL文(とVB)のコードでのご回答宜しくお願いいたします。 環境 VB2005 SQLServer2005

  • VB.NETのSQL文について

    質問失礼します。 VB、SQLともに勉強しはじめて日が浅い初心者ですが、どなたかお力をお貸しください。 データベースに登録しているデータをNPOIを使って、出力したいと考えています。 DataTableを使用して作りましたが、上手くできない部分があります。 テーブルのカラムは、社員番号、事務物販名、登録数、登録日、更新日のようなものが入っているイメージです。 登録日を検索して、全てのテーブルを抽出したいのですが、○月○日〜○月○日にデータを登録した人というときに、つまづいてしまいました。 SQL.Append("SELECT " ) ・ ・ SQL.Append("WHERE ") SQL.Append(" 登録日 BETWEEN パラメータ1 AND パラメータ2 ) のように、書いたところ問題なく、出力されました。 パラメーターの部分は、DateTimePickerコントロールを配置して、日付を入力した値を設定しています。 2023/1/1 と 2023/1/2と2つ入力して、この2日間のデータを出そうとしたところ、1/1の文しか出力されませんでした。 原因は、データベースに入っているのは、Date型で、YYYY/MM/DD HH:mm:SS形式でした。 1/2の0時以降は、該当データに含まれないということは分かっているのですが、それを含めてのSQLの書き方がわかりません。 単純にSQLを書くには、 BETWEEN 2023/1/1 AND 2023/1/2 23:59:59 で、2日の文を抽出されますが、VBに書く時がうまくできない状態で、 時間の部分を、結合すれば良いのかと思い、 SQL.Append("SELECT " ) ・ ・ SQL.Append("WHERE ") SQL.Append(" 登録日 BETWEEN パラメータ1 AND パラメータ2 II '23:59:59' ") と、DataTimePickerから持ってきた、パラメータの日付に時間を結合してみたところ、ダメでした。 型の問題なのか、よくわからず、勉強している状態です。 基礎がなっておらず、初歩的なミスかと思いますが、ご指導ください。 データベースはOracleを使用しています。