SQLの窓

2018年06月18日


MySQL で、Group by して合算された行内で最新データの明細を再び取り出す SQL

MySQL のドキュメントでは、『3.6.4 特定のカラムのグループごとの最大値が格納されている行』 として解説されていますが、それとは違ったアプローチで。( 全ての元の列を取り出します )

目的の SQL を実行する為に以下のようなテーブルを作成しました。

1) 同一取引先で、複数の日付で明細が存在します。
2) それぞれの行は code というユニークな主キーをもっています。
3) 取引先コードで group by すると、MySQL の拡張仕様で取得されるデータはどのような値になるか解りません
列名 型名 最大桁 NULL 主キー
1 code int N 1
2 取引日付 datetime
3 取引先コード varchar 4
4 明細 varchar 100
5 数量 int
set @@session.sql_mode='PIPES_AS_CONCAT' で連結を容易にできるようにします

日付を文字列として考えると、常に10桁で、その後にキーを結合しても max である事には変わりが無いので、インラインビューとしての結果を分割してキーを得ます。

そして、それに対して再び本体を結合させて全ての列データを取得します。
set @@session.sql_mode='PIPES_AS_CONCAT';
select
 * from
	(select
		最大日付とキー.取引先コード,
		substring_index(target, ',', -1) as key_data
		from
		(select
			取引先コード,max(取引日付||','||code) as target from
			一行伝票
			group by 取引先コード
		) 最大日付とキー
	) キーを取り出す

inner join 一行伝票

on key_data = code

order by キーを取り出す.取引先コード

取引先コード key_data code 取引日付 取引先コード 明細 数量
1 476 476 2005/8/17 1 この日が最新 14
2 997 997 2005/9/8 2 この日が最新 12
3 521 521 2005/9/8 3 この日が最新 9
4 820 820 2005/8/24 4 この日が最新 16



posted by lightbox at 2018-06-18 17:19 | MySQL | このブログの読者になる | 更新情報をチェックする

2018年06月12日


C# でDataTable と DataSource を使用して、DataGridView にデータを表示するテンプレート( 行をダブルクリックしてダイアログを表示して行データを処理 )



画面はメインとなる DataGridView を最初に作成して Dock を Fill にします。Fill を設定したコントロールの上下にコントロールを使用する場合は、レイアウトは見たままでは無く Fill にしたものを一番上に置いて他のコントロールを下にします。



ステータスバー、ツールバー、メニューバーと順序が見ている位置と逆にして、それぞれの Dock プロパティを設定します。( ステータスとメニューはデフォルトで OK )

DataGridView のプロパティは重要なので以下に設定内容を自動作成されたコードで示します
            this.dataGridView1 = new System.Windows.Forms.DataGridView();

            this.dataGridView1.AllowUserToAddRows = false;
            this.dataGridView1.AllowUserToDeleteRows = false;
            this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.dataGridView1.Location = new System.Drawing.Point(0, 49);
            this.dataGridView1.MultiSelect = false;
            this.dataGridView1.Name = "dataGridView1";
            this.dataGridView1.ReadOnly = true;
            this.dataGridView1.RowTemplate.Height = 21;
            this.dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
            this.dataGridView1.Size = new System.Drawing.Size(813, 407);
            this.dataGridView1.TabIndex = 0;
            this.dataGridView1.CellDoubleClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellDoubleClick);

            public System.Windows.Forms.DataGridView dataGridView1;
ハイライトの行は、最初に設定する3つの編集を許可するかどうかのプロパティで、全て使用不可にしています。

1) 選択は単一行にする : MultiSelect = false
2) 選択表示は行全体にする : SelectionMode = FullRowSelect
3) 行のダブルクリックイベントは、CellDoubleClick で行う
4) Form2 から直接参照可能なように、public で定義する( Modifiers = Public )

次に、Form1 のソースコードですが、表示するデータは環境変数の一覧を使用しています( 実際に変更せずに DataGridView にデータを戻すまでの処理を行います )
    public partial class Form1 : Form
    {
        private DataTable table;
        private DataColumn column;
        private DataRow row;
        private Form nextWindow;

        public Form1()
        {
            InitializeComponent();
        }

        // ツールバーのボタンをクリック
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            // DataTable の作成
            table = new DataTable("EnvironmentVariables");

            // 列情報 の作成
            column = new DataColumn();
            column.DataType = Type.GetType("System.String");
            column.ColumnName = "環境変数";
            table.Columns.Add(column);

            // 列情報 の作成
            column = new DataColumn();
            column.DataType = Type.GetType("System.String");
            column.ColumnName = "値";
            table.Columns.Add(column);

            // 環境変数一覧より、行情報の作成
            foreach (DictionaryEntry dict in Environment.GetEnvironmentVariables())
            {
                row = table.NewRow();
                row["環境変数"] = dict.Key;
                row["値"] = dict.Value;
                table.Rows.Add(row);
            }

            // データーソース経由で DataGridView を表示
            dataGridView1.DataSource = table;
            // 第一カラムでソート
            dataGridView1.Sort(dataGridView1.Columns[0], ListSortDirection.Ascending);
            // 自動整列
            dataGridView1.AutoResizeColumns();

        }

        // 行をダブルクリックしてダイアログを表示
        private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            int rowNumber = e.RowIndex;
            if (rowNumber < 0 ){
                return;
            }

            // 行=>列=>からの参照
            string value = dataGridView1.Rows[rowNumber].Cells["値"].Value.ToString();
            Console.WriteLine(value);

            // モーダルダイアログとして開く
            using (nextWindow = new Form2(rowNumber))
            {
                nextWindow.ShowDialog(this);
            }

        }
    }


DataTable の考え方は、SQL 文の cerate tableを実行して列の定義を行った上で、テーブルに行を追加して行くというものです。そのテーブル情報全てを DataSource にセットする事で DataGridView への表示が完了します。

※ 列のタイトルは、ColumnName にセットされた内容が表示されます

そして、行をダブルクリックして 行=>列=>からの参照でデータを取得していますが、ここでは確認の為に表示しているだけで、実際は Form2 から直接に [列,行] という形で参照しています。
    public partial class Form2 : Form
    {
        private int rowNumber;
        private DataGridView grid;

        // コンストラクタで処理する行を渡す
        public Form2(int rowNumber)
        {
            this.rowNumber = rowNumber;
            InitializeComponent();

        }

        // データ変更ボタンで親内の DataGridView を直接変更
        private void button1_Click(object sender, EventArgs e)
        {
            grid["値", rowNumber].Value = textBox2.Text;
            grid["値", rowNumber].Style.BackColor = Color.Pink;

            Console.WriteLine("表示データを書き換えました");
            this.Close();
        }

        // キャンセル( フォームのデフォルトボタン )
        private void button2_Click(object sender, EventArgs e)
        {
            Console.WriteLine("キャンセルされました");
            this.Close();
        }

        // 初期フォーカス
        private void Form2_Shown(object sender, EventArgs e)
        {
            textBox1.Focus();

        }

        // 親フォームからの情報を取得
        private void Form2_Load(object sender, EventArgs e)
        {
            grid = ((Form1)Owner).dataGridView1;
            textBox1.Text = grid["環境変数",rowNumber].Value.ToString();
            textBox2.Text = grid["値",rowNumber].Value.ToString();

        }
    }

親フォームの参照は、Owner プロパティを使用し、初期フォーカスの設定を Shown イベントで行うのが重要です。




