0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShell SQLPlus Select結果(複数行)をいい感じで受け取る

Last updated at Posted at 2024-05-08

ニッチすぎる。

ODBCとかOracleClientとかそっち使えよって感じだけど
業務上PowerShell+SQLPLusじゃないとダメって人向け。

Hoge.ps1
# チェック
if(!$ENV:Path.Contains("C:\Oracle\bin")){
    $ENV:Path+=";C:\Oracle\bin"
    echo "ADD PATH"
}

# SQL*Plusを使用してSQLファイルを実行し、結果を受け取る
$sqlPlusOutput = @"
set heading on
set underline off
set termout off 
set feedback off 
set colsep ,
set lines 9999
set trimspool on 
set trimout on 
set tab off 
SET RECSEP OFF

select * from TABLE1 WHERE COLUMN1 in ('11','21');
"@

$command = @"
echo '$sqlPlusOutput' | sqlplus -S -L 'sys/Oradoc_db1@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(Host=localhost)(Port=1521))(CONNECT_DATA=(SID=ORCLCDB)))' as sysdba 
"@

$table = (Invoke-Expression -Command $command)

if($table | Out-String -Stream | ?{$_.Contains('ORA-') -or $_.Contains('SP2-')}) {
    echo $table 
    exit 1
}

$data = @()
$Header = @()
foreach($row in $table[1].Split(",")){
    $Header += $row.Trim()
}
for ($i = 2; $i -lt $table.Length; $i++) {
    $rowData = @{}
    for ($j = 0; $j -lt $Header.Length; $j++) {
        $columnName = $Header[$j]
        $rowData[$columnName] = ($table[$i].Split(","))[$j].Trim()
    }
    $data += $rowData
}

echo $data[1].COLUMN4
batcher.bat
@echo off

REM 引数チェック
if "%~1"=="" (
    echo Usage: executeBat.bat 100
    exit 11
)

SET script_path=C:\IF\powershell.ps1
if not exist "%script_path%" (
    echo スクリプトが見つかりません: %script_path%
    exit 1
)

powershell -ExecutionPolicy Bypass -File "%script_path%" %~1
set powershell_exit_code=%errorlevel%
if %powershell_exit_code% equ 0 (
    echo PowerShell スクリプトは正常に終了しました。 管理番号[%~1]
) else (
    echo PowerShell スクリプトはエラーで終了しました。管理番号[%~1] エラーコード: %powershell_exit_code% 
)
exit %powershell_exit_code%

exec.sql
DECLARE
  v_table_name   VARCHAR2(100) := '&table_name';-- テーブル名をパラメータとして指定
  v_execute_sql  VARCHAR(200);      -- 実行するSQLを格納
  v_cursor       PLS_INTEGER;       -- カーソルを定義
  v_column_count INTEGER;           -- 列数を格納する変数
  v_column_desc  dbms_sql.desc_tab; -- 列の情報を格納する配列
  v_column_name  VARCHAR2(100);      -- 列名を格納する変数
  v_column_value VARCHAR2(4000);    -- 列の値を格納する変数、適宜サイズを調整
  v_pre_count    VARCHAR2(100);     -- pre件数を取得する
  v_pre_sql      VARCHAR2(200);      -- pre実行するSQLを格納
BEGIN
  -- カーソルを開く
  v_cursor := dbms_sql.open_cursor;
  
  -- SQLの準備
  v_execute_sql := 'SELECT * FROM ' || v_table_name;
  v_pre_sql     := 'SELECT count(*) FROM ' || v_table_name;
  -- SQL文を解析する
  dbms_sql.parse(v_cursor, v_execute_sql, dbms_sql.native);

  -- 列の情報を取得する
  dbms_sql.describe_columns(v_cursor, v_column_count, v_column_desc);

  -- 行数と、列数を出力する
  EXECUTE IMMEDIATE v_pre_sql into v_pre_count;
  DBMS_OUTPUT.PUT_LINE(v_pre_count||','||v_column_count);

  -- 各列について処理を行う
  FOR i IN 1..v_column_count LOOP
    -- 列名を取得
    v_column_name := v_column_desc(i).col_name;
    -- 列の値を定義
    dbms_sql.define_column(v_cursor, i, v_column_value, 4000);
  END LOOP;

  -- 実行結果をバインドする
  dbms_sql.define_column(v_cursor, 1, v_column_value, 4000);

  -- SQL文を実行する
  IF dbms_sql.execute(v_cursor) = 0 THEN
    -- 結果を取得する
    LOOP
      EXIT WHEN dbms_sql.fetch_rows(v_cursor) = 0;
      FOR i IN 1..v_column_count LOOP
        -- 列の値を取得
        dbms_sql.column_value(v_cursor, i, v_column_value);
        -- 結果を出力
        DBMS_OUTPUT.PUT_LINE(v_column_desc(i).col_name || ',' || v_column_value);
      END LOOP;
    END LOOP;
  END IF;

  -- カーソルを閉じる
  dbms_sql.close_cursor(v_cursor);
END;
/
psooo.ps1
Set-StrictMode -Version 3.0
$BATCH_RESULT = [ordered]@{
    SUCC =  0; # 成功
    ERR  = -1; # エラー
}
$PLSQL_RESULT = [ordered]@{ 
    SUCC = 0; # 成功
    ERR  = 1; # エラー
    PERR = 2; # 一部エラー
    WARN = 3; # 警告
}
$EXE_STATE = [ordered]@{
    RUN  = 0; # 実行中
    WAIT = 1; # 待機中
}
$resultValue = $PLSQL_RESULT.ERR;
Write-Host  $($PLSQL_RESULT.WARN) 
if($resultValue -eq $PLSQL_RESULT.ERR) {
   Write-Host "result_VAlue is err"
}
$key = ($EXE_STATE.GetEnumerator() | Where-Object { $_.Value -eq  $resultValue }).Key
Write-Host $key

$($BATCH_RESULT | Out-String -Stream | %{ $_ -replace "\s+$" ,''} )
$($PLSQL_RESULT | Out-String -Stream | %{ $_ -replace "\s+$" ,''} )
solo.ps1

# 関数の呼び出しを別プロセスとして実行
$to = "recipient@example.com"
$from = "sender@example.com"
$subject = "Test Email"
$body = "This is a test email sent from PowerShell."
$smtpServer = "smtp.example.com"
$port = 587
$username = "your_smtp_username"
$password = "your_smtp_password"

$job = Start-Job -ScriptBlock {
    param (
        $To, $From, $Subject, $Body, $SmtpServer, $Port, $Username, $Password
    )
    # 関数の再定義
    function Send-Email {
        param (
            [string]$To,
            [string]$From,
            [string]$Subject,
            [string]$Body,
            [string]$SmtpServer,
            [int]$Port = 25,
            [string]$Username,
            [string]$Password
        )

        try {
            # Send-MailMessage コマンドレットを使用してメールを送信
            Send-MailMessage -To $To -From $From -Subject $Subject -Body $Body -SmtpServer $SmtpServer -Port $Port -ErrorAction Stop
            
            # 正常終了の場合の終了コード
            return 0
        }
        catch {
            # エラーメッセージを表示
            Write-Error "Errorです.$PID $_"

            # 異常終了の場合の終了コード
            return 1
        }
    }

    # 関数の呼び出し
    Send-Email -To $To -From $From -Subject $Subject -Body $Body -SmtpServer $SmtpServer -Port $Port -Username $Username -Password $Password
} -ArgumentList $to, $from, $subject, $body, $smtpServer, $port, $username, $password

try {
    # ジョブの終了を待機して結果を表示
    $job | Wait-Job >> $null

    # 終了コードを取得
    $jobResult = $job | Receive-Job
    if ($jobResult -eq 0) {
        Write-Output "メール送信が正常に完了しました。"
    } else {
        Write-Output "メール送信中にエラーが発生しました。"
    }
}catch {
    Write-Host "$PID OK__ $_ "
} finally {
    # ジョブの削除
    Remove-Job -Job $job
}

debugcursor.sql
DECLARE
    TYPE ref_cursor IS REF CURSOR;
    c ref_cursor;
    l_sql VARCHAR2(32767) := 'SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM emp'; -- 可変SQL
    l_column_value VARCHAR2(4000);
    l_column_name VARCHAR2(4000);
    l_column_list DBMS_SQL.desc_tab2;
    l_cursor INTEGER;
    l_dummy INTEGER;

    PROCEDURE debug_dynamic_cursor(p_cursor IN ref_cursor) IS
        l_col_cnt INTEGER;
        l_desc DBMS_SQL.desc_tab2;
        l_col_name VARCHAR2(1000);
        l_col_type NUMBER;
        l_rowid ROWID;
        l_value VARCHAR2(4000);
    BEGIN
        l_cursor := DBMS_SQL.TO_CURSOR_NUMBER(p_cursor);
        DBMS_SQL.describe_columns2(l_cursor, l_col_cnt, l_desc);
        
        FOR i IN 1 .. l_col_cnt LOOP
            l_col_name := l_desc(i).col_name;
            l_col_type := l_desc(i).col_type;

            DBMS_SQL.DEFINE_COLUMN(l_cursor, i, l_value, 4000);

            CASE l_col_type
                WHEN 1 THEN
                    DBMS_SQL.DEFINE_COLUMN(l_cursor, i, l_value, 4000); -- VARCHAR2
                WHEN 2 THEN
                    DBMS_SQL.DEFINE_COLUMN(l_cursor, i, l_value, 4000); -- NUMBER
                WHEN 12 THEN
                    DBMS_SQL.DEFINE_COLUMN(l_cursor, i, l_value, 4000); -- DATE
                ELSE
                    DBMS_SQL.DEFINE_COLUMN(l_cursor, i, l_value, 4000); -- その他の型
            END CASE;
        END LOOP;

        IF DBMS_SQL.FETCH_ROWS(l_cursor) > 0 THEN
            FOR i IN 1 .. l_col_cnt LOOP
                DBMS_SQL.COLUMN_VALUE(l_cursor, i, l_value);
                DBMS_OUTPUT.PUT_LINE(l_desc(i).col_name || ': ' || l_value);
            END LOOP;
        END IF;
        
        DBMS_SQL.CLOSE_CURSOR(l_cursor);
    END debug_dynamic_cursor;

BEGIN
    -- 動的SQLを開く
    OPEN c FOR l_sql;
    -- デバッグ用プロシージャを呼び出し
    debug_dynamic_cursor(c);
    -- カーソルを閉じる
    CLOSE c;
END;
/
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?