iT邦幫忙

0

(PHP)請教高手們有關MSSQL回傳資料表資料 問題

技術高超的各位 大家好
由於本人是PHP新手,專題一直無法解決有邏輯及程式上的問題
想請教各位 能幫小弟 打通腦中混亂的思緒

我們是開發PHP 一部份是連結MSSQL拉回資料庫的資料 並顯示在PHP表單上
但目前我遇到的困難是有一資料表(如下圖範例↓)
http://ithelp.ithome.com.tw/upload/images/20161028/20103184klwg7E7ubz.png
前面有幾個欄位的數值是一模一樣的但後面商品代碼與商品名稱...etc,有不一樣的資訊,
能回傳到PHP表格上能進行重複值的刪除與分類
規劃是
(如下圖網頁版表格範例↓)
http://ithelp.ithome.com.tw/upload/images/20161028/20103184lVCszCHZeV.png

首先我會
在PHP下SQL語法(SELECT * FROM table where id = 'AA11**')
把目前資料表有關ID = AA11**的資料全部被篩選出來(如下圖↓)
http://ithelp.ithome.com.tw/upload/images/20161028/20103184anL5fLoWPj.png
但後續顯示
ID
消費時間
商店編號
商店名稱

(一次)

商品代碼
商品名稱
數量

(依序顯示出)

就不是很了解我該使用什麼語法能讓我去只要列出
是該使用 while($row=sqlsrv_fetch_array($result)) 儲存到陣列
echo嗎?
或是做二維陣列?
還是 foreach ?
再去做i=0 i++ ?

網路爬文找好久了...
請各位大師神救援小弟 的程式邏輯
真的很感恩

只要能依需求顯示資料出來的程式都是正確的.
如果每張單的資料量不大,其實用那一種語法應該都ok(程式效能差異不大).

2 個回答

0
海綿寶寶
iT邦超人 1 級 ‧ 2016-10-28 14:36:35
最佳解答

PHP 官網範例 來改

<?php
$serverName = "serverName\instanceName";
$connectionInfo = array( "Database"=>"dbName", "UID"=>"username", "PWD"=>"password");
$conn = sqlsrv_connect( $serverName, $connectionInfo );
if( $conn === false ) {
    die( print_r( sqlsrv_errors(), true));
}

$sql = "SELECT * FROM table where id = 'AA11**'";
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
    die( print_r( sqlsrv_errors(), true) );
}

$rowcnt = 0;
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
   $rowcnt = $rowcnt + 1;   
   if ($rowcnt==1) { //第一筆,特別處理
      //1.用 $row['Id'],$row['Date'],$row['Qa1'],$row['Qa2']顯示表頭
      //2.顯示表身標題列(Num, Id, Date... )
      //3.用 $row['Qa3'], $row['Qa4'], $row['Qa5'] 顯示表身資料列
   } else {   //第二筆(含)以後
      //只需用 $row['Qa3'], $row['Qa4'], $row['Qa5'] 顯示表身資料列
   }
   echo $row['LastName'].", ".$row['FirstName']."<br />";
}

sqlsrv_free_stmt( $stmt);
?>
看更多先前的回應...收起先前的回應...

歹勢,程式用抄的,忘了刪掉這列

echo $row['LastName'].", ".$row['FirstName']."<br />";
ayo0831 iT邦新手 5 級 ‧ 2016-10-28 23:19:14 檢舉

謝謝海綿寶寶您的協助,讓我在程式上有些突破
我也有研究你所po的code
但到最後 else { //第二筆(含)以後
會把其他日期的 'Qa3' 'Qa4' 'Qa5' 一起echo 出來

http://ithelp.ithome.com.tw/upload/images/20161028/20103184pPoWOWOa4U.png

這樣那些資料就不是2016 10 28的了
最主要以ID與date
自動判斷會直接去區分
http://ithelp.ithome.com.tw/upload/images/20161028/20103184lVCszCHZeV.png
http://ithelp.ithome.com.tw/upload/images/20161028/20103184FKPDEn5GR0.jpg

在else 後續部分 我需要怎麼愈切割會比較好?
謝謝您

沒注意到日期不同
修正如下

<?php
$serverName = "serverName\instanceName";
$connectionInfo = array( "Database"=>"dbName", "UID"=>"username", "PWD"=>"password");
$conn = sqlsrv_connect( $serverName, $connectionInfo );
if( $conn === false ) {
    die( print_r( sqlsrv_errors(), true));
}

$sql = "SELECT * FROM table WHERE id = 'AA11**' ORDER BY date";//要加 ORDER BY,否則就錯
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
    die( print_r( sqlsrv_errors(), true) );
}

$rowcnt = 0;
$savekey = "";
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
   $rowcnt = $rowcnt + 1;   
   if ($rowcnt==1) { //第一筆,特別處理
      //1.用 $row['Id'],$row['Date'],$row['Qa1'],$row['Qa2']顯示表頭
      //2.顯示表身標題列(Num, Id, Date... )
      //3.用 $row['Qa3'], $row['Qa4'], $row['Qa5'] 顯示表身資料列
      //4.將 Date 記錄下來
      $savekey = $row['Date'];
   } else {   //第二筆(含)以後
      //1.判斷該筆資料的 Date 是否等於 $savekey
      //1.a 如果不同,表示換日期了(要顯示表頭那一堆,即上面 $rowcnt==1 的 1.2.3.)      
      //1.b 如果相同,只需用 $row['Qa3'], $row['Qa4'], $row['Qa5'] 顯示表身資料列
      //2.將 Date 記錄下來
      $savekey = $row['Date'];
   }
}

sqlsrv_free_stmt( $stmt);
?>
ayo0831 iT邦新手 5 級 ‧ 2016-10-29 23:51:11 檢舉

HI 海綿寶寶 ,感謝您的幫忙
我總覺得我還是在程式上遇到問題

但為什麼最後MOS 的可樂雪碧 會只跳一個出來?
http://ithelp.ithome.com.tw/upload/images/20161029/20103184uzjWtKX66N.png

ayo0831 iT邦新手 5 級 ‧ 2016-10-29 23:52:31 檢舉
<?php
        $serverName="*";
        $connectionInfo=array("database"=>"*","UID"=>"*","PWD"=>"*","CharacterSet" => "UTF-8");  
        $conn=sqlsrv_connect($serverName,$connectionInfo);  
        if($conn === false ){               
         echo "資料庫無法連線!!!<br />";  
        die(print_r(sqlsrv_errors(),true));  
           }



$sql = "SELECT * FROM dbo.table1 WHERE id = 'AA11**' ORDER BY Date";//要加 ORDER BY,否則就錯
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
    die( print_r( sqlsrv_errors(), true) );
}

$rowcnt = 0;
$savekey = "";
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
   $rowcnt = $rowcnt + 1;   
   if ($rowcnt==1) { //第一筆,特別處理
        print "======================================\n";echo "<br>";
        echo "ID:";print_r($row['Id']);echo "<br>";
        echo "日期:";print_r($row['Date']);echo "<br>";
        echo "商店ID:";print_r($row['ShopId']);echo "<br>";
        echo "商店名稱:";print_r($row['ShopName']);echo "<br>";
        print "======================================\n";echo "<br>";
        echo "商品ID:";print_r($row['ProdId']);echo "<br>";
        echo "商品名稱:";print_r($row['ProdName']);echo "<br>";
        echo "數量:";print_r($row['Qty']);echo "<br>";
        print "======================================\n";echo "<br>";
      //1.用 $row['Id'],$row['Date'],$row['Qa1'],$row['Qa2']顯示表頭
      //2.顯示表身標題列(Num, Id, Date... )
      //3.用 $row['Qa3'], $row['Qa4'], $row['Qa5'] 顯示表身資料列
      //4.將 Date 記錄下來
      $savekey = $row['Date'];
      } 
      else if ($row['Date'] == $savekey) {
        echo "商品ID:";print_r($row['ProdId']);echo "<br>";
        echo "商品名稱:";print_r($row['ProdName']);echo "<br>";
        echo "數量:";print_r($row['Qty']);echo "<br>";}
        $savekey = $row['Date'];
      //第二筆(含)以後
      //1.判斷該筆資料的 Date 是否等於 $savekey
      //1.a 如果不同,表示換日期了(要顯示表頭那一堆,即上面 $rowcnt==1 的 1.2.3.)      
      //1.b 如果相同,只需用 $row['Qa3'], $row['Qa4'], $row['Qa5'] 顯示表身資料列
      //2.將 Date 記錄下來
        // if ($row['Date'] == $savekey){
        // print "======================================\n";echo "<br>";
        // print_r($row['Id']);echo "<br>";
        // print_r($row['Date']);echo "<br>";
        // print_r($row['ShopId']);echo "<br>";
        // print_r($row['ShopName']);echo "<br>";}
        

       
    }



sqlsrv_free_stmt( $stmt);

?>
ayo0831 iT邦新手 5 級 ‧ 2016-10-29 23:58:24 檢舉

阿~~~~
我竟然...../images/emoticon/emoticon02.gif
我該怎麼刪除我的留言

但為什麼最後MOS 的可樂雪碧 會只跳一個出來?

因為你只寫了 1.b 而沒完成 1.a 的部份
除了「可樂」之外
你沒發現也沒有出現 2016-10-29 那一大段「表頭」嗎?

ayo0831 iT邦新手 5 級 ‧ 2016-10-30 00:28:56 檢舉

OK 感謝
我也是醉了~
我在研究看看
/images/emoticon/emoticon13.gif

ayo0831 iT邦新手 5 級 ‧ 2016-11-07 17:11:20 檢舉

真的很感謝 海綿寶寶
我問題已經OK了

如果問題解決了
就「選個最佳解答」
以便結束這一回合...

1
weiclin
iT邦高手 4 級 ‧ 2016-10-29 10:45:53

難得看到一個比較用心的發問, 就給你詳細一點的程式

首先按照你原本的表格設計方式, 可以這樣寫(注意我把表格欄位改名了):

query.php

<?php

$pdo = require_once "sample_db.php";

$records = $pdo->query("SELECT * FROM record;");
$prevId = $prevDate = $prevShopId = null;
$rowNum = 0;
foreach($records as $data) {
    if ($prevId !== $data["Id"]
        || $prevDate !== $data["Date"]
        || $prevShopId !== $data["ShopId"]
    ) {
        $rowNum = 0;
        $prevId = $data["Id"];
        $prevDate = $data["Date"];
        $prevShopId = $data["ShopId"];
    }

    if (0 === $rowNum++) {
        print "======================================\n";
        print "Num: {$data["Num"]}, Id: {$data["Id"]}, ";
        print "Date: {$data["Date"]}, ShopId: {$data["ShopId"]}, ";
        print "{$data["ShopName"]}\n";
    }
    print "--------------------------------------\n";
    print "{$data["ProdId"]}, {$data["ProdName"]}, {$data["Qty"]}\n";
}

在終端機執行, 輸出長這樣:

======================================
Num: 1, Id: AA1100, Date: 2016-10-28, ShopId: 123123, 麥當勞
--------------------------------------
FF33A, 漢堡, 1
--------------------------------------
HB77H, 薯條, 1
--------------------------------------
RGJ32, 蕃茄醬, 2
--------------------------------------
BBDDA, 糖醋醬, 3
======================================
Num: 5, Id: AA1100, Date: 2016-10-29, ShopId: 111111, MOS
--------------------------------------
RFAXS, 可樂, 5
--------------------------------------
HJKLA, 雪碧, 4

這是 sample_db.php, 只是建樣本資料, 可略過不看

<?php

$db_filename = "db.sqlite";
$db_exists = file_exists($db_filename);

$pdo = new PDO("sqlite:$db_filename", null, null);

if (!$db_exists) {
    $pdo->exec("CREATE TABLE record(Num INTEGER PRIMARY KEY, Id, Date, ShopId, ShopName, ProdId, ProdName, Qty);");
    $datas = array(
        array(
            'Id' => "AA1100",
            'Date' => "2016-10-28",
            'ShopId' => "123123",
            'ShopName' => "麥當勞",
            'ProdId' => "FF33A",
            'ProdName' => "漢堡",
            'Qty' => 1
        ),
        array(
            'Id' => "AA1100",
            'Date' => "2016-10-28",
            'ShopId' => "123123",
            'ShopName' => "麥當勞",
            'ProdId' => "HB77H",
            'ProdName' => "薯條",
            'Qty' => 1
        ),
        array(
            'Id' => "AA1100",
            'Date' => "2016-10-28",
            'ShopId' => "123123",
            'ShopName' => "麥當勞",
            'ProdId' => "RGJ32",
            'ProdName' => "蕃茄醬",
            'Qty' => 2
        ),
        array(
            'Id' => "AA1100",
            'Date' => "2016-10-28",
            'ShopId' => "123123",
            'ShopName' => "麥當勞",
            'ProdId' => "BBDDA",
            'ProdName' => "糖醋醬",
            'Qty' => 3
        ),
        array(
            'Id' => "AA1100",
            'Date' => "2016-10-29",
            'ShopId' => "111111",
            'ShopName' => "MOS",
            'ProdId' => "RFAXS",
            'ProdName' => "可樂",
            'Qty' => 5
        ),
        array(
            'Id' => "AA1100",
            'Date' => "2016-10-29",
            'ShopId' => "111111",
            'ShopName' => "MOS",
            'ProdId' => "HJKLA",
            'ProdName' => "雪碧",
            'Qty' => 4
        ),
    );

    foreach ($datas as $data) {
        $sql = <<<END_SQL
            INSERT INTO record(Id, Date, ShopId, ShopName, ProdId, ProdName, Qty)
            VALUES(
                '{$data["Id"]}',
                '{$data["Date"]}',
                '{$data["ShopId"]}',
                '{$data["ShopName"]}',
                '{$data["ProdId"]}',
                '{$data["ProdName"]}',
                '{$data["Qty"]}'
            );
END_SQL;

        $pdo->exec($sql);
    }
}

return $pdo;

但是你這資料表的設計, 如果要打分數的話, 只能給你 50 分不及格。因為你完全沒有做正規化。
這邊不跟你解釋什麼叫正規化, 網路上隨便搜尋都有資料, 自己去查。

我直接給你一個對購買清單正規化的範例, 注意這個範例沒有把正規化做完, 只做了一小步而已:

sample_db2.php

<?php

$db_filename = "db2.sqlite";
$db_exists = file_exists($db_filename);

$pdo = new PDO("sqlite:$db_filename", null, null);

if (!$db_exists) {
    $pdo->exec("CREATE TABLE record(Num INTEGER PRIMARY KEY, Id, Date, ShopId, ShopName);");
    $pdo->exec("CREATE TABLE items(fk_Num, ProdId, ProdName, Qty)");

    $pdo->exec("INSERT INTO record(Id, Date, ShopId, ShopName) VALUES ('AA1100', '2016-10-28', '123123', '麥當勞')");
    $fk_Num = $pdo->lastInsertId();
    $pdo->exec("INSERT INTO items VALUES ($fk_Num, 'FF33A', '漢堡', 1)");
    $pdo->exec("INSERT INTO items VALUES ($fk_Num, 'HB77H', '薯條', 1)");
    $pdo->exec("INSERT INTO items VALUES ($fk_Num, 'RGJ32', '蕃茄醬', 2)");
    $pdo->exec("INSERT INTO items VALUES ($fk_Num, 'BBDDA', '糖醋醬', 3)");

    $pdo->exec("INSERT INTO record(Id, Date, ShopId, ShopName) VALUES ('AA1100', '2016-10-29', '111111', 'MOS')");
    $fk_Num = $pdo->lastInsertId();
    $pdo->exec("INSERT INTO items VALUES ($fk_Num, 'RFAXS', '可樂', 5)");
    $pdo->exec("INSERT INTO items VALUES ($fk_Num, 'HJKLA', '雪碧', 4)");
}

return $pdo;

這樣子做, 你的資料庫就會有兩個表格, 一個紀錄消費的時間及店家資料, 另一個紀錄消費內容。兩個表格利用 Num 與 fk_Num 做關聯查詢, 最後出來的可以跟你原本表格的內容一模一樣。

例如利用 join 來處理, 這邊除了 sql 語法變了, 其餘程式都沒有變動:

query2.php

<?php

$pdo = require_once "sample_db2.php";

$records = $pdo->query("SELECT record.*, items.* FROM record LEFT JOIN items ON record.Num = items.fk_Num;");
$prevId = $prevDate = $prevShopId = null;
$rowNum = 0;
foreach($records as $data) {
    if ($prevId !== $data["Id"]
        || $prevDate !== $data["Date"]
        || $prevShopId !== $data["ShopId"]
    ) {
        $rowNum = 0;
        $prevId = $data["Id"];
        $prevDate = $data["Date"];
        $prevShopId = $data["ShopId"];
    }

    if (0 === $rowNum++) {
        print "======================================\n";
        print "Num: {$data["Num"]}, Id: {$data["Id"]}, Date: {$data["Date"]}, ";
        print "ShopId: {$data["ShopId"]}, {$data["ShopName"]}\n";
    }
    print "--------------------------------------\n";
    print "{$data["ProdId"]}, {$data["ProdName"]}, {$data["Qty"]}\n";
}

最後再給你一點提示, 你的商店名稱跟商品名稱都需要正規化。而正規化請 "至少" 做到 3NF 才及格。

另外以上的程式需要在 php 5.4 以上, 且有安裝 pdo 與 sqlite 的環境才能運作。

看更多先前的回應...收起先前的回應...

難得看到一個比較用心的發問

+1

ayo0831 iT邦新手 5 級 ‧ 2016-10-30 00:20:12 檢舉

很感謝weiclin的協助,我也嘗試在研究各位的程式碼
我想在請問 如何嘗試不用sample_db.php 去呼叫資料
直接透過SELECT * FROM dbo.table1 WHERE id = 'AA11**'去抓所有的資料
並將資料做成陣列

while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {

程式怎麼改會比較好

weiclin iT邦高手 4 級 ‧ 2016-10-30 07:59:32 檢舉

sample_db.php 那個只是我用來建立樣本資料用的而已, 實際上你只要看 query.php 裡面的邏輯即可。因為我用的是 sqlite 資料庫當範例, 所以你會覺得看起來怎麼不一樣, 但用的都是 sql。雖然語法可能有點差異, 但只用到很基本的功能所以查一下應該都能作到。

幫你劃重點, 我的這兩行:

$records = $pdo->query("SELECT * FROM record;");
foreach($records as $data) {

跟你的這兩行對應, 一行是在查詢, 另一行是對查詢結果做處理。:

$stmt = sqlsrv_query( $conn, $sql );
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {

另外 $data 跟 $row 變數名稱雖然不一樣, 但其實是一樣的東西。$rowNum 跟 $rowcnt 也是差不多用意, 但我的寫法 $rowNum 在第一筆會是 0。重點是其中的邏輯, 那就是你要的東西。

ayo0831 iT邦新手 5 級 ‧ 2016-11-07 17:10:52 檢舉

感謝 weiclin,
我現階段的已經問題解決了
真的很感謝

weiclin iT邦高手 4 級 ‧ 2016-11-07 19:08:11 檢舉

解決就好, 加油吧

我要發表回答

立即登入回答