C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[6]: oracleで指定期間のデータを読み込む方法


(過去ログ 103 を表示中)

[トピック内 10 記事 (1 - 10 表示)]  << 0 >>

■61662 / inTopicNo.1)  oracleで指定期間のデータを読み込む方法
  
□投稿者/ 裕猫 (251回)-(2011/08/26(Fri) 09:30:17)

分類:[データベース全般] 

開発環境
OS: WindowsXP SP3
言語: VisualStudio2010 C#
Oracle 10gExpressEdition

以下のような形で2011年7月分の集計をしようとしています。
using (OracleConnection con = new OracleConnection())
{
con.ConnectionString = MKST.UID;
con.Open();
Object[] OJ = new Object[16];
using (OracleCommand cmd = con.CreateCommand())
{
cmd.CommandText = "select 日付,a,b,c,d,e,f,g,"
+ "h,i,j,k,l,m,n,o"
+ " from テーブル名 WHERE 日付 >= '" + Form1.Day2 + "/01' ORDER BY 日付 ASC";
using (OracleDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
for (int CT1 = 0; CT1 < 16; CT1++)
{
OJ[CT1] = dr[CT1];
}
if (Convert.ToInt64(OJ[0].ToString().Substring(0, 7).Replace("/", "")) > Convert.ToInt64(Form1.Day2.Replace("/", "")))
{ break; }
Keisan(OJ);
}
}
}
}
しかし2011年7月1日のデータ一つしか読みません。読み込み開始を2011年7月1日にし、7月の中のデータをループで読み込むにはどう書き換えたらいいのでしょう?
全データを読み込み日付の年月を比較し、取り出せばできますが、データが毎日増加していくので、かなりデータ数が多くなるのでその方法は使いたくないです。
いろいろ試していますが、いまだに解決できません。よろしくお願いいたします。
引用返信 編集キー/
■61663 / inTopicNo.2)  Re[1]: oracleで指定期間のデータを読み込む方法
□投稿者/ バキュラ (1回)-(2011/08/26(Fri) 10:28:34)
No61662 (裕猫 さん) に返信

Form1.Day2についての説明がないので、何とも言えませんが、
SQL文に間違いがなければ、

> if (Convert.ToInt64(OJ[0].ToString().Substring(0, 7).Replace("/", "")) > Convert.ToInt64(Form1.Day2.Replace("/", "")))

あたりがおかしいのではないでしょうか?
気になるのは、上記式で、OJ[0].ToString()...とありますが、これはOJ[CT1]でなくていいのですか?
あと、OJ[i]は、多分"yyyy/MM/dd"形式であることを想定していると思いますが、これは間違いないですか?
引用返信 編集キー/
■61664 / inTopicNo.3)  Re[1]: oracleで指定期間のデータを読み込む方法
□投稿者/ 魔界の仮面弁士 (2331回)-(2011/08/26(Fri) 11:08:41)
No61662 (裕猫 さん) に返信
> 以下のような形で2011年7月分の集計をしようとしています。
日付項目は、'2011/07/01' 形式の CHAR(10) ですか? それとも、DATE 型ですか?


DATE 型なのだとしたら、WHERE 日付 >= '2011/07/01' は避けた方が良いでしょう。
この場合、必要な書式が NLS_DATE_FORMAT の設定によって変化してしまうため、
 WHERE 日付 >= DATE '2011-07-01'
 WHERE 日付 >= TO_DATE('20110701', 'YYYYMMDD')
などといった構文を利用した方が安全です。また、それを取得する際にも、
SQL または C# 側で、日付→文字列化のための書式指定が必要です。

とりあえず今回は、CHAR(10) という仮定で回答します。


> " from テーブル名 WHERE 日付 >= '" + Form1.Day2 + "/01' ORDER BY 日付 ASC";
Day2 は '2011/07' 形式の string なのですね?


> しかし2011年7月1日のデータ一つしか読みません。
CommandText に設定した文字列を、TextBox 等に転記し、その SQL を C# からではなく
SQL Plus 等で実行してみてください。予期していたレコード数になっていますか?


> if (Convert.ToInt64(OJ[0].ToString().Substring(0, 7).Replace("/", "")) > Convert.ToInt64(Form1.Day2.Replace("/", "")))
これはたとえば Form1.Day2 が '2011/07' だったとして、対象レコードとして
  '2011/07/07'
  '2011/08/01'
  '2011/09/02'
  '2011/09/15'
という 4 レコードが該当する場合に、
 7/7 は if に該当しないので処理続行、
 8/1 は該当するのでループ脱出し、
 それ以降のレコード(9/2、9/15)は処理されない
…という流れを期待していますか?

もしそうだとしたら、C# 側で追加の絞り込みを行うのではなく、
最初の SQL 段階で条件を絞り込んでおくべきかと思いますよ。

たとえば、
 WHERE 日付 LIKE '2011/07/__'
とか
 WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'
などとして。
引用返信 編集キー/
■61665 / inTopicNo.4)  Re[2]: oracleで指定期間のデータを読み込む方法
□投稿者/ 裕猫 (252回)-(2011/08/26(Fri) 11:32:01)
No61663 (バキュラ さん) に返信
> ■No61662 (裕猫 さん) に返信
>
> Form1.Day2についての説明がないので、何とも言えませんが、
> SQL文に間違いがなければ、
>
>> if (Convert.ToInt64(OJ[0].ToString().Substring(0, 7).Replace("/", "")) > Convert.ToInt64(Form1.Day2.Replace("/", "")))
>
> あたりがおかしいのではないでしょうか?
> 気になるのは、上記式で、OJ[0].ToString()...とありますが、これはOJ[CT1]でなくていいのですか?
> あと、OJ[i]は、多分"yyyy/MM/dd"形式であることを想定していると思いますが、これは間違いないですか?
日付データはstring型でyyyy/MM/dd"形式です。
日付データは読み込み時OJ[0]に入りますのでOJ[CT1]でなくとも固定で大丈夫です。
しかしやはりこのあたりの書き方が悪いのでしょうかね?
引用返信 編集キー/
■61666 / inTopicNo.5)  Re[2]: oracleで指定期間のデータを読み込む方法
□投稿者/ 魔界の仮面弁士 (2332回)-(2011/08/26(Fri) 11:32:05)
No61663 (バキュラ さん) に返信
> 気になるのは、上記式で、OJ[0].ToString()...とありますが、これはOJ[CT1]でなくていいのですか?
この if 文は for ループの外にあるので、CT1 にはアクセスできないと思いますよ。

外側の while ループは、レコードを移動させるもので、
CT1 の for ループは、レコード内の列データを取り出すもの、
OJ[0] での if 判定は、翌月以降のデータを Keisan させないためのものですね。


この場合、OJ は Keisan に渡すためだけのものであり、while ループの外では使用されないため、
>> Object[] OJ = new Object[16];
は while の中に移動させた方が良いと思います。

また、if による break 判定については、for ループの前に置いた方が無駄が無さそうです。
(そもそもは、if を使わずに SQL で WHERE 条件に含めた方が良いですが)
引用返信 編集キー/
■61667 / inTopicNo.6)  Re[2]: oracleで指定期間のデータを読み込む方法
□投稿者/ 裕猫 (253回)-(2011/08/26(Fri) 11:38:59)
No61664 (魔界の仮面弁士 さん) に返信
> ■No61662 (裕猫 さん) に返信
>>以下のような形で2011年7月分の集計をしようとしています。
> 日付項目は、'2011/07/01' 形式の CHAR(10) ですか? それとも、DATE 型ですか?
日付項目は、'2011/07/01' 形式の CHAR(10) です。

>>" from テーブル名 WHERE 日付 >= '" + Form1.Day2 + "/01' ORDER BY 日付 ASC";
> Day2 は '2011/07' 形式の string なのですね?
そうです。

>>if (Convert.ToInt64(OJ[0].ToString().Substring(0, 7).Replace("/", "")) > Convert.ToInt64(Form1.Day2.Replace("/", "")))
> これはたとえば Form1.Day2 が '2011/07' だったとして、対象レコードとして
>   '2011/07/07'
>   '2011/08/01'
>   '2011/09/02'
>   '2011/09/15'
> という 4 レコードが該当する場合に、
>  7/7 は if に該当しないので処理続行、
>  8/1 は該当するのでループ脱出し、
>  それ以降のレコード(9/2、9/15)は処理されない
> …という流れを期待していますか?
そのとうりです。

> もしそうだとしたら、C# 側で追加の絞り込みを行うのではなく、
> 最初の SQL 段階で条件を絞り込んでおくべきかと思いますよ。
>
> たとえば、
>  WHERE 日付 LIKE '2011/07/__'
> とか
>  WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'
> などとして。
WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'は試してみましたが、やはり1つしか読み込みませんでした。
WHERE 日付 LIKE '2011/07/__'は気づかなかったので試してみます。
引用返信 編集キー/
■61668 / inTopicNo.7)  Re[3]: oracleで指定期間のデータを読み込む方法
□投稿者/ 魔界の仮面弁士 (2333回)-(2011/08/26(Fri) 12:08:37)
No61667 (裕猫 さん) に返信
> 日付項目は、'2011/07/01' 形式の CHAR(10) です。
NCHAR(10) でも CHAR(11) でも VARCHAR2(12) とかでもないのですね?

う〜ん、日付列に余計な文字が混入しているのかと推測していたのですが、
CHAR(10) では最小限の文字しか入りませんものね…。謎です。


念のために確認しますが、その列は「CHAR(10 BYTE)」と「CHAR(10 CHAR)」の
いずれが使われているのでしょうか。仮に文字数で定義されているのだとしたら、
一部の数字や/記号が全角になっている可能性も調査した方が良いと思います。


> WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'は試してみましたが、やはり1つしか読み込みませんでした。
妙ですね。その現象は SQL Plus でも同じですか?

仮に SQL Plus で再現しないのであれば、ミドルウェア側の不具合か、
そもそもの接続先を間違えているぐらいしか思いつかないです。


確認のため、元の SQL から 日付の WHERE を削り、7月や8月のレコードが
含まれるようにして、その上で SQL の SELECT 句を
 SELECT 日付, …
から、
 SELECT CASE WHEN (日付 >= '2011/07/01' AND 日付 < '2011/08/01')
  THEN '◎' ELSE '×' END 日付確認, 日付, …
のように変更してみてください。
この場合も、7月1日だけが ◎ で、それ以外の日付が × になってしまうのでしょうか?
引用返信 編集キー/
■61671 / inTopicNo.8)  Re[4]: oracleで指定期間のデータを読み込む方法
□投稿者/ 裕猫 (254回)-(2011/08/26(Fri) 13:35:20)
No61668 (魔界の仮面弁士 さん) に返信
> ■No61667 (裕猫 さん) に返信
> 念のために確認しますが、その列は「CHAR(10 BYTE)」と「CHAR(10 CHAR)」の
> いずれが使われているのでしょうか。仮に文字数で定義されているのだとしたら、
> 一部の数字や/記号が全角になっている可能性も調査した方が良いと思います。
CHAR(10)なのでBYTEですね。
>>WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'は試してみましたが、やはり1つしか読み込みませんでした。
> 妙ですね。その現象は SQL Plus でも同じですか?
SQL Plus使ったことがないので未確認です。

> 確認のため、元の SQL から 日付の WHERE を削り、7月や8月のレコードが
> 含まれるようにして、その上で SQL の SELECT 句を
>  SELECT 日付, …
> から、
>  SELECT CASE WHEN (日付 >= '2011/07/01' AND 日付 < '2011/08/01')
>   THEN '◎' ELSE '×' END 日付確認, 日付, …
> のように変更してみてください。
> この場合も、7月1日だけが ◎ で、それ以外の日付が × になってしまうのでしょうか?

これに変えたら動かなくなりました。どうもORACLEがうまく動かないようです。処理中にプログレスバー表示しているので、この処理は
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
の中で実行しているのですが、この辺に原因があるかもしれません。またいろいろ試してみます。
引用返信 編集キー/
■61673 / inTopicNo.9)  Re[5]: oracleで指定期間のデータを読み込む方法
□投稿者/ 魔界の仮面弁士 (2334回)-(2011/08/26(Fri) 14:10:17)
2011/08/26(Fri) 14:12:26 編集(投稿者)

No61671 (裕猫 さん) に返信
> CHAR(10)なのでBYTEですね。
CHAR(10) という省略表記が、CHAR(10 BYTE) と解釈されるか CHAR(10 CHAR) と解釈されるかは
データベースの NLS_LENGTH_SEMANTICS に依存します。

BYTE 固定のセマンティクスで運用しているという認識で良いですか?


> >>WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'は試してみましたが、やはり1つしか読み込みませんでした。
>>妙ですね。その現象は SQL Plus でも同じですか?
> SQL Plus使ったことがないので未確認です。
試してみてください。使うのは SQL*Plus でも iSQL*Plus でも良いですが、
C# からではなく Oracle 純正環境からの接続でも同じ問題が発生するのかどうかで、
コーディングミスなのか、環境問題なのかの切り分けを行いやすくなります。


> これに変えたら動かなくなりました。
第三者にもわかるよう、状況をもう少し具体的に説明していただけると助かります。

CASE WHEN を実験するために、どのようなコードを書いているのか。

そして、どの行でどんなエラーが発生してしまうとか、
どの行を実行すると応答が無くなるとか、
こういう動作を期待していたけれども、こんな結果になってしまう、とか。


> 処理中にプログレスバー表示しているので、
既存のコードを直していくのではなく、実験用の新規コードを用意してみてください。
問題の切り分けを先に行いましょう。

原因を特定してからでなければ、現状のコードの何を修正するべきかも見えてきませんので。


それとも、「Oracle 側」には問題無く、プログレスバー制御や BackgroundWorker の扱いや
日付処理などの「C# 側」のコードに問題がありそうなのでしょうか?
だとしたら、既存コードに手を加えた方が良いでしょうけれども。


> private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
> の中で実行しているのですが、この辺に原因があるかもしれません。
その考えに至った理由は何でしょうか?
何か問題のありそうな箇所が見つかったのであれば、その情報も開示してみてください。
引用返信 編集キー/
■61676 / inTopicNo.10)  Re[6]: oracleで指定期間のデータを読み込む方法
□投稿者/ 裕猫 (255回)-(2011/08/26(Fri) 15:04:49)
No61673 (魔界の仮面弁士 さん) に返信
> 2011/08/26(Fri) 14:12:26 編集(投稿者)

> BYTE 固定のセマンティクスで運用しているという認識で良いですか?
はい。

>>>>WHERE 日付 >= '2011/07/01' AND 日付 < '2011/08/01'は試してみましたが、やはり1つしか読み込みませんでした。
> >>妙ですね。その現象は SQL Plus でも同じですか?
>>SQL Plus使ったことがないので未確認です。
> 試してみてください。使うのは SQL*Plus でも iSQL*Plus でも良いですが、
> C# からではなく Oracle 純正環境からの接続でも同じ問題が発生するのかどうかで、
> コーディングミスなのか、環境問題なのかの切り分けを行いやすくなります。
SQL PLUS これから試してみます。

> 既存のコードを直していくのではなく、実験用の新規コードを用意してみてください。
> 問題の切り分けを先に行いましょう。
実験用コードでは成功しました。

>> private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
>> の中で実行しているのですが、この辺に原因があるかもしれません。
> その考えに至った理由は何でしょうか?
> 何か問題のありそうな箇所が見つかったのであれば、その情報も開示してみてください。
他と違う組み方をしているのはそこだけでしたのでそうかなと思ったのですが、一つ一つ動作を追った結果、原因はkeisan()の中にあることが判明しました。
#region NOC メソッド
public static string NOC(object SOJ)
{
if (SOJ == null) { return null; } else { return SOJ.ToString(); }
}
#endregion

private void Keisan(object[] KOJ)
{
Int64 NB;
if (Henkan.NOC(KOJ[1]) != null)
{
MessageBox.Show("ct1=1" + "[" + Henkan.NOC(KOJ[8]));
NB = Convert.ToInt64(KOJ[1]);
Form1.TT[NB, 0] = Form1.TT[NB, 0] + Convert.ToInt64(KOJ[8]);
}

if (Henkan.NOC(KOJ[2]) != null)
{
MessageBox.Show("ct1=2" + "[" + Henkan.NOC(KOJ[9]));
NB = Convert.ToInt64(KOJ[2]);
Form1.TT[NB, 1] = Form1.TT[NB, 1] + Convert.ToInt64(KOJ[9]);
}

if (Henkan.NOC(KOJ[3]) != null)
{
MessageBox.Show("ct1=" + Henkan.NOC(KOJ[3]) + "[" + Henkan.NOC(KOJ[10]));
NB = Convert.ToInt64(KOJ[3]);
Form1.TT[NB, 2] = Form1.TT[NB, 2] + Convert.ToInt64(KOJ[10]);
}
   }
で調べたところnullのところでメッセージボックスが出てきました。nullをnullと認識しなかったため、数値にしようとしてエラーになり、止まっていたようです。
原因がわかりましたので解決とさせていただきます。SQL文かORACLEが原因ではないかと思っていたのでなかなか原因にたどり着けず混乱させてすみませんでした。
今後のために、MySQLの使い方を覚えます。いろいろご指導ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -