PDOでSQLSERVERの日本語テーブル、日本語項目を取得

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,894

juriparu0411

score 12

前提・実現したいこと

PHPでPDO接続でsqlserverを使用を試みていますが、日本語の項目名、テーブル名の場合、配列取得でエラーとなります。

英数字のテーブル、項目名は、正しく機能します。
(コードは、UTF8で記述)

どなたか、おわかりの方がいらっしゃいましたら、
日本語のテーブルを扱う方法をおしえていただけますでしょうか?

発生している問題・エラーメッセージ

エラーメッセージ


PHP Notice:  Undefined index: DPT in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 73
PHP Notice:  Undefined index: DPT in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 74
PHP Notice:  Undefined index: DPT略名_漢字 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 75
PHP Notice:  Undefined index: DPT in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 73
PHP Notice:  Undefined index: DPT in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 74
PHP Notice:  Undefined index: DPT略名_漢字 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 75
PHP Notice:  Undefined index: DPT in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 73
PHP Notice:  Undefined index: DPT in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 74
PHP Notice:  Undefined index: DPT略名_漢字 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 75

<?php

/**
 * common.php
 */
/**
 * DSN
 */

define('DSN_MSSQL', 'sqlsrv:server=.\sqlexpress;database=iryoumysql;');

/**
 * エスケープ
 */
function h($string)
{
    return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

/**
 * データベースコネクション
 * @return \PDO
 */
function db_con()
{


    // MSSQL
    $username = 'testuser';
    $password = 'testpass';
    $pdo = new PDO(DSN_MSSQL, $username, $password);

    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
    return $pdo;
}

/**
 * select
 * @param string $sql
 * @param array $params
 * @return array
 */


function select($sql, $params = array())
{    
    $pdo = db_con();
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    return $stmt->fetchAll();
}

該当のソースコード

<?php
/**
 * index.php
 */
ini_set('display_errors', 1);
require 'common.php';

// 商品リストを検索

$sql_items = 'SELECT DPT, DPT略名_漢字 FROM DPT';
print 'DPTマスタ select';
var_dump($sql_items);
$arrItems = select($sql_items);
var_dump($arrItems);


// 購入履歴の検索
if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST') {

    $arr = array();

    $sql_trading = 'SELECT ';
    $sql_trading .= 'SUM(t.hatchusu) AS quantity';
    $sql_trading .= ', s.venmein as shop_name ';
    $sql_trading .= ', i.dptmein as item_name ';
    $sql_trading .= ', l.linmein as lin_name ';
    $sql_trading .= 'FROM VM_nouhin_jisseki t ';
    $sql_trading .= 'INNER JOIN ven_mast s ON s.ven = t.ven ';
    $sql_trading .= 'INNER JOIN dpt_mast i ON i.dpt = t.dpt ';
    $sql_trading .= 'INNER JOIN lin_mast l ON l.lin = t.lin ';
//    $sql_trading .= 'WHERE 1 ';
    $sql_trading .= 'WHERE 1=1 ';

    if (0 < filter_input(INPUT_POST, 'shop')) {
        $sql_trading .= 'AND t.ven = :shop_id ';
        $arr[':shop_id'] = filter_input(INPUT_POST, 'shop');
    }
    if (0 < filter_input(INPUT_POST, 'item')) {
        $sql_trading .= 'AND t.dpt = :item_id ';
        $arr[':item_id'] = filter_input(INPUT_POST, 'item');
    }

//    $sql_trading .= 'GROUP BY t.shop_id,t.item_id,t.lin_id ';
    $sql_trading .= 'GROUP BY s.venmein,i.dptmein,l.linmein';

    $arrTradings = select($sql_trading, $arr);
//    var_dump($sql_trading);
}
?><!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>Ajaxサンプル</title>
        <style type="text/css">
            table {
                border-collapse: collapse;
                width: 600px;
            }
            table th, table td {
                border: 1px solid #CCC;
            }
        </style>
    </head>
    <body>
        <form method="post">
            <p>
                <label for="item">DPT</label>
                <select name="item" id="item">
                    <option value="">---- 選択してください ----</option>

                    <?php foreach ($arrItems as $item) : ?>

                        <?php if ($item['DPT'] == filter_input(INPUT_POST, 'item')): ?>
                            <option value="<?= h($item['DPT']); ?>" selected="selected">
                                <?= h($item['DPT略名_漢字']); ?>
                            </option>
                        <?php else: ?>
                            <option value="<?= h($item['DPT']); ?>">
                                <?= h($item['DPT略名_漢字']); ?>
                            </option>
                        <?php endif; ?>

                    <?php endforeach; ?>
                </select>

試したこと

エラーが出ている箇所の日本語項目名をバックックオート(`)で囲みましたが、エラーのままでした。

$item[0]、$item[1]にソ-スを変更しましたが、
エラーメッセージは同じでした。

PHP Notice:  Undefined offset: 0 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 73
PHP Notice:  Undefined offset: 0 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 74
PHP Notice:  Undefined offset: 1 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 75
PHP Notice:  Undefined offset: 0 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 73
PHP Notice:  Undefined offset: 0 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 74
PHP Notice:  Undefined offset: 1 in C:\inetpub\wwwroot\php\pdo_nihongo\index.php on line 75

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

PHP Version 5.4.45
IIS7.0
Microsoft SQL Server 2008 R2 Express

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • juriparu0411

    2016/11/25 11:58

    先ほどの投稿の修正です。エラーメッセージは、3行(line 73,74,75) ☓ 90組みほど出力しているので、SELECTはできているかもしれません。

    キャンセル

  • kunai

    2016/11/25 12:12

    ただの配列のインデックスエラーのようですね。<?php foreach ($arrItems as $item) : ?>の直後に<?php var_dump($item); ?>とかしてみたらいかがでしょう

    キャンセル

  • juriparu0411

    2016/11/25 12:24

    <?php foreach ($arrItems as $item) : ?>の直後に<?php var_dump($item); ?>を入れましたがDISPLAYには出力されませんでした。

    キャンセル

回答 3

checkベストアンサー

+1

SQLServer は Windows で動作するものですから、
テーブル名、およびカラム名は CP932(SJIS-WIN)の文字コードとなります。
Ajaxを利用するという条件ではスクリプトは UTF-8を使うことが推奨されますから、データベースのカラム名にはマルチバイトを使わず、シングルバイトで定義するのがベストプラクティスです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/25 17:34

    早速のご確認ありがとうございます。また、ご指導いただいたソースを無断で公開してしまい失礼いたしました。実は、社内のシステムはVB.NET、レガシーASPで開発している案件も多く、DBのテーブル、項目名が日本語項目になっていて質問した次第です。やはりシングルバイトなんですね。よく考えてみます。

    キャンセル

  • 2016/11/25 17:36 編集

    場当たり的な対処としては、DB側にViewでシングルバイトにしたものを作ってしまうという手も考えられなくはありません。

    カラム名をいちいち、mb_convert_encoding するよりはソースコードもスッキリするでしょう。

    キャンセル

  • 2016/11/25 18:21

    Viewでの対応は思いつきませんでした。これ名案ですね。やりたいことに必要な項目を整理して試してみます。

    キャンセル

+1

var_dump($arrItems);
しているようですが、そこで各要素に「DTP」をキーにした値はありませんか?
正直肝心のPDOの部分が書いていないのでなんとも言えません
実行していないのであれば実行してください

 追記

SQLサーバーとPDO、文字コードの相性があるので明示的に
$pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND,'SET NAMES utf8');
を実行してみるとかですかね
一般に$dsn内で「;charset=UTF8」をつけるんですけどね

その上でどうしても文字化けするようならarray_walkで付け替えてください

$a=["あああ"=>"いいい","ううう"=>"えええ"];//元データをsjisやeucで書いておいて
$b=[];//UTF8用の配列に流し込む
array_walk($a,function($val,$index) use(&$b){
  $b[mb_convert_encoding($index,'UTF8','EUCJP,SJIS')]=mb_convert_encoding($val,'UTF8','EUCJP,SJIS');
  });
print_r($b);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/25 18:32

    "SELECT DPT DPT, DPT略名_漢字 DPT_SHORTNAME FROM DPT"⇒こちらで動きました。
    ありがとうございます。

    キャンセル

  • 2016/11/25 18:57

    @juriparu0411
    動きましたか。この対応は今後のメンテナンス時のことを考えるとかなりバッドノウハウ(DB定義変更などによるプログラムへの影響調査など行う時にDBの項目名などで検索できないなど)です。
    正対応としては本来の項目名で取得できるようにすべきなので、であまり多用はなさらないように。

    キャンセル

  • 2016/11/26 11:35

    承知いたしました。SQLSERVER自体がSJISなので、無理に文字コードを合わせるのは難があるようですね。ご指導ありがとうございました。

    キャンセル

0

define('DSN_MSSQL', 'sqlsrv:server=.\sqlexpress;database=iryoumysql;charset=UTF-8');


↑のように、SQLServer側の文字コードを指定してみたら通るのでは

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/11/25 17:38

    charsetは指定できないようですね。

    PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[IMSSP]: An invalid keyword 'charset' was specified in the DSN string.' in C:\inetpub\wwwroot\php\pdo_nihongo\common.php:35
    Stack trace:
    #0 C:\inetpub\wwwroot\php\pdo_nihongo\common.php(35): PDO->__construct('sqlsrv:server=....', 'sa', 'sa')
    #1 C:\inetpub\wwwroot\php\pdo_nihongo\common.php(53): db_con()
    #2 C:\inetpub\wwwroot\php\pdo_nihongo\index.php(13): select('SELECT \xEF\xBC\xA4\xEF\xBC\xB0\xEF\xBC...')
    #3 {main}
    thrown in C:\inetpub\wwwroot\php\pdo_nihongo\common.php on line 35

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる