20200721のMySQLに関する記事は6件です。

PHP-MySQLi-Database-Classの解説 日本語訳

MysqliDb -- MySQLi のシンプルなラッパーの解説日本語訳

PHP-MySQLi-Database-Classは日本ではあまり知られていませんが、
githubでは☆2800スターを集めて世界中の人に使われているものとなります。

本家githubはこちらから
https://github.com/ThingEngineer/PHP-MySQLi-Database-Class

利用方法

このクラスを利用するには、まずMysqliDb.phpをプロジェクトにインポート。

require_once ('MysqliDb.php');

composerでの利用方法

composer経由でライブラリをインストールすることも可能です。

composer require thingengineer/mysqli-database-class:dev-master

初期化 (initialization)

デフォルトではutf8のcharsetが設定されているので、簡単な初期化が可能です。
$db = new MysqliDb ('host', 'username', 'password', 'databaseName');

高度な初期化

$db = new MysqliDb (Array (
                'host' => 'host',
                'username' => 'username', 
                'password' => 'password',
                'db'=> 'databaseName',
                'port' => 3306,
                'prefix' => 'my_',
                'charset' => 'utf8'));

テーブルの接頭辞、ポート、データベースのcharsetパラメータはオプションです。
charsetを設定すべきでない場合は、nullに設定します。
また、すでに接続されている mysqli オブジェクトを再利用することも可能です。

$mysqli = new mysqli ('host', 'username', 'password', 'databaseName');
$db = new MysqliDb ($mysqli);

オブジェクトの作成時にテーブルのプレフィックスが設定されていなかった場合は、
後から別の呼び出しでテーブルのプレフィックスを設定することができます。

$db->setPrefix ('my_');

mysqlへの接続が切断される場合、Mysqlidbは自動的に一度データベースに再接続しようとします。
この動作を無効にするには以下のようにしてください。

$db->autoReconnect = false;

すでに作成された mysqliDb オブジェクトを別のクラスや関数から取得する場合は以下のように設定します。

    function init () {
        // db staying private here
        $db = new MysqliDb ('host', 'username', 'password', 'databaseName');
    }
    function myfunc () {
        // obtain db object created in init  ()
        $db = MysqliDb::getInstance();
        ...
    }

複数のデータベース接続

複数のデータベースに接続する必要がある場合は、以下の方法で使用してください。

$db->addConnection('slave', Array (
                'host' => 'host',
                'username' => 'username',
                'password' => 'password',
                'db'=> 'databaseName',
                'port' => 3306,
                'prefix' => 'my_',
                'charset' => 'utf8')
);

データベースを選択するには connection() メソッドを使用します。

$users = $db->connection('slave')->get('users');

オブジェクトのマッピング

dbObject.php は、モデル表現機能を提供するために mysqliDb の上に構築されたオブジェクトマッピングライブラリです。

挿入クエリ(Insert Query)

簡単な例

$data = Array ("login" => "admin",
               "firstName" => "John",
               "lastName" => 'Doe'
);
$id = $db->insert ('users', $data);
if($id)
    echo 'user was created. Id=' . $id;

fuunction挿入

$data = Array (
    'login' => 'admin',
    'active' => true,
    'firstName' => 'John',
    'lastName' => 'Doe',
    'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")),
    // password = SHA1('secretpassword+salt')
    'createdAt' => $db->now(),
    // createdAt = NOW()
    'expires' => $db->now('+1Y')
    // expires = NOW() + interval 1 year
    // Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear
);

$id = $db->insert ('users', $data);
if ($id)
    echo 'user was created. Id=' . $id;
else
    echo 'insert failed: ' . $db->getLastError();

INSERT ... ON DUPLICATE KEY UPDATE 構文

$data = Array ("login" => "admin",
               "firstName" => "John",
               "lastName" => 'Doe',
               "createdAt" => $db->now(),
               "updatedAt" => $db->now(),
);
$updateColumns = Array ("updatedAt");
$lastInsertId = "id";
$db->onDuplicate($updateColumns, $lastInsertId);
$id = $db->insert ('users', $data);

複数のデータセットを一度に挿入

$data = Array(
    Array ("login" => "admin",
        "firstName" => "John",
        "lastName" => 'Doe'
    ),
    Array ("login" => "other",
        "firstName" => "Another",
        "lastName" => 'User',
        "password" => "very_cool_hash"
    )
);
$ids = $db->insertMulti('users', $data);
if(!$ids) {
    echo 'insert failed: ' . $db->getLastError();
} else {
    echo 'new users inserted with following id\'s: ' . implode(', ', $ids);
}

すべてのデータセットが同じキーしか持たない場合は、単純化することができます。

$data = Array(
    Array ("admin", "John", "Doe"),
    Array ("other", "Another", "User")
);
$keys = Array("login", "firstName", "lastName");

$ids = $db->insertMulti('users', $data, $keys);
if(!$ids) {
    echo 'insert failed: ' . $db->getLastError();
} else {
    echo 'new users inserted with following id\'s: ' . implode(', ', $ids);
}

データ置換(REPLACE文)

Replace() メソッドは insert() と同じ API を実装しています。

データを更新する(UPDATE文)

$data = Array (
    'firstName' => 'Bobby',
    'lastName' => 'Tables',
    'editCount' => $db->inc(2),
    // editCount = editCount + 2;
    'active' => $db->not()
    // active = !active;
);
$db->where ('id', 1);
if ($db->update ('users', $data))
    echo $db->count . ' records were updated';
else
    echo 'update failed: ' . $db->getLastError();

update() はリミットパラメータもサポートしています。
php:
$db->update ('users', $data, 10);
// Gives: UPDATE users SET ... LIMIT 10

データを取得する(SELECT文)

セレクト/ゲット関数が呼び出された後、金額または返された行は$count変数に格納されます。

$users = $db->get('users'); //contains an Array of all users 
$users = $db->get('users', 10); //contains an Array 10 users

またはカスタムカラムを設定して選択します。関数を使用することもできます。

$cols = Array ("id", "name", "email");
$users = $db->get ("users", null, $cols);
if ($db->count > 0)
    foreach ($users as $user) { 
        print_r ($user);
    }

一行だけを選択する

$db->where ("id", 1);
$user = $db->getOne ("users");
echo $user['id'];

$stats = $db->getOne ("users", "sum(id), count(*) as cnt");
echo "total ".$stats['cnt']. "users found";

1つの列の値または関数の結果を選択

$count = $db->getValue ("users", "count(*)");
echo "{$count} users found";

複数の行から1つの列の値または関数の結果を選択

$logins = $db->getValue ("users", "login", null);
// select login from users
$logins = $db->getValue ("users", "login", 5);
// select login from users limit 5
foreach ($logins as $login)
    echo $login;

データを追加する(INSERT文)

また、特定のテーブルに .CSV または .XML データを読み込むこともできます。
.csv データを挿入するには、以下の構文を使用します。

$path_to_file = "/home/john/file.csv";
$db->loadData("users", $path_to_file);

これは、/home/john/ (johnのホームディレクトリ)フォルダにfile.csvという.csvファイルをロードします。
オプションでオプションの配列を添付することもできます。有効なオプションは以下の通りです。

Array(
    "fieldChar" => ';',     // Char which separates the data
    "lineChar" => '\r\n',   // Char which separates the lines
    "linesToIgnore" => 1    // Amount of lines to ignore at the beginning of the import
);

Attach

$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1);
$db->loadData("users", "/home/john/file.csv", $options);
// LOAD DATA ...

DATAの代わりにLOCAL DATAを使用するように指定

$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1, "loadDataLocal" => true);
$db->loadData("users", "/home/john/file.csv", $options);
// LOAD DATA LOCAL ...

XML挿入

XML データをテーブルにロードするには、loadXML メソッドを使用します。構文は loadData 構文と同じです。

$path_to_file = "/home/john/file.xml";
$db->loadXML("users", $path_to_file);

オプションのパラメータを追加

Array(
    "linesToIgnore" => 0,       // Amount of lines / rows to ignore at the beginning of the import
    "rowTag"    => "<user>" // The tag which marks the beginning of an entry
)

使用例

$options = Array("linesToIgnore" => 0, "rowTag" => "<user>"):
$path_to_file = "/home/john/file.xml";
$db->loadXML("users", $path_to_file, $options);

ページネーション(Pagination)

ページ分割された結果を取得するには get() の代わりに paginate() を使用します。

$page = 1;
// set page limit to 2 results per page. 20 by default
$db->pageLimit = 2;
$products = $db->arraybuilder()->paginate("products", $page);
echo "showing $page out of " . $db->totalPages;

MAP

純粋な配列で結果を取得するのではなく、必要なキーを含む連想配列で結果を取得することも可能です。get() で取得するフィールドが 2 つだけの場合は配列($k => $v)で、それ以外の場合は配列 ($k => 配列 ($v, $v)) で結果を返します。

$user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'login, id');
Array
(
    [user1] => 1
)

$user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'id,login,createdAt');
Array
(
    [user1] => stdClass Object
        (
            [id] => 1
            [login] => user1
            [createdAt] => 2015-10-22 22:27:53
        )

)

リターン型の定義

MysqliDbは、3つの異なるフォーマットで結果を返すことができます。配列の配列、オブジェクトの配列、Json文字列です。返り値の型を選択するには、ArrayBuilder()、ObjectBuilder()、JsonBuilder()メソッドを使用します。ArrayBuilder() はデフォルトの戻り値の型であることに注意してください。

// Array return type
$= $db->getOne("users");
echo $u['login'];
// Object return type
$u = $db->ObjectBuilder()->getOne("users");
echo $u->login;
// Json return type
$json = $db->JsonBuilder()->getOne("users");

生のSQLクエリの実行

$users = $db->rawQuery('SELECT * from users where id >= ?', Array (10));
foreach ($users as $user) {
    print_r ($user);
}

長いifチェックを避けるために、生のクエリの選択結果を扱うためのヘルパー関数があります。
結果の1行を取得します。

$user = $db->rawQueryOne ('select * from users where id=?', Array(10));
echo $user['login'];
// Object return type
$user = $db->ObjectBuilder()->rawQueryOne ('select * from users where id=?', Array(10));
echo $user->login;

1カラムの値を文字列として取得

$password = $db->rawQueryValue ('select password from users where id=? limit 1', Array(10).
echo "パスワードは {$password} です。
注意: rawQueryValue() が配列ではなく文字列を返すようにするには、 クエリの最後に 'limit 1' を追加しなければなりません。

複数の行から1列の値を取得します。

$logins = $db->rawQueryValue ('select login from users limit 10');
foreach ($logins as $login)
    echo $login;

応用例

$params = Array(1, 'admin');
$users = $db->rawQuery("SELECT id, firstName, lastName FROM users WHERE id = ? AND login = ?", $params);
print_r($users); // contains Array of returned rows

// will handle any SQL query
$params = Array(10, 1, 10, 11, 2, 10);
$q = "(
    SELECT a FROM t1
        WHERE a = ? AND B = ?
        ORDER BY a LIMIT ?
) UNION (
    SELECT a FROM t2 
        WHERE a = ? AND B = ?
        ORDER BY a LIMIT ?
)";
$results = $db->rawQuery ($q, $params);
print_r ($results); // contains Array of returned rows
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP-MySQLi-Database-Classの解説

MysqliDb -- MySQLi のシンプルなラッパーの解説 日本語訳

PHP-MySQLi-Database-Classは日本ではあまり知られていませんが、
githubでは☆2800スターを集めて世界中の人に使われているものとなります。

本家githubはこちらから
https://github.com/ThingEngineer/PHP-MySQLi-Database-Class

利用方法

このクラスを利用するには、まずMysqliDb.phpをプロジェクトにインポート。

require_once ('MysqliDb.php');

composerでの利用方法

composer経由でライブラリをインストールすることも可能です。

composer require thingengineer/mysqli-database-class:dev-master

初期化 (initialization)

デフォルトではutf8のcharsetが設定されているので、簡単な初期化が可能です。
$db = new MysqliDb ('host', 'username', 'password', 'databaseName');

高度な初期化

$db = new MysqliDb (Array (
                'host' => 'host',
                'username' => 'username', 
                'password' => 'password',
                'db'=> 'databaseName',
                'port' => 3306,
                'prefix' => 'my_',
                'charset' => 'utf8'));

テーブルの接頭辞、ポート、データベースのcharsetパラメータはオプションです。
charsetを設定すべきでない場合は、nullに設定します。
また、すでに接続されている mysqli オブジェクトを再利用することも可能です。

$mysqli = new mysqli ('host', 'username', 'password', 'databaseName');
$db = new MysqliDb ($mysqli);

オブジェクトの作成時にテーブルのプレフィックスが設定されていなかった場合は、
後から別の呼び出しでテーブルのプレフィックスを設定することができます。

$db->setPrefix ('my_');

mysqlへの接続が切断される場合、Mysqlidbは自動的に一度データベースに再接続しようとします。
この動作を無効にするには以下のようにしてください。

$db->autoReconnect = false;

すでに作成された mysqliDb オブジェクトを別のクラスや関数から取得する場合は以下のように設定します。

    function init () {
        // db staying private here
        $db = new MysqliDb ('host', 'username', 'password', 'databaseName');
    }
    function myfunc () {
        // obtain db object created in init  ()
        $db = MysqliDb::getInstance();
        ...
    }

複数のデータベース接続

複数のデータベースに接続する必要がある場合は、以下の方法で使用してください。

$db->addConnection('slave', Array (
                'host' => 'host',
                'username' => 'username',
                'password' => 'password',
                'db'=> 'databaseName',
                'port' => 3306,
                'prefix' => 'my_',
                'charset' => 'utf8')
);

データベースを選択するには connection() メソッドを使用します。

$users = $db->connection('slave')->get('users');

オブジェクトのマッピング

dbObject.php は、モデル表現機能を提供するために mysqliDb の上に構築されたオブジェクトマッピングライブラリです。

挿入クエリ(Insert Query)

簡単な例

$data = Array ("login" => "admin",
               "firstName" => "John",
               "lastName" => 'Doe'
);
$id = $db->insert ('users', $data);
if($id)
    echo 'user was created. Id=' . $id;

fuunction挿入

$data = Array (
    'login' => 'admin',
    'active' => true,
    'firstName' => 'John',
    'lastName' => 'Doe',
    'password' => $db->func('SHA1(?)',Array ("secretpassword+salt")),
    // password = SHA1('secretpassword+salt')
    'createdAt' => $db->now(),
    // createdAt = NOW()
    'expires' => $db->now('+1Y')
    // expires = NOW() + interval 1 year
    // Supported intervals [s]econd, [m]inute, [h]hour, [d]day, [M]onth, [Y]ear
);

$id = $db->insert ('users', $data);
if ($id)
    echo 'user was created. Id=' . $id;
else
    echo 'insert failed: ' . $db->getLastError();

INSERT ... ON DUPLICATE KEY UPDATE 構文

$data = Array ("login" => "admin",
               "firstName" => "John",
               "lastName" => 'Doe',
               "createdAt" => $db->now(),
               "updatedAt" => $db->now(),
);
$updateColumns = Array ("updatedAt");
$lastInsertId = "id";
$db->onDuplicate($updateColumns, $lastInsertId);
$id = $db->insert ('users', $data);

複数のデータセットを一度に挿入

$data = Array(
    Array ("login" => "admin",
        "firstName" => "John",
        "lastName" => 'Doe'
    ),
    Array ("login" => "other",
        "firstName" => "Another",
        "lastName" => 'User',
        "password" => "very_cool_hash"
    )
);
$ids = $db->insertMulti('users', $data);
if(!$ids) {
    echo 'insert failed: ' . $db->getLastError();
} else {
    echo 'new users inserted with following id\'s: ' . implode(', ', $ids);
}

すべてのデータセットが同じキーしか持たない場合は、単純化することができます。

$data = Array(
    Array ("admin", "John", "Doe"),
    Array ("other", "Another", "User")
);
$keys = Array("login", "firstName", "lastName");

$ids = $db->insertMulti('users', $data, $keys);
if(!$ids) {
    echo 'insert failed: ' . $db->getLastError();
} else {
    echo 'new users inserted with following id\'s: ' . implode(', ', $ids);
}

データ置換(REPLACE文)

Replace() メソッドは insert() と同じ API を実装しています。

データを更新する(UPDATE文)

$data = Array (
    'firstName' => 'Bobby',
    'lastName' => 'Tables',
    'editCount' => $db->inc(2),
    // editCount = editCount + 2;
    'active' => $db->not()
    // active = !active;
);
$db->where ('id', 1);
if ($db->update ('users', $data))
    echo $db->count . ' records were updated';
else
    echo 'update failed: ' . $db->getLastError();

update() はリミットパラメータもサポートしています。
php:
$db->update ('users', $data, 10);
// Gives: UPDATE users SET ... LIMIT 10

データを取得する(SELECT文)

セレクト/ゲット関数が呼び出された後、金額または返された行は$count変数に格納されます。

$users = $db->get('users'); //contains an Array of all users 
$users = $db->get('users', 10); //contains an Array 10 users

またはカスタムカラムを設定して選択します。関数を使用することもできます。

$cols = Array ("id", "name", "email");
$users = $db->get ("users", null, $cols);
if ($db->count > 0)
    foreach ($users as $user) { 
        print_r ($user);
    }

一行だけを選択する

$db->where ("id", 1);
$user = $db->getOne ("users");
echo $user['id'];

$stats = $db->getOne ("users", "sum(id), count(*) as cnt");
echo "total ".$stats['cnt']. "users found";

1つの列の値または関数の結果を選択

$count = $db->getValue ("users", "count(*)");
echo "{$count} users found";

複数の行から1つの列の値または関数の結果を選択

$logins = $db->getValue ("users", "login", null);
// select login from users
$logins = $db->getValue ("users", "login", 5);
// select login from users limit 5
foreach ($logins as $login)
    echo $login;

データを追加する(INSERT文)

また、特定のテーブルに .CSV または .XML データを読み込むこともできます。
.csv データを挿入するには、以下の構文を使用します。

$path_to_file = "/home/john/file.csv";
$db->loadData("users", $path_to_file);

これは、/home/john/ (johnのホームディレクトリ)フォルダにfile.csvという.csvファイルをロードします。
オプションでオプションの配列を添付することもできます。有効なオプションは以下の通りです。

Array(
    "fieldChar" => ';',     // Char which separates the data
    "lineChar" => '\r\n',   // Char which separates the lines
    "linesToIgnore" => 1    // Amount of lines to ignore at the beginning of the import
);

Attach

$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1);
$db->loadData("users", "/home/john/file.csv", $options);
// LOAD DATA ...

DATAの代わりにLOCAL DATAを使用するように指定

$options = Array("fieldChar" => ';', "lineChar" => '\r\n', "linesToIgnore" => 1, "loadDataLocal" => true);
$db->loadData("users", "/home/john/file.csv", $options);
// LOAD DATA LOCAL ...

XML挿入

XML データをテーブルにロードするには、loadXML メソッドを使用します。構文は loadData 構文と同じです。

$path_to_file = "/home/john/file.xml";
$db->loadXML("users", $path_to_file);

オプションのパラメータを追加

Array(
    "linesToIgnore" => 0,       // Amount of lines / rows to ignore at the beginning of the import
    "rowTag"    => "<user>" // The tag which marks the beginning of an entry
)

使用例

$options = Array("linesToIgnore" => 0, "rowTag" => "<user>"):
$path_to_file = "/home/john/file.xml";
$db->loadXML("users", $path_to_file, $options);

ページネーション(Pagination)

ページ分割された結果を取得するには get() の代わりに paginate() を使用します。

$page = 1;
// set page limit to 2 results per page. 20 by default
$db->pageLimit = 2;
$products = $db->arraybuilder()->paginate("products", $page);
echo "showing $page out of " . $db->totalPages;

MAP

純粋な配列で結果を取得するのではなく、必要なキーを含む連想配列で結果を取得することも可能です。get() で取得するフィールドが 2 つだけの場合は配列($k => $v)で、それ以外の場合は配列 ($k => 配列 ($v, $v)) で結果を返します。

$user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'login, id');
Array
(
    [user1] => 1
)

$user = $db->map ('login')->ObjectBuilder()->getOne ('users', 'id,login,createdAt');
Array
(
    [user1] => stdClass Object
        (
            [id] => 1
            [login] => user1
            [createdAt] => 2015-10-22 22:27:53
        )

)

リターン型の定義

MysqliDbは、3つの異なるフォーマットで結果を返すことができます。配列の配列、オブジェクトの配列、Json文字列です。返り値の型を選択するには、ArrayBuilder()、ObjectBuilder()、JsonBuilder()メソッドを使用します。ArrayBuilder() はデフォルトの戻り値の型であることに注意してください。

// Array return type
$= $db->getOne("users");
echo $u['login'];
// Object return type
$u = $db->ObjectBuilder()->getOne("users");
echo $u->login;
// Json return type
$json = $db->JsonBuilder()->getOne("users");

生のSQLクエリの実行

$users = $db->rawQuery('SELECT * from users where id >= ?', Array (10));
foreach ($users as $user) {
    print_r ($user);
}

長いifチェックを避けるために、生のクエリの選択結果を扱うためのヘルパー関数があります。
結果の1行を取得します。

$user = $db->rawQueryOne ('select * from users where id=?', Array(10));
echo $user['login'];
// Object return type
$user = $db->ObjectBuilder()->rawQueryOne ('select * from users where id=?', Array(10));
echo $user->login;

1カラムの値を文字列として取得

$password = $db->rawQueryValue ('select password from users where id=? limit 1', Array(10).
echo "パスワードは {$password} です。
注意: rawQueryValue() が配列ではなく文字列を返すようにするには、 クエリの最後に 'limit 1' を追加しなければなりません。

複数の行から1列の値を取得します。

$logins = $db->rawQueryValue ('select login from users limit 10');
foreach ($logins as $login)
    echo $login;

応用例

$params = Array(1, 'admin');
$users = $db->rawQuery("SELECT id, firstName, lastName FROM users WHERE id = ? AND login = ?", $params);
print_r($users); // contains Array of returned rows

// will handle any SQL query
$params = Array(10, 1, 10, 11, 2, 10);
$q = "(
    SELECT a FROM t1
        WHERE a = ? AND B = ?
        ORDER BY a LIMIT ?
) UNION (
    SELECT a FROM t2 
        WHERE a = ? AND B = ?
        ORDER BY a LIMIT ?
)";
$results = $db->rawQuery ($q, $params);
print_r ($results); // contains Array of returned rows

データを取得する条件を設定する(WHERE句) & グループ化したデータを取得する条件を設定する(HAVING句)

where(), orWhere(), having(), orHaving() メソッドを使用すると、クエリの where と having の条件を指定することができます。where() でサポートされているすべての条件は、having() でも同様にサポートされています。

警告: カラム間の比較を行うためには、生のwhere条件のみをカラム名として使用するか、関数をバインド変数として渡すことはできません。

$db->where ('id', 1);
$db->where ('login', 'admin');
$results = $db->get ('users');
// Gives: SELECT * FROM users WHERE id=1 AND login='admin';
$db->where ('id', 1);
$db->having ('login', 'admin');
$results = $db->get ('users');
// Gives: SELECT * FROM users WHERE id=1 HAVING login='admin';

演算子を使用して、カラム間の比較

// 間違い
$db->where ('lastLogin', 'createdAt');
// 正しい
$db->where ('lastLogin = createdAt');
$results = $db->get ('users');
// Gives: SELECT * FROM users WHERE lastLogin = createdAt;
$db->where ('id', 50, ">=");
// or $db->where ('id', Array ('>=' => 50));
$results = $db->get ('users');
// Gives: SELECT * FROM users WHERE id >= 50;

BETWEEN / NOT BETWEEN:

$db->where('id', Array (4, 20), 'BETWEEN');
// or $db->where ('id', Array ('BETWEEN' => Array(4, 20)));

$results = $db->get('users');
// Gives: SELECT * FROM users WHERE id BETWEEN 4 AND 20

IN / NOT IN:

$db->where('id', Array(1, 5, 27, -1, 'd'), 'IN');
// or $db->where('id', Array( 'IN' => Array(1, 5, 27, -1, 'd') ) );

$results = $db->get('users');
// Gives: SELECT * FROM users WHERE id IN (1, 5, 27, -1, 'd');

OR CASE:

$db->where ('firstName', 'John');
$db->orWhere ('firstName', 'Peter');
$results = $db->get ('users');
// Gives: SELECT * FROM users WHERE firstName='John' OR firstName='peter'

NULL比較

$db->where ("lastName", NULL, 'IS NOT');
$results = $db->get("users");
// Gives: SELECT * FROM users where lastName IS NOT NULL

LIKE比較

$db->where ("fullName", 'John%', 'like');
$results = $db->get("users");
// Gives: SELECT * FROM users where fullName like 'John%'
$db->where ("id != companyId");
$db->where ("DATE(createdAt) = DATE(lastLogin)");
$results = $db->get("users");

Or raw condition with variables:

$db->where ("(id = ? or id = ?)", Array(6,2));
$db->where ("login","mike")
$res = $db->get ("users");
// Gives: SELECT * FROM users WHERE (id = 6 or id = 2) and login='mike';

ページネーション総数の例

$offset = 10;
$count = 15;
$users = $db->withTotalCount()->get('users', Array ($offset, $count));
echo "Showing {$count} from {$db->totalCount}";

ページネーション総数の例

クエリーキーワード

LOW PRIORITY | DELAYED | HIGH PRIORITY | IGNORE およびその他の mysql キーワードを INSERT ()、REPLACE ()、GET ()、UPDATE ()、DELETE() メソッド、または FOR UPDATE | LOCK IN SHARE MODE に SELECT () に追加するには、以下のようにします。

$db->setQueryOption ('LOW_PRIORITY')->insert ($table, $param);
// GIVES: INSERT LOW_PRIORITY INTO table ...
$db->setQueryOption ('FOR UPDATE')->get ('users');
// GIVES: SELECT * FROM USERS FOR UPDATE;

キーワードの配列を使用

$db->setQueryOption (Array('LOW_PRIORITY', 'IGNORE'))->insert ($table,$param);
// GIVES: INSERT LOW_PRIORITY IGNORE INTO table ...

同じようにキーワードはSELECTクエリでも使用できます。

$db->setQueryOption ('SQL_NO_CACHE');
$db->get("users");
// GIVES: SELECT SQL_NO_CACHE * FROM USERS;

オプションで、メソッドチェーニングを使用して、何度もオブジェクトを参照せずに何度もどこを呼び出すことができます。

$results = $db
    ->where('id', 1)
    ->where('login', 'admin')
    ->get('users');

データを削除する(DELETE文)

$db->where('id', 1);
if($db->delete('users')) echo 'successfully deleted';

取得するデータをソートする(ORDER BY句)

$db->orderBy("id","asc");
$db->orderBy("login","Desc");
$db->orderBy("RAND ()");
$results = $db->get('users');
// Gives: SELECT * FROM users ORDER BY id ASC,login DESC, RAND ();

値で順番に並べる

$db->orderBy('userGroup', 'ASC', array('superuser', 'admin', 'users'));
$db->get('users');
// Gives: SELECT * FROM users ORDER BY FIELD (userGroup, 'superuser', 'admin', 'users') ASC;

setPrefix()の機能を使用していて、orderBy()メソッドでテーブル名を使用する必要がある場合は、
テーブル名が ``でエスケープされていることを確認してください。

$db->setPrefix ("t_");
$db->orderBy ("users.id","asc");
$results = $db->get ('users');
// WRONG: That will give: SELECT * FROM t_users ORDER BY users.id ASC;

$db->setPrefix ("t_");
$db->orderBy ("`users`.id", "asc");
$results = $db->get ('users');
// CORRECT: That will give: SELECT * FROM t_users ORDER BY t_users.id ASC;

データをグループ化する(GROUP BY句)

$db->groupBy ("name");
$results = $db->get ('users');
// Gives: SELECT * FROM users GROUP BY name;

内部結合を行う(INNER JOIN句)

$db->join("users u", "p.tenantID=u.tenantID", "LEFT");
$db->where("u.id", 6);
$products = $db->get ("products p", null, "u.name, p.productName");
print_r ($products);

結合文にAND条件を追加

$db->join("users u", "p.tenantID=u.tenantID", "LEFT");
$db->joinWhere("users u", "u.tenantID", 5);
$products = $db->get ("products p", null, "u.name, p.productName");
print_r ($products);
// Gives: SELECT  u.login, p.productName FROM products p LEFT JOIN users u ON (p.tenantID=u.tenantID AND u.tenantID = 5)

結合文にOR条件を追加

$db->join("users u", "p.tenantID=u.tenantID", "LEFT");
$db->joinOrWhere("users u", "u.tenantID", 5);
$products = $db->get ("products p", null, "u.name, p.productName");
print_r ($products);
// Gives: SELECT  u.login, p.productName FROM products p LEFT JOIN users u ON (p.tenantID=u.tenantID OR u.tenantID = 5)

プロパティ共有

プロパティをコピーすることも可能です。

$db->where ("agentId", 10);
$db->where ("active", true);

$customers = $db->copy ();
$res = $customers->get ("customers", Array (10, 10));
// SELECT * FROM customers where agentId = 10 and active = 1 limit 10, 10

$cnt = $db->getValue ("customers", "count(id)");
echo "total records found: " . $cnt;
// SELECT count(id) FROM users where agentId = 10 and active = 1

サブクエリ

Subquery init
Subquery init without an alias to use in inserts/updates/where Eg. (select * from users)

$sq = $db->subQuery();
$sq->get ("users");
A subquery with an alias specified to use in JOINs . Eg. (select * from users) sq

$sq = $db->subQuery("sq");
$sq->get ("users");
Subquery in selects:

$ids = $db->subQuery ();
$ids->where ("qty", 2, ">");
$ids->get ("products", null, "userId");

$db->where ("id", $ids, 'in');
$res = $db->get ("users");
// Gives SELECT * FROM users WHERE id IN (SELECT userId FROM products WHERE qty > 2)

MySQLサブクエリを使ったINSERT文

$userIdQ = $db->subQuery ();
$userIdQ->where ("id", 6);
$userIdQ->getOne ("users", "name"),

$data = Array (
    "productName" => "test product",
    "userId" => $userIdQ,
    "lastUpdated" => $db->now()
);
$id = $db->insert ("products", $data);
// Gives INSERT INTO PRODUCTS (productName, userId, lastUpdated) values ("test product", (SELECT name FROM users WHERE id = 6), NOW());

MySQLサブクエリを使ったJOIN文

$usersQ = $db->subQuery ("u");
$usersQ->where ("active", 1);
$usersQ->get ("users");

$db->join($usersQ, "p.userId=u.id", "LEFT");
$products = $db->get ("products p", null, "u.login, p.productName");
print_r ($products);
// SELECT u.login, p.productName FROM products p LEFT JOIN (SELECT * FROM t_users WHERE active = 1) u on p.userId=u.id;

EXISTS と NOT EXISTS

$sub = $db->subQuery();
    $sub->where("company", 'testCompany');
    $sub->get ("users", null, 'userId');
$db->where (null, $sub, 'exists');
$products = $db->get ("products");
// Gives SELECT * FROM products WHERE EXISTS (select userId from users where company='testCompany')

Has

この関数の前に where メソッドを呼び出して指定した where 条件を満たす要素が少なくとも存在する場合に TRUE を返す便利な関数です。

$db->where("user", $user);
$db->where("password", md5($password));
if($db->has("users")) {
    return "You are logged";
} else {
    return "Wrong user/password";
}

Helper methods

データベースから切断

    $db->disconnect();

mysql の接続が切れた場合の再接続

if (!$db->ping())
    $db->connect()

最後に実行されたSQLクエリを取得します。この関数がSQLクエリを返すのはデバッグ目的のみであることに注意してください。

    $db->get('users');
    echo "Last executed query was ". $db->getLastQuery();

テーブルが存在するかどうかをチェック

    if ($db->tableExists ('users'))
        echo "hooray";

mysqli_real_escape_string() wrapper:

$escaped = $db->escape ("' and 1=1");

トランザクションヘルパー

トランザクションはinnoDBのテーブルで動作していることを覚えておいてください。挿入に失敗した場合は、トランザクションをロールバックします。

$db->startTransaction();
...
if (!$db->insert ('myTable', $insertData)) {
    //Error while saving, cancel new record
    $db->rollback();
} else {
    //OK
    $db->commit();
}

エラーヘルパー

クエリを実行した後、エラーが発生したかどうかをチェックするオプションがあります。
MySQLのエラー文字列や、最後に実行したクエリのエラーコードを取得することができます。

$db->where('login', 'admin')->update('users', ['firstName' => 'Jack']);

if ($db->getLastErrno() === 0)
    echo 'Update succesfull';
else
    echo 'Update failed. Error: '. $db->getLastError();

クエリ実行時間のベンチマーク

クエリの実行時間を追跡するためには、setTrace()関数を呼び出す必要があります。

$db->setTrace (true);
// As a second parameter it is possible to define prefix of the path which should be striped from filename
// $db->setTrace (true, $_SERVER['SERVER_ROOT']);
$db->get("users");
$db->get("test");
print_r ($db->trace);
    [0] => Array
        (
            [0] => SELECT  * FROM t_users ORDER BY `id` ASC
            [1] => 0.0010669231414795
            [2] => MysqliDb->get() >>  file "/avb/work/PHP-MySQLi-Database-Class/tests.php" line #151
        )

    [1] => Array
        (
            [0] => SELECT  * FROM t_test
            [1] => 0.00069189071655273
            [2] => MysqliDb->get() >>  file "/avb/work/PHP-MySQLi-Database-Class/tests.php" line #152
        )

テーブルロック

テーブルをロックするには、setLockMethodと一緒にロックメソッドを使用します。
次の例では、書き込みアクセスのためにテーブルのユーザをロックします。

$db->setLockMethod("WRITE")->lock("users");

別のロックを呼び出すと、最初のロックが解除されます。

$db->unlock();

以前にロックされていたテーブルのロックを解除します。複数のテーブルをロックするには、配列を使用します。

$db->setLockMethod("READ")->lock(array("users", "log"));

これは、テーブルのユーザーとログをロックします。その後に*unlock()を使用するか、
テーブルがロックされたままになることを確認してください!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初投稿】較べてわかるT-SQL - MySQL

初投稿です。よろしくお願いします。

はじめに

いまさら感あふれますが、これから触る初心者向けに簡単な2種類のSQLコマンドを比較してみました。自身のメモを基に書くので情報が古かったら申し訳ないです、ご指摘ください。

主目的となるものはT-SQLコマンドです。それに対してトップメタであるMySQLを比較対象として採用しました。
T-SQL自体はそこまでメジャーなものでもないので利用する人は少ないとは思いますが、実際使うことになったら情報少なかったり、微妙に他と違うものになってるのでその際には、ぜひ参考にしていただけたら嬉しいです。

そもそもT-SQLとは

本記事で詳細に説明することではないと思うので詳しくは 公式のリファレンス 参照

簡単に説明すると、T-SQL(正式にはTransact-SQL)はMicrosoft SQL Serverで利用されているSQL言語です。基本はSQLなので大きくMySQLなどのメジャー言語と差はないのですが上でも書きましたが、微妙に違う部分があります。

MySQL - T-SQL の比較

ざっくりとやっていきます。ベースは前述のとおりトップメタのMySQLとします。
すべてを紹介するわけではない点は承知ください。

データ型について

doubleenumはT-SQLでは対応していない

もちろん、MySQLならdoublefloatもどっちも使える。T-SQLだとdoubleは使えないのでfloat(またはreal)型を使いましょうというだけ。

enumはそもそもないです。

MySQL
-- double
point double
-- enum
color enum('red','blue', 'green')
T-SQL
-- double
point float
point real
-- enum
color varchar(10) NOT NULL CHECK (color IN('red','blue', 'green')) default 'red'

enumの置き換えはどうしても冗長になってしまいますがあきらめましょう。

フィールドの設定について

auto_incrementkeyは使えない

最重要ポイントかなと自分では考えています。この部分、PostgreSQLとかとも全然違いますし、冗長になってる気がして個人的に好まないんですよね……

MySQL
-- auto_increment
id int not null auto_increment
-- key
key point(point)
T-SQL
-- auto_increment
id int not null IDENTITY(1,1)
-- key
CREATE INDEX score ON users(score);

ポイントとしてはT-SQLの場合、INDEXの設定はそもそも別の句で設定するってところですね。MySQLの場合はテーブル定義の時にセットで書くと思います。

テーブルの作成 - CREATE

上記二点を踏まえたうえで本記事でのベーステーブルを以下CREATE構文で示します。

MySQL
CREATE TABLE accounts(
  id int not null auto_increment,
  name varchar(255),
  mail varchar(255) unique,
  password char(32),
  point double,
  color enum('red', 'blue', 'green'),
  created datetime,
  key point(point)
);
T-SQL
CREATE TABLE accounts(
  id int not null IDENTITY(1,1),
  name varchar(255),
  mail varchar(255) unique,
  password char(32),
  point float,
  color varchar(10) NOT NULL CHECK (color IN('red', 'blue', 'green')) default 'red',
  created datetime
);

CREATE INDEX point ON accounts(point);

こんな感じ。フィールドとかは適当でそれっぽく設定しています。
今回はこのテーブルをベースにしていきます。

テーブルの一覧表示

基本コマンド。そもそもどんなテーブルがあるのかを見る。

MySQL
SHOW TABLES;
T-SQL
SELECT * FROM sys.objects;

-- もしくは
SELECT name, crdate
FROM sysobjects
WHERE xtype = 'U'
ORDER BY NAME

テーブル構造の確認

カラムの定義を確認したくなったら使いましょう。

MySQL
DESC accounts;
T-SQL
SP_COLUMNS accounts;

レコードの挿入 - INSERT

共通

INSERT INTO accounts(
  name,
  mail,
  password ,
  point,
  color,
  created
) VALUES(
  'nayuta',
  'nayuta@hoge.hoga',
  '********'
  5.5,
  'blue',
  '2020-07-19 11:00:00'
), (
  'kiseki',
  'kiseki@hoge.hoga',
  '********'
  7.0,
  'red',
  '2020-07-21 15:00:00'
)

レコードの抽出 - SELECT

共通

-- 全件取得
SELECT * FROM accounts;
-- nameとmailカラムのみ取得
SELECT name, mail FROM accounts;

LENGTH句

そんなに変わらない

MySQL
SELECT mail, LENGTH(mail) FROM accounts;
T-SQL
SELECT mail, LEN(mail) FROM accounts;

NOW句

T-SQLではGETDATEだが、世界標準時間になっているので変換が必要

MySQL
SELECT NOW();
T-SQL
SELECT GETDATE();
SELECT DATEADD(hour, 9, GETDATE());

DATEDIFF句

T-SQLでは引数が3つになっていおり、第一引数に差分の単位が追加されている。
また、NOWが使えない点も注意。

MySQL
SELECT name, DATEDIFF(NOW(), created) FROM accounts;
T-SQL
SELECT name, DATEDIFF(
  day,
  DATEADD(hour, 9, GETDATE()),
  created
) FROM accounts;

メタコマンドGについて

MySQLには便利なメタコマンドとしてGが存在しています。

MySQL
select * from accounts \G

簡単に説明すると取得したデータを縦に表示してくれるものです。超便利……

残念ながらT-SQLには存在しません。解散!

レコードの抽出(条件付き) - WHERE

そもそもセクションとしてSELECT構文と分けるか、内包させるかで悩みましたがSQL言語を学ぶ上で非常に重要な項目だと思ったので分けました。

条件の構文に関しては基本的に共通。

WHERE句

基本のき。共通。

-- accountsテーブルでcolorがred以外のレコードを取得
SELECT * FROM accounts WHERE color != 'red';

BETWEEN句

共通

-- accountsテーブルでpointが5.0から8.0までのレコードを取得
SELECT * FROM accounts WHERE point between 5.0 and 8.0;

IN句

共通

-- accountsテーブルでcolorがredまたはblueであるレコードを取得
SELECT * FROM accounts WHERE color in ('red', 'blue');

AND/OR句

共通

-- accountsテーブルでpointが4以上かつcolorがblueのレコードを取得
SELECT * FROM accounts WHERE point >= 4.0 and color = 'blue';
-- accountsテーブルでpointが4以上かcolorがblueのレコードを取得
SELECT * FROM accounts WHERE point >= 4.0 or color = 'blue';

並び替え、件数の制限

WHERE句同様、分けるか内包するか悩んだ末分けた。

ORDER BY句

共通
デフォルトは昇順。昇順(asc)と降順(desc)は切り替え可能

SELECT * FROM accounts ORDER BY point;
SELECT * FROM accounts ORDER BY point desc;

LIMIT句

T-SQLには存在しません。面倒ですが、OFFSET FETCH句を利用しましょう。
流れとしてはソートしてOFFSET、FETCHになります。

LIMITがどれだけ便利だったかがわかりますね……

先頭から3つレコードを取得する

MySQL
SELECT * FROM accounts LIMIT 3;
T-SQL
SELECT * FROM accounts ORDER BY id OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;

先頭2番目から2つレコードを取得する

MySQL
SELECT * FROM accounts LIMIT 2,2;
T-SQL
SELECT * FROM accounts ORDER BY id OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY;

レコードの更新

共通

UPDATE accounts SET mail = 'nayutanokiseki@hoge.fuga' WHERE id = 1;

レコードの削除

共通

DELETE FROM accounts WHERE point <= 9.0;

テーブル構造の変更

フィールドの追加

T-SQLの使い勝手が悪い部分です(他もですけど)
T-SQLではカラムの位置を指定しての追加ができません(修正されてたらすみません)

一番後ろに追加することはできます。

MySQL
ALTER TABLE accounts ADD full_name varchar(255) AFTER name;
T-SQL
ALTER TABLE accounts ADD full_name varchar(255);

どっか間に入れたいってなったら……あきらめてSSMSを使うかテーブル自体を生成しなおしましょう。

参考: 【驚愕】SQLServer2008は指定位置にカラムを追加できない【ツール強要】

フィールドの変更

CHENGE句は使えません。

MySQL
ALTER TABLE accounts CHANGE name name varchar(100);
T-SQL
ALTER TABLE accounts ALTER COLUMN name varchar(100);

フィールドの削除

MySQL
ALTER TABLE accounts DROP name;
T-SQL
ALTER TABLE accounts DROP COLUMN name;

テーブル名の変更

ALTER TABLEじゃできないのでsp_renameでやりましょう

MySQL
ALTER TABLE accounts rename new_accounts;
T-SQL
sp_rename accounts, new_accounts;
EXEC sp_rename 'accounts', 'new_accounts';

おわりに

初めての投稿ということもあったんで色々書き方がわからなかったり、どういう風に書けばいいのかわからない点も多かったです。結構ノリと勢いで書いている感じがあるんで指摘していただけると嬉しいです!

当初の目的は私自身の知識の確認という部分が大きかったのですが、もし誰かの手助けになれば幸いです。

以上、閲覧ありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Django入門03(リリース編)

環境ごとに設定ファイル(settings)を変える

ローカル環境、開発サーバー、本番サーバーで設定を切り替える為の変更。
基本的に以下ページの通り。
Djangoプロジェクト構造のカスタマイズ(分割と構造化)

configディレクトリのリネーム

  • settings.pyが含まれるフォルダの名前を変更する
  • manage.pyの中の os.environ.setdefault を変更する

settingsの分割

  • settings.pyから共通部分を抜き出してbase.pyとする
  • 共通ではない部分をdevelopment.pyやproduction.pyとする
  • development.pyやproduction.pyに from .base import * を記述し、共通部分を読み込むようにする
  • manage.pyの中のos.environ.setdefaultを変更する

Djangoサーバー起動時の設定ファイル指定方法

--settingsで切り替える。

python manage.py runserver 0.0.0.0:8000 --settings=config.settings.production

AWSで動かす場合の注意点

起動時は --daemon をつける

--daemon をつけないとEC2インスタンスにアクセスしているterminal(teratermなど)のプロセスを落とした瞬間にサーバー側のプロセスも落ちてしまう。

gunicorn config.wsgi --bind=0.0.0.0:8000 --env DJANGO_SETTINGS_MODULE=config.settings.development --daemon

https://stackoverflow.com/questions/13654688/what-is-the-correct-way-to-leave-gunicorn-running

wsgiファイルにもmysqlライブラリをimportすべし

wsgiファイルにもmysqlライブラリ(pymysqlなど)をimportしておかないと、gunicornから起動する際にmysqlに接続できずにエラーになる。

import os
import pymysql
pymysql.install_as_MySQLdb()
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.development')

application = get_wsgi_application()

staticディレクトリを参照する際の注意

nginxの設定変更

/etc/nginx/nginx.conf にstaticの参照設定の追記が必要。
パスを書き込む際 (app name) までの指定でよく、(app name)/static までは不要。

location /static/ {
             root /home/ec2-user/(app name);
        }

設定変更後は nginx の再起動が必要。

sudo nginx -s reload
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[MySQL5.6] rootユーザーの初期パスワード確認方法

/root/.mysql_secretに書かれている。

[root@hostname ~]# cat /root/.mysql_secret
# The random password set for the root user at Mon Jul 20 16:33:13 2020 (local time): 
g1R3DBjSLM6f3pec
[root@hostname~]# mysql -uroot -pg1R3DBjSLM6f3pec
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.6.47

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

しかし、

mysql> show databases;
ERROR 1820 (HY000): You must SET PASSWORD before executing this statement

新しいパスワードをセットしないと怒られる。

mysql> set password for root@localhost=password("root");
Query OK, 0 rows affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
+--------------------+
4 rows in set (0.00 sec)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

mysql.server startできないときにやったこと

事象

MySQLの起動や停止ができない。
Qiitaで記事を見つけていろいろとやってみたが駄目。

$ mysql.server start
Starting MySQL
.. ERROR! The server quit without updating PID file (/usr/local/var/mysql/XXXXXXXX.local.pid).
$ mysql.server stop
 ERROR! MySQL server PID file could not be found!

試したこと

解決方法

起動中のMySQLをkill(強制終了する)

# MySQLに関する起動中のプロセスを検索
$ ps -ef | grep mysql
  501  4412     1   0  3 720  ??  0:00.02 /bin/sh /usr/local/Cellar/mysql/8.0.19/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/username.local.pid
# 強制終了
$ sudo kill 4412

起動した!

$ mysql.server start
Starting MySQL
 SUCCESS! 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む