posted by lightbox at 2018-06-12 12:42 | VS(C#) | このブログの読者になる | 更新情報をチェックする

PowerShell( 実質C# )を使用して、ファイルの分割を行う

最初に『OpenFileDialog』でファイルを開くダイアログを表示して、そのファイルを1メガバイト(0x100000) のファイルに分割します。( ここでは、初期フォルダは C:\ )



split_file.ps1

readSize はバッファーに読み取られた合計バイト数で。 要求しただけのバイト数を読み取れなかった場合、この値は要求したバイト数より小さくなります。
$code = @"
using System;
using System.IO;
using System.Windows.Forms;
public class MyClass {
	public static void split_file() {


		OpenFileDialog obj = new OpenFileDialog();
		obj.Filter = "全て|*.*";
		obj.InitialDirectory = @"C:\";

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

		// 分割ファイルの拡張子の連番用
		int count = 0;

		// 入力ファイル
		FileStream fsi = new FileStream( obj.FileName, FileMode.Open, FileAccess.Read);

		// オリジナルファイル名
		string FileName = Path.GetFileName(obj.FileName);

		// 1メガバイト
		byte[] buffer = new byte[0x100000];
		// 読み込まれたサイズ
		int readSize;
		while(true) {
			// 読み込み
			readSize = fsi.Read(buffer, 0, buffer.Length);
			if (readSize == 0) {
				break;
			}
			count++;

			// 出力ファイル
			FileStream fso = new FileStream( string.Format("{0}.{1:000}", FileName, count),FileMode.Create,FileAccess.Write);
			fso.Write(buffer, 0, readSize);
			fso.Close();
		}
		fsi.Close();
	}
}
"@

Add-Type -Language CSharp -TypeDefinition $code -ReferencedAssemblies ("System.Windows.Forms")

[MyClass]::split_file()



inter_active.bat
echo off

echo 処理を開始しました

powershell -NoProfile -ExecutionPolicy Unrestricted .\split_file.ps1
実行すると、拡張子が オリジナルファイル名.001、オリジナルファイル名.002 というように連番で分割して作成されます。 結合は、copy コマンドを使用して行う事ができます
copy /b オリジナルファイル名.001 + オリジナルファイル名.002 オリジナルファイル名
関連する記事 PowerShell : ファイルを開くダイアログを使うのに System.Windows.Forms を参照する二つの方法 PowerShell( 実質C# )を使用して、MessageBox の応答でバッチファイルの処理を変化させる
posted by lightbox at 2018-06-12 00:00 | PowerShell + C# | このブログの読者になる | 更新情報をチェックする

2018年06月09日


PowerShell( 実質C# )を使用して、MessageBox の応答でバッチファイルの処理を変化させる

PowerShell は、C# のコードをそのまま実行する事ができるので、MesaageBox を表示させて、そまの応答結果をファイルに書き込んで、バッチファイル内の for で読み込み、内容によって実行先を変化させます

console_message_box.ps1
$code = @"
using System;
using System.IO;
using System.Windows.Forms;
public class MyClass {
	public static void console_message_box() {

		string path = Environment.GetEnvironmentVariable("temp");

		string writePath = string.Format(@"{0}\_check_result",path);

		StreamWriter sw = new StreamWriter(writePath,false);

		DialogResult check = MessageBox.Show("実行しますか?","確認", MessageBoxButtons.OKCancel);
		if (check == DialogResult.OK)
		{
			sw.Write("1");
		}
		else
		{
			sw.Write("0");
		}

		sw.Close();

	}
}
"@

Add-Type -Language CSharp -TypeDefinition $code -ReferencedAssemblies ("System.Windows.Forms")

[MyClass]::console_message_box()



inter_active.bat
echo off

echo 処理を開始しました

powershell -NoProfile -ExecutionPolicy Unrestricted .\console_message_box.ps1

FOR /F %%i IN (%temp%\_check_result) DO (
	if "%%i"=="1" goto :ok
	if "%%i"=="0" goto :cancel
)

:ok
echo OK を選択しました
goto :end

:cancel
echo Cancel を選択しました
goto :end


:end


関連する記事

PowerShell : ファイルを開くダイアログを使うのに System.Windows.Forms を参照する二つの方法

バッチファイル内で、コマンドプロンプトが管理者権限で実行されているかのチェック






posted by lightbox at 2018-06-09 23:05 | PowerShell + C# | このブログの読者になる | 更新情報をチェックする

タスクスケジューラの使用方法(schtasks.exe と taskschd.msc) : /IT という正しい説明がされていないオプションの使用方法

タスクスケジューラは、UI から登録するとそんなに問題はありませんが、schtasks.exe を使用してデスクトップと対話させるタスクを起動する場合は注意が必要です。



task_test : テスト用タスクを登録するコマンド
SCHTASKS /Create /RU ログインユーザ /RP パスワード /SC MINUTE /TN task_test /IT /TR "C:\user\bat\open_cmd.bat"
schtasks /Create /? で表示されるオプションの指定方法には、/IT というものがあります。
ジョブの実行時に /RU ユーザーが現在ログオンしている場合にのみ、タスクが対話的に実行されるようにします。このタスクは、ユーザーがログインしている場合にのみ実行します。
とありますが、登録直後は『ユーザーがログオンしているかどうかにかかわらず』に設定されています。さらに、登録時には以下のメッセージが表示されます。
警告: タスクは登録されていますが、指定されたすべてのトリガーがこのタスクを開始するわけではありません。詳細については、タスク スケジューラのイベント ログを確認してください。
/IT を指定しない場合は、バッチ処理として正常に登録されてすぐに処理がスケジュールされますが、/IT を指定した場合は処理そのものが実行されずに『不思議な待機状態』になっています。 そこで、ユーザにログオンしている時のみ実行するに変更 そうすると、スケジュールどおりに実行を開始します。 但し、この登録では /SC MINUTE で『1分ごとに無期限に繰り返す』ので、1分後に再びコマンドプロンプトを開こうとするのですが、前のタスクが終わって無い場合はコマンドプロンプトは開きません つまり、このタスクは『1分毎にチェックして、もしコマンドプロンプトが無かったらコマンドプロンプトを開く』というタスクになった事になります open_cmd.bat
cd \ & cd %temp% & cmd /k
いずれにしても、削除は UI ( ファイル名を指定して実行から taskschd.msc ) から行うといいですし、登録だけ /IT でコマンドでしておいて、後から UI で適宜変更するといいと思います。
posted by lightbox at 2018-06-09 20:47 | Windows10 | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり

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

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり