様々な基本になるサンプルを記録しています。

不定期更新です。

記事のサイドに使用している商品の紹介も掲載しているので、良ければご覧ください。

【ORACLE】正規表現

正規表現でのチェックは、正規表現自体を理解していれば 非常に有用且つ開発が楽になる。
ただ、基本的にはサーバーサイドで使用することは あんまり良くない。
その理由として、
バックトラッキング(文字のチェック等が構文によって最初からやり直されること)の影響が計りしれないため、
サーバーサイドのボトルネックを増やすことになるのと、原因がつかみにくくなる。

そこを考えた上で、簡単なものであれば使ってもよさそうだ。

というわけでPL/SQLでの例
0から9の整数であれば、数値とみなすチェック。


SET SERVEROUTPUT ON 
DECLARE 

TYPE STR_TYPE IS TABLE OF VARCHAR(2000); 
STR_ARRY STR_TYPE; 

BEGIN 

STR_ARRY :=STR_TYPE(); 
STR_ARRY.EXTEND; 

STR_ARRY(STR_ARRY.COUNT) := 'AAAAA'; 

STR_ARRY.EXTEND; 
STR_ARRY(STR_ARRY.COUNT) := 'BBBBB'; 


STR_ARRY.EXTEND; 
STR_ARRY(STR_ARRY.COUNT) := '1234'; 


STR_ARRY.EXTEND; 
STR_ARRY(STR_ARRY.COUNT) := '5679'; 


FOR I IN 1..STR_ARRY.COUNT 
LOOP 
 /*数字かチェックする*/ 
      IF REGEXP_LIKE(STR_ARRY(I),'^[0-9]+$') THEN 

         DBMS_OUTPUT.PUT_LINE(TO_CHAR(I) || '番目は数値だよ'); 

      END IF; 
       
END LOOP 


RETURN; 

END;

日付チェックとかは、日付型を利用したほうが早いので
フォーマットが確実に決まっているのであれば、
それに対して限定的に使うというのが一番良いかもしれない。

【ORACLE】エラーコードの割り当て

RAISE_APPLICATION_ERRORという関数を使えば、
エラーコードの割り当てとメッセージを指定することができる。
ただし、ユーザー定義のエラーとして使用が許可されている番号は -20000〜-20999 までの 1000 コード分らしい。
トリガーで例外エラーとして処理する場合とか役に立ちそうな気がする。

CREATE OR REPLACE TRIGGER SAMPLE_TRG
BEFORE INSERT ON TABLE1
FOR EACH ROW
BEGIN
  
    RAISE_APPLICATION_ERROR(-20001, 'TABLE1のデータ追加は認めていません。' );
     
END ;
/

フロントエンド開発とかでよく定義するイベントハンドラをイメージすると
個人的にはかなりいろいろなことができるような気がしている。

サーバーサービスの機能をしっかり使っていかないと、
宝の持ち腐れになるので、もったいない感じがする。

これ以外にもきっとまだ知られていないものがあるのだろう。

【Oracle】複合トリガー

Oracle11gからの新しい機能。
基本的に行トリガーは自分自身のレコードを更新することはできない。
でも、複合トリガーを使うとそんなことができてしまったりする。
これは便利ではあるが、開発では非機能要件をしっかり考慮しておかないと
運用でかなり危ない状況に陥る可能性があるので、慎重に使わなければならないもの。

とりあえず、簡単なものを作ってみる。

毎度のことだが、テーブルの構成は以下の記事にある。
fubukin.hatenablog.com

サンプルで作ってるテーブルの主キーの設定はここの記事の最後くらいにある。
fubukin.hatenablog.com


そして、事前準備として
シーケンスを作っておく

CREATE SEQUENCE "TEST_SEQ" MINVALUE 1 MAXVALUE 9999999999999999999999999999 
 INCREMENT BY 1 START WITH 6060 CACHE 20 NOORDER NOCYCLE;

複合トリガーの作成。
トリガーの起動順序は
1.BEFORE行トリガー
2.BEFORE文トリガー
3.AFTER行トリガー
4.AFTER文トリガー

CREATE OR REPLACE TRIGGER  TEST_INSERT_COMPOUND
FOR  INSERT  ON TABLE1
/*****************************************************************/
-- 共通の宣言のセクション
/*****************************************************************/
COMPOUND  TRIGGER
    /*共通の宣言部(共通の変数などを宣言する)*/
    
 /*テーブル配列定義*/   
 TYPE TABLE1_TYPE IS TABLE OF TABLE1%ROWTYPE;
 TABLE1_REC TABLE1_TYPE :=TABLE1_TYPE();

/*****************************************************************/
-- BEFOREの行のセクション
/*****************************************************************/
BEFORE  EACH ROW  IS
BEGIN

    /*配列拡張*/
    TABLE1_REC.EXTEND;

    /*シーケンス番号を自動で入れる*/
    :NEW.A1 :=  TEST_SEQ.NEXTVAL;
    TABLE1_REC(TABLE1_REC.COUNT).A1 := :NEW.A1;

END  BEFORE  EACH ROW;
/*****************************************************************/
-- BEFOREの文のセクション
/*****************************************************************/
/*
BEFORE  STATEMENT IS
BEGIN
END  BEFORE STATEMENT;
*/
/*****************************************************************/
-- AFTERの行のセクション
/*****************************************************************/
/*
AFTER  EACH ROW  IS
BEGIN
END  AFTER EACH ROW;
*/
/*****************************************************************/
-- AFTERの文のセクション
/*****************************************************************/
AFTER  STATEMENT IS
BEGIN

    /*値の更新*/
    FOR I IN 1..TABLE1_REC.COUNT
    LOOP

       UPDATE TABLE1
       SET A2  = TO_CHAR(I)
          ,A3  = TO_CHAR(SYSDATE,'YYYYMMDD')
          ,A4  = TO_CHAR(SYSDATE,'HH24MISS')
          ,A5  = ' '
          ,A6  = ' '
          ,A7  = ' '
          ,A8  = ' '
          ,A9  = ' '
          ,A10 = ' '
          ,A11 = ' '
          ,A12 = ' '
       WHERE
          A1 = TABLE1_REC(I).A1;
    END LOOP;
    TABLE1_REC.DELETE;

END  AFTER STATEMENT;
/*****************************************************************/
-- 終わりのEND;
/*****************************************************************/
END  TEST_INSERT_COMPOUND;

何も入れない全てNULLになるINSERT文を実行
f:id:karinto441:20181015001017p:plain


そして結果を見ると、対象に値が入っている。
f:id:karinto441:20181015001132p:plain


非機能要件制約さえ決めておけば、この使い道は結構あると思うんだけどな。

【ASP.NET】サーバーコントロールをHTMLとしてレスポンスで返す

AndroidiOSの開発を行っていた時に、
どんな端末でも使えるようにというコンセプトで
WEBブラウザを使用してアプリケーション開発を行ったことがあった。

スマートフォンがまだ普及していなくて
ちょうど、iPadが話題になってたときだった。

そのときに開発言語がバラバラになるのを恐れて、
調査して実装したのがWEBサービスAJAXを使用して、
フロントエンド開発もバックエンド開発もやれるように考えて
出てきたのがこれ。

サーバーコントロールをうまく使えば
ポストバックを回避できるので、どんな端末でもほとんど対応できる。

Google系のブラウザやSafariを扱うときは、オープンソースJqueryを使っていくと
Javascriptの構文の違いに悩まされることは、ほぼ無いのではないかと思う。

とりあえず、Visual StudioでWEBアプリケーションの新規プロジェクトを起こして
以下のソースをコピーしてやってみると、何か見えるかもしれない。
Default.aspx.vb

Imports System.IO
Imports System.Web.UI
Partial Public Class _Default
    Inherits System.Web.UI.Page
    'ロードイベントは必ず通ります。
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Select Case Request.Form("load")



            Case "Button1"

                Grid_View()

            Case Else

        End Select



    End Sub
    Public Sub Grid_View()

        'オブジェクトの定義はWEB画面で配置するより、中で定義して貼り付けたほうが環境に依存することがないです。
        'ここではGridViewコントロールをHTMLとして出力します。
        Dim dgv As New GridView

        'HTMLを吐き出すために以下のクラスを使います。
        Dim strw As New StringWriter()
        Dim wt As New System.Web.UI.HtmlTextWriter(strw)


        'サンプルでデータテーブルを作り、適当にデータを入れています。
        Dim dt As New DataTable
        Dim dr As DataRow


        dt.Columns.Add("項目1")
        dt.Columns.Add("項目2")
        dt.Columns.Add("項目3")
        dt.Columns.Add("項目4")

        For i As Integer = 0 To 50



            dr = dt.NewRow


            dr(0) = "データA" & CStr(i)
            dr(1) = "データB" & CStr(i)
            dr(2) = "データC" & CStr(i)
            dr(3) = "データD" & CStr(i)

            dt.Rows.Add(dr)


        Next

        'GridViewのデータバインドメソッドです。
        dgv.DataSource = dt

        'このメソッドを実行しないと、
        'データソースにデータ定義を関連付けしても反映されません。
        dgv.DataBind()

        'クライアントに返すレスポンスを初期化します。
        Response.Clear()

        'GridViewのレンダー(実際にWEBで記述されるHTMLの内容)を
        'ここでTextWriterに出力します
        dgv.RenderControl(wt)

        'レスポンスに出力します
        Response.Write(strw.ToString)


        '以下、リソースの開放です。必ずレスポンスを終わらせる場合は開放してから、
        'Response.Endしてください。
        wt.Close()
        strw.Close()

        wt.Dispose()
        strw.Dispose()
        dt.Clear()
        dt.Dispose()
        dgv.Dispose()

        'レスポンス終了
        Response.End()

    End Sub

End Class

Default.aspx

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplication1._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">

    <script src="js_XMLHTTPRequest.js" type="text/javascript" ></script>
    
    <script language="JavaScript">
	<!--
	
	    //GridViewの表示
	    function button_clk(){

			document.getElementById('test').innerHTML = HTTPXMLREQ('Default.aspx','load=Button1&test=12');
		}
		
	//-->
	</script>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
     
     <div id="test">
     
     
     
     </div>
     
   <p>
    <input id="Button1" type="button" value="button" onclick='button_clk();' /></p>
   
   
   
    </form>
</body>
</html>

js_XMLHTTPRequest.js

var xhr
var Restxt
// ------------------------------------------------------------
// XMLHttpRequest オブジェクトを作成する関数
// ------------------------------------------------------------
function XMLHttpRequestCreate() {
    try {
        return new XMLHttpRequest();
    } catch (e) { }
    try {
        return new ActiveXObject('MSXML2.XMLHTTP.6.0');
    } catch (e) { }
    try {
        return new ActiveXObject('MSXML2.XMLHTTP.3.0');
    } catch (e) { }
    try {
        return new ActiveXObject('MSXML2.XMLHTTP');
    } catch (e) { }

    return null;
}

function HTTPXMLREQ(url, send_data) {

    Restxt = "";
    // ------------------------------------------------------------
    // XMLHttpRequest オブジェクトを作成
    // ------------------------------------------------------------
    xhr = XMLHttpRequestCreate();

    // ------------------------------------------------------------
    // XHR 通信の状態が変化するたびに実行されるイベント
    // ------------------------------------------------------------
    xhr.onreadystatechange = ResponseData

    // ------------------------------------------------------------
    // 「POST メソッド」「接続先 URL」を指定
    // ------------------------------------------------------------
    xhr.open("POST",url,false);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    // ------------------------------------------------------------
    // 「送信データ」を指定、XHR 通信を開始する
    // ------------------------------------------------------------
    xhr.send(send_data);

    return Restxt
}

function ResponseData() {

    switch (xhr.readyState) {
        case 4:
            // ------------------------------------------------------------
            // XHR 通信失敗
            // ------------------------------------------------------------
            if (xhr.status == 0) {

                alert("XHR 通信に失敗しました。");
                
                // ------------------------------------------------------------
                // XHR 通信成功
                // ------------------------------------------------------------
            } else {

                // ------------------------------------------------------------
                // リクエスト成功
                // ------------------------------------------------------------
                if ((200 <= xhr.status && xhr.status < 300) || (xhr.status == 304)) {
                Restxt = xhr.responseText;
                    

                    // ------------------------------------------------------------
                    // リクエスト失敗
                    // ------------------------------------------------------------
                } else {

                    alert(xhr.status);

                }
            }
            break;
    }
};

【Oracle】ネイティブコンパイル

サーバーのメモリを消費する分、
30%くらい処理速度が向上するらしい。

サーバーのスケールアップを考えた上で、
考慮したいところ。

/*常にネイティブコンパイルを行うように設定を変更する*/
ALTER SYSTEM SET PLSQL_CODE_TYPE = NATIVE;
/


/*以下、限定的にネイティブコンパイルを行う*/
ALTER PACKAGE SYS.UTL_FILE COMPILE PLSQL_CODE_TYPE = NATIVE;
/
ALTER PACKAGE SYS.DBMS_STATS COMPILE PLSQL_CODE_TYPE = NATIVE;
/
ALTER PACKAGE SYS.DBMS_SQL COMPILE PLSQL_CODE_TYPE = NATIVE;

SYSにあるパッケージはネイティブで動かした方が得がありそうな気がする。

【Oracle】DBセッション確認

接続セッションの状態を確認するSQL
ACTIVEセッションが一つ増えるけど、実行している自分になるので気にしないでおこう

SELECT
    TO_CHAR(SYSDATE,'yyyy/mm/dd HH24:MI:SS'),
    S.STATUS,
    S.USERNAME,
    NVL(S.SQL_EXEC_START,S.PREV_EXEC_START),
    S.LAST_CALL_ET,
    ROUND(
        CASE
            WHEN
                Q.EXECUTIONS > 0
            THEN
                Q.CPU_TIME / Q.EXECUTIONS / 1000
            ELSE
                0
        END,2)
FROM
    V$SESSION S,
    V$SQLSTATS Q
WHERE
    S.USER# <> 0 AND
    Q.SQL_ID (+)   = NVL(S.SQL_ID,S.PREV_SQL_ID)
ORDER BY
    CASE
        STATUS
        WHEN
            'ACTIVE'
        THEN
            1
        WHEN
            'INACTIVE'
        THEN
            2
        ELSE
            9
    END,
    CASE
            WHEN
                Q.EXECUTIONS > 0
            THEN
                Q.CPU_TIME / Q.EXECUTIONS
            ELSE
                0
        END
    DESC;