SQLの窓

2017年10月29日


C# : Microsoft Access のテーブルとビューの一覧と任意の SQL を実行するテンプレート

Visual Studio 2012 で作成しています。
(C:\Users\ユーザ\Documents\Visual Studio 2012\Templates\ProjectTemplates に保存します)





Access を参照すると、テーブル一覧とビュー一覧が表示され、テーブルまたはビューをダブルクリックすると、行を表示するテンプレートです。

システムテーブル表示をチェックすると、Access のシステムテーブルを表示しますが、ユーザと権限の管理でシステムテーブルへのアクセス権限が設定できるのは、.mdb ファイルのみになります。

サンプルデータ / 販売管理C.accdb と 販売管理C.mdb



以下はシステムテーブルを表示したものですが、表示できないデータは x となっています。



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SqlUnitAccess2 {
	public partial class Form1 : Form {

		// ファイル選択用
		private OpenFileDialog ofd = new OpenFileDialog();

		// *********************
		// コンストラクタ
		// *********************
		public Form1() {
			InitializeComponent();
		}

		// *********************
		// 画面初期処理
		// *********************
		private void Form1_Load(object sender, EventArgs e) {

			// *********************
			// タイトル表示変更
			// *********************
			this.Text = "SqlUnitAccess";

		}

		// *********************
		// 参照ボタン
		// *********************
		private void ref_Click(object sender, EventArgs e) {

			// *********************
			// ファイル選択
			// *********************
			ofd.Filter = "Access(*.mdb;*.accdb)|*.mdb;*.accdb|すべてのファイル(*.*)|*.*";
			ofd.FilterIndex = 1;
			ofd.Title = "Access データベースを選択してください";
			ofd.RestoreDirectory = true;

			if (ofd.ShowDialog() != DialogResult.OK) {
				return;
			}

			// *********************
			// タイトル表示変更
			// *********************
			this.Text = ofd.FileName;

			// *********************
			// テーブル一覧表示
			// *********************
			loadTables(ofd.FileName);

		}

		// *********************
		// 実行ボタン
		// *********************
		private void action_Click(object sender, EventArgs e) {

			string sql = textBox1.Text;
			// *********************
			// select 実行
			// *********************
			executeReader(ofd.FileName, sql);

		}

		// *********************
		// テーブル一覧ダブルクリック
		// *********************
		private void tabel_Select(object sender, DataGridViewCellEventArgs e) {

			// *********************
			// table 名取得
			// *********************
			string value = dataGridTables.Rows[e.RowIndex].Cells[0].Value.ToString();
			textBox1.Text = "select * from " + value;

			// *********************
			// select 実行
			// *********************
			executeReader(ofd.FileName, textBox1.Text);

		}

		// *********************
		// テーブル一覧表示
		// *********************
		private void loadTables(string path) {

			dataGridSelect.DataSource = null;

			using (OleDbConnection myCon = new OleDbConnection()) {

				// *********************
				// 接続文字列の作成
				// *********************
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", path);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
					return;
				}

				DataTable dataTable = null;
				if (checkBoxSysTable.Checked) {
					// *********************
					// 全て
					// *********************
					dataTable = myCon.GetOleDbSchemaTable(
						OleDbSchemaGuid.Tables,
						new object[] { null, null, null, null }
					);
				}
				else {
					// *********************
					// TABLE と VIEW をマージ
					// *********************
					dataTable = myCon.GetOleDbSchemaTable(
						OleDbSchemaGuid.Tables,
						new object[] { null, null, null, "TABLE" }
					);
					DataTable dataTable2 = myCon.GetOleDbSchemaTable(
						OleDbSchemaGuid.Tables,
						new object[] { null, null, null, "VIEW" }
					);
					dataTable.Merge(dataTable2);
				}

				// 表示しない列は削除
				dataTable.Columns.Remove("TABLE_CATALOG");
				dataTable.Columns.Remove("TABLE_SCHEMA");
				//dataTable.Columns.Remove("TABLE_TYPE");
				dataTable.Columns.Remove("TABLE_GUID");
				dataTable.Columns.Remove("DESCRIPTION");
				dataTable.Columns.Remove("TABLE_PROPID");
				dataTable.Columns.Remove("DATE_CREATED");
				dataTable.Columns.Remove("DATE_MODIFIED");

				// 表示
				dataGridTables.DataSource = dataTable;

				// 接続解除
				myCon.Close();
			}

			// カラム幅の自動調整
			dataGridSelect.AutoResizeColumns();
		}

		// *********************
		// select 実行
		// *********************
		private void executeReader(string path, string sql) {

			using (OleDbConnection myCon = new OleDbConnection())
			using (OleDbCommand myCommand = new OleDbCommand()) {

				// *********************
				// 接続文字列の作成
				// *********************
				myCon.ConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};", path);

				// *********************
				// 接続
				// *********************
				try {
					// 接続文字列を使用して接続
					myCon.Open();
					// コマンドオブジェクトに接続をセット
					myCommand.Connection = myCon;
					// コマンドを通常 SQL用に変更
					myCommand.CommandType = System.Data.CommandType.Text;
				}
				catch (Exception ex) {
					MessageBox.Show(this, ex.Message);
					return;
				}

				// *********************
				// 実行 SQL
				// *********************
				myCommand.CommandText = sql;

				// *********************
				// レコードセット取得
				// *********************
				try {
					using (OleDbDataReader myReader = myCommand.ExecuteReader()) {

						DataTable dataTable = new DataTable();
						dataTable.Load(myReader);
						dataGridSelect.DataSource = dataTable;

						// リーダを使い終わったので閉じる
						myReader.Close();
					}
				}
				catch (Exception ex) {
					myCon.Close();
					MessageBox.Show(this, ex.Message);
					return;
				}

				// 接続解除
				myCon.Close();

			}

			// カラム幅の自動調整
			dataGridSelect.AutoResizeColumns();
		}

		// *********************
		// システム表の表示エラー対応
		// *********************
		private void dataGridSelect_DataError(object sender, DataGridViewDataErrorEventArgs e) {

		}


	}
}




【VS(C#)の最新記事】
posted by lightbox at 2017-10-29 02:24 | Comment(0) | VS(C#) | このブログの読者になる | 更新情報をチェックする

2017年10月26日


別に納品するわけでは無いので、Android の ListView のカスタマイズなんてこれで十分でしょ / TestArrayAdapter バージョン2

前のバージョンはこちらになりますが、世の中に腐るほどある getView 内の記述を外に出しただけのものでした。しかし、よくよく考えてみると、Adapter 内で セットされているデータを取り出して、そのクラスで引数に渡したらもっと楽だし、View のセットなんかも、Adapter 内ですればいい事に気が付きました。

これで、いろんなテストを気楽に出来る人が増えると思うわけです。

TestArrayAdapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

public class TestArrayAdapter<T> extends ArrayAdapter<T> {

	public interface OnGetViewListener<T> {
		abstract public void onGetViewListener(int position, View convertView, ViewGroup parent, T item);
	}

	private OnGetViewListener listener = null;
	private int resource;
	private LayoutInflater inflater;

	public TestArrayAdapter(Context context, int resource, OnGetViewListener listener) {
		super(context, resource);
		this.listener = listener;
		this.resource = resource;
		this.inflater = (LayoutInflater)context.getSystemService
				(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if ( listener != null ) {

			if (convertView == null) {
				convertView = inflater.inflate(resource, null);
			}

			T item = this.getItem(position);

			listener.onGetViewListener(position, convertView, parent, item);
			return convertView;
		}
		return super.getView(position, convertView, parent);
	}
}

呼び出し側は、正式には以下のようにインターフェイスにも<WebData> を指定する事で引数の値を WebData として取得できます。しかし、面倒な場合は <WebData> を指定せずに引数を Object でもらってキャストして使えばいいはずです。
		// *******************************
		// ListView で一覧
		// *******************************
		listView = (ListView) MainControl.this.findViewById(R.id.listView);
		arrayAdapter = new TestArrayAdapter<WebData>(MainControl.this, R.layout.item, new TestArrayAdapter.OnGetViewListener<WebData>() {
			@Override
			public void onGetViewListener(int position, View convertView, ViewGroup parent, WebData item) {

				TextView textView;

				textView = convertView.findViewById(R.id.textCode);
				textView.setText(item.社員コード);

				textView = convertView.findViewById(R.id.textName);
				textView.setText(item.氏名);

				textView = convertView.findViewById(R.id.textType);
				textView.setText(item.所属名);
			}
		});
		listView.setAdapter(arrayAdapter);


画面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">


    <TextView
        android:id="@+id/textCode"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp"/>

    <TextView
        android:id="@+id/textName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black"
        android:textSize="23sp"/>

    <TextView
        android:id="@+id/textType"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="6dp"
        android:textSize="18sp"/>


</LinearLayout>




WebData
public class WebData {

	String 社員コード;
	String 氏名;
	String フリガナ;
	String 所属;
	String 性別;
	int 給与;
	String 手当;
	String 管理者;
	String 生年月日;
	String 生年月日2;
	String 所属名;

	@Override
	public String toString() {
		return 氏名;
	}
}


WebData は 『Java : Class 構造より、update 文を作成する』でも使用しています



タグ:android
posted by lightbox at 2017-10-26 20:00 | Comment(0) | 2017 Android Studio | このブログの読者になる | 更新情報をチェックする

2017年10月21日


Java : Class 構造より、update 文を作成する

作ったのは Android Studio です。

以下のクラスですが、一目して ListView 用のクラスである事が解ると思います( toString が表示用 )。また、JSON を Google Gson でデシリアライズする事を想定しているので、C 言語の構造体のような単純な定義です。

WebData クラス
public class WebData {

	String 社員コード;
	String 氏名;
	String フリガナ;
	String 所属;
	String 性別;
	int 給与;
	String 手当;
	String 管理者;
	String 生年月日;
	String 生年月日2;
	String 所属名;

	@Override
	public String toString() {
		return 氏名;
	}
}


この Class のインスタンスに、画面から入力データをセットし、Class 構造を取得して Update 文の where 以降以外を作成するコードが以下です。

buildUpdate メソッド
	public String buildUpdate(String table, Object obj, Class<?> cls) {
		String result = "";

		Field[] flds = cls.getDeclaredFields();
		String type = "";
		String col = "";
		String val = "";
		for( Field fld : flds ) {

			// null 値の場合無視
			try {
				if ( fld.get( obj ) == null ) continue;
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}

			// フィールド名( 列名に一致させた Class 定義 )
			col = fld.getName();
			try {
				// 値( 文字列 )
				val = fld.get( obj ).toString();

			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}

			// データ型 : この場合、int かそれ以外
			type = fld.getType().getName();

			if (!result.equals("")) {
				result += ",";
			}
			if (type.equals("int")) {
				if ( val.equals("") ) {
					result += String.format(" %s = null ", col);
				}
				else {
					result += String.format(" %s = %s ", col, val);
				}
			}
			else {
				if ( val.equals("") ) {
					result += String.format(" %s = null ", col);
				}
				else {
					result += String.format(" %s = '%s' ", col, val);
				}
			}

		}

		result = String.format("update %s set %s", table, result );

		return result;
	}

※ 本来、StringBuilder 等を使用するところを += 演算子を使用しているのはコードを見やすくする為です

エラー処理は最低限で作られていますが、重要なのは Field オブジェクトなので、ご理解下さい。

冒頭に、cls.getDeclaredFields() で、定義されている Field オブジェクトの配列を取得して、ループ処理しているだけです。

引数より、Object として、WebData のインスタンスが渡されて、fld.get( obj ).toString() でデータを取得し、fld.getName() として取得された文字列は列名と一致する事を想定しています。

あとは、fld.getType().getName() で、int かそれ以外でシングルクォートの使い方を決めるわけです。

以下は、その呼び出しコードです。
		WebData curInput = new WebData();

		String code = helper.getTextViewString(R.id.textViewCode);

		// 使用しないフィールドには null をセットする
		curInput.社員コード = null;
		curInput.所属名 = null;
		curInput.生年月日2 = null;

		curInput.氏名 = helper.getEditTextString(R.id.editText1);
		curInput.フリガナ = helper.getEditTextString(R.id.editText2);
		curInput.所属 = helper.getEditTextString(R.id.editText3);
		curInput.給与 = Integer.parseInt(helper.getEditTextString(R.id.editText5));
		curInput.手当 = helper.getEditTextString(R.id.editText6);
		curInput.管理者 = helper.getEditTextString(R.id.editText7);
		curInput.生年月日 = helper.getEditTextString(R.id.editTexBirth);

		curInput.性別 = ((Spinner)(helper.mainActivity).findViewById(R.id.spinner)).getSelectedItemPosition()+"";

		String update = helper.buildUpdate("社員マスタ", curInput, WebData.class );
		String text = update + String.format(" where 社員コード = '%s' ", code );



null を設定して、除外するフィールドを決めています。なので、このコードでは意図的に空文字を文字列の列にセットする事ができません。そういう場合は、仕様を追加します。



タグ:java Reflect
posted by lightbox at 2017-10-21 01:15 | Comment(0) | 2017 Android Studio | このブログの読者になる | 更新情報をチェックする

2017年10月12日


Oracle : SQL Plus で、デッドロックテスト ( ORA-00060 )

SQL Plus では、意図的に commit を実行しない限りトランザクションが終わらないので、二つの行を A クライアントと B クライアントで取り合うように UPDATE 文を実行すると、デッドロックを発生させる事ができます。

デッドロック(ORA-00060)が発生した場合、そちらのクライアントで rollback を実行すると、もう片方では更新が完了するので、そちらで commit を実行して更新を確定させます

▼ 対象レコード


A クライアントの SQL
update 商品分類マスタ set 名称 = 'A-野菜'
where 商品分類 = 'A01';

update 商品分類マスタ set 名称 = 'A-果物'
where 商品分類 = 'A02';

B クライアントの SQL
update 商品分類マスタ set 名称 = 'B-果物'
where 商品分類 = 'A02';

update 商品分類マスタ set 名称 = 'B-野菜'
where 商品分類 = 'A01';

実行の経過

A クライアントも B クライアントも違う行を更新して、それぞれ行は更新されますが、commit で確定されていないので実際の更新は行われていません。しかし、これらのレコードに対するロックが有効になります。





次の実行で更新が待機になり、その次の更新でデッドロックが起こり、A クライアントで待機が解除されてデッドロックのステータスが返ります。





デッドロック(ORA-00060)が発生したので、更新はやりなおしになります。いったん rollback を実行して次の更新に備えます( このような処理を何回までリトライするかはシステムであらかじめ決めておきます )



rollback が実行されてロックされていた行が開放されたので、B クライアントでは更新が完了するので、commit で確定させます。





posted by lightbox at 2017-10-12 14:36 | Comment(0) | Oracle | このブログの読者になる | 更新情報をチェックする

テーブルのTDをクリックしたら、INPUT で値を変更可能にして、元の値と違うものにはフラグを立てる処理を絵で書いて説明してみました



とにかく、複雑になってしまったので絵にしてみました。

デモページ(送信ボタンで一覧表示した後でデモ)


ソースコードはこんな感じ
	$("#data .row_data").each(function(i){

		var td = $(this).find("td").eq(2);

		td.css( 
			{ "text-decoration":"underline", "cursor":"crosshair", "background-color" : "pink" }
		);

		// 入力内容
		var text = td.text();
		// 入力内容を保存
		td.data("text", text );

		td.on("click", function(){
			if ( $(this).data("input") != "use" ) {
				// 入力切替えフラグ
				$(this).data("input", "use" );

				// 入力内容
				var text_now = $(this).text();

				// TD の表示を消去
				$(this).text("");

				// 入力を追加
				$("<input>")
						.appendTo($(this))		// TD に追加
						.val(text_now)			// テキストセット
						.focus()			// フォーカスセット
						// focusout で元に戻す
						.on( "focusout", function(){

							// 現在の入力
							var text = $(this).val();

							// 親 TD
							var td = $(this).parent();

							// データが変更されていたら『変更フラグ』をセット
							if ( text != td.data("text") ) {
								td.data("change", "yes");
								td.css("background-color","silver");
							}
							else {
								td.data("change", "");
								td.css("background-color","pink");
							}

							// TD に値を戻して 切替えフラグを消去
							td
								.append(text)
								.data("input", "" );

							// INPUT を削除
							$(this).remove();


						});

			}

		});

	});



posted by lightbox at 2017-10-12 03:17 | Comment(0) | jQuery | このブログの読者になる | 更新情報をチェックする
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり