顯示具有 mysql 標籤的文章。 顯示所有文章
顯示具有 mysql 標籤的文章。 顯示所有文章

2022年5月12日 星期四

MySQL 移除重複資料

資料表[data]欄位: [id] [A欄][B欄] [C欄][D欄]

當有多筆資料的A, B, C三個欄位相同時,只保留一筆的語法。


原本以為用用A, B, C 三個欄位group by ,找出count > 1的資料即為重複的所有資料筆數。

語法:

SELECT *

FROM data

GROUP BY A, B, C

HAVING count(id)  > 1


但是發現這樣找出來的資料僅顯示一筆資料,其他筆數不會顯示。

例如: 

[1][蘋果][日本][50g][0210]

[2][香蕉][台灣][500g][0220]

[3][蘋果][日本][50g][0310]

[4][蘋果][日本][50g][0410]

[5][香蕉][台灣][500g][0310]


以上五筆資料,透過上述語法查詢 結果如下:

[1][蘋果][日本][50g][0210]

[2][香蕉][台灣][500g][0220]


這個結果反而是重複筆數中要保留的資料!

另外要保留的是,不重複的資料,也就是只有一筆的資料

語法:

SELECT *

FROM data

GROUP BY A, B, C

HAVING count(id)  = 1


因此兩種結果是要保留的,因此就是排除以上兩種結果的資料,

剩下的就是要刪除的,可先用Select選出來檢查。

SELECT * FROM data

WHERE 

id NOT IN 

( SELECT id FROM data GROUP BY A, B, C HAVING count(id) > 1 ) 

AND

id NOT IN 

( SELECT id FROM data GROUP BY A, B, C HAVING count(id) = 1 )


確認以上篩選出的結果是要刪除得,再把SELECT改成DELETE就可以了。


---------------------------------------------------------------------------------

篩選出某個欄位重複值的資料

SELECT * FROM table WHERE colName IN (SELECT colName FROM table GROUP BY colName HAVING count(colName ) > 1) ORDER BY colName 


2020年9月24日 星期四

Ubuntu 18.04. 安裝php7.2, mysql


安裝php:

sudo apt update

安裝php相關套件:

sudo apt install php php-cli php-fpm php-json php-pdo php-mysql php-zip php-gd php-mbstring php-curl php-xml php-pear php-bcmath

查看php版本:

php -v

Ubuntu18.04的php會預設為php7.2版本。


安裝mysql

sudo apt install mysql-server 

sudo apt install mariadb-server-core(安裝在數莓派上要用這個)

安裝後預設密碼空白,需要修改mysql root 密碼

sudo mysql -uroot -p 

進入mysql後輸入以下指令來設定root帳號密碼

mysql>SET PASSWORD FOR 'root'@'localhost' = PASSWORD('pi&metrackPI');

ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('pi&metrackPI');


>flush privileges;


變更密碼指令:

SET PASSWORD FOR '[帳號]'@'localhost' = PASSWORD('[密碼]');


修改mySQL設定
- 預設MySQL是只允許本機存取,因此要修改成允許遠端存取
-  sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
-  將blind-address這一行的IP改成自己要遠端的IP,若不限制可以加上#註解掉
-在[mysqld]區塊中加上character-set-server=utf8 

啟動mySQL
-輸入指令:sudo systemctl start mysql
- 查看運作狀況service mysql status


安裝phpmyadmin

sudo apt install phpmyadmin

php7.2以後的phpmyadmin有些問題,因此都會出現錯誤訊息;小弟尚未查到完整修改的方式,

但因為不引響實際網站存取資料庫問題,因此就先不管了。

若朋友有解法分享,小弟萬分感謝。

設定phpmyadmin連結網址:

sudo ln -s /usr/share/phpmyadmin /var/www/html/[例:phpmyadmin]


設定mysql使用者允許遠端連線(視需求設定)

若mysql在遠端環境,則需要允許遠端連線,可將以下指令IP改為%,或指定特定IP,若為本機用戶則輸入localhost。

允許遠端連線帳號權限,進入mysql後

mysql>GRANT ALL PRIVILEGES ON *.* TO '[帳號]'@'IP' IDENTIFIED BY '[密碼]';

更新權限

mysql>flush privileges;


PS. 若是由程式讀取本機資料庫,使用者可設定為Localhost,程式端的資料庫位置也要localhost才行。


2020年8月6日 星期四

JQuery ajax post, php接收,回傳資料

花了些時間研究圖片上傳功能。
前端將圖片轉成Base64後,透過ajax post傳到後端php程式,由程式寫入資料庫並產生圖片路徑,再回傳圖片路徑資料給前端。

前端程式:
Head設定語系跟載入jquery
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
</head>

HTML:包含一個編號、一個選擇圖片功能,一個上傳按鈕,還有一個顯示回傳資料的欄位
<html>
    <form>
        <label> 編號
            <input id="pid" type="text"/>
        </label>
        <label> 圖檔:</label>
        <label class="btn_img">請選擇圖片
            <input id="upload_img" type="file">
        </label>
        <div class="edit_form_img">
            <img id="img_preview" />
        </div>
        <input id="sent" class="form_submit" type="button" value="submit" ></input>
    </form>
    <label id="info"></label>
</html>

JS:將選擇的圖片轉成base64並產生預覽
    $("#upload_img").change(function() {
        //readURL(this);//互叫變更預覽圖片的功能
        //取得file選擇的檔案
        pv_img = $("#upload_img").get(0).files[0];
        //新增reader物件轉成base64資料,再onload時寫入圖片的scr
        var reader = new FileReader();
        reader.onload=function(){
            $("#img_preview").attr('src',reader.result);
        }
        reader.readAsDataURL(pv_img);
    });

JS 當上傳按鈕被點擊後,取得資料,並透過ajax Post到php
-這裡偷懶取代base64資料前的資料描述文字,但比較好的作法應該是要另外存檔案格式,之後轉回圖片時再加上附檔名(這動作可以在php端處理,也可以在前端)
-processData這個參數有點神奇,當true時data參數才能正確傳到php端,false就不行了;但網路上有些範例卻說要用false。若有大大知道原理,還忘不吝告知,感恩喔!
-data的傳送方式試過傳送form序列化或json.stringfy,但資料還是送不出去;這邊提供傳送成功的方式跟php接收的程式有關係。
- 取回php回傳的陣列資料,先抓兩個欄位顯示出來。

    $('#sent').click(function(){
        img64=$("#img_preview").attr("src");
        sb64=img64;
        //取代編碼後前面的描述文字
        sb64= sb64.replace("data:image/jpeg;base64,",''); 
        $.ajax({
            url:'jsonPHP.php',
            type: 'POST',
            processData: true, //false時,data參數無法傳到php POST接收端,true時才可以
            dataType: "json",
            //傳送data參數值
            data: { 'pid':$("#pid").val(),     
                    'sb64':sb64
                },
            success: function(data){
                console.log(data);
                //取回php回傳的陣列資料
                    var imgsNum=data.length;
                    for (i=0;i<imgsNum;i++){
                        imgid=data[i]['img_id'];
                        imgurl=data[i]['img_url'];
                        $("#info").append("id:"+imgid+"|url:"+imgurl);
                    }
                },
        });  
    });

PHP程式
- 取得前端傳遞的資料後,呼叫寫入資料的程式,再透過查詢回傳同個編號的圖片資料
- Insert_img 先將base64資料轉成圖片,我去抓一個時間當作檔名(這是另外引入的函式),再將資料存到資料庫
- query_img查詢同個ID的資料,存成陣列後回傳。


<?php
    header('Content-Type: application/json; charset=UTF-8');
    require_once("fundation_func.php");
    $link = new mysqli($dbhost,$dbuser,$dbpass,$db);

    //偵測POST的資料與前端ajax參數有關,要對應才行
    if ($_SERVER['REQUEST_METHOD'] == "POST"){
        @$id=$_POST["pid"];
        //@$name=$_POST["name"];
        @$sb64=$_POST["sb64"];
        $msg="取得pid:".$id;
        echo json_encode(insert_img($link, $id,$sb64));
    }else
    {
        $msg="request錯誤";
        echo json_encode(array(
            'msg'=> $msg
        ));
    }

    function insert_img($link,$product_id,$sb64){
        //產生圖片路徑
        $img_file=base64_decode($sb64);
        $file_name=get_pure_text(get_file_no());
        $file_url="product_imgs/".$product_id."_".$file_name.".jpg";
        file_put_contents($file_url, $img_file);

        //新增產品圖片資料的SQL
            $sql="INSERT INTO product_img(product_id, imgb, img_url) VALUES ('$product_id','$sb64','$file_url')";
            $link->query($sql);
        //查詢產品圖片
        return query_img($link,$product_id);
    }

//查詢同個ID的圖片函式,會回傳一個陣列
    function query_img($link,$product_id){
        $imgs_array=array(
            array('img_id','img_url'),
        );
        $sql="SELECT img_id, img_url FROM product_img WHERE product_id=$product_id";
        $result=$link->query($sql);
            $i=0;
            while($row=$result->fetch_array(MYSQLI_ASSOC)){
                //將查到的產品圖片存到array中
                $imgs_array[$i]=array(
                        'msg'=>"ss",
                        'img_id'=>$row['img_id'],
                        'img_url'=>$row['img_url']
                );
                $i++;
            }
            return $imgs_array;
    }
?>



2020年7月13日 星期一

mysqli::query(): Couldn't fetch mysqli 問題排除紀錄

發生了幾次mysqli::query(): Couldn't fetch mysqli 的錯誤,
紀錄解決方式如下:

原因一: SQL語法有錯
- 將查詢語法輸出,再把輸出的SQL放到mysql中執行看看結果是否正確
- 發生了where欄位條件='xxx' 沒加上'',int的時候不用''


原因二: 太早結束連線時,導致接續的查詢出錯
- 先查詢資料重複再插入新資料時,若在查詢重複資料時就結束連線,就會出現錯誤。

$sql->query(查詢)
$sql->close()  //這時就會出錯,移除這一個步驟的Close()就可以排除問題

$sql->query(插入資料)
$sql->close()

mysql, php取得特定字串

透過mysql語法取得欄位中的部分字串:

左邊取得特定[文字長度]
SELECT [欄位名], LEFT([欄位名] ,[文字長度]) FROM [資料表] WHERE [條件]
例: SELECT content, LEFT(content,50) FROM contacts 

從右取得特定[文字長度]
SELECT [欄位名], RIGHT([欄位名] ,[文字長度]) FROM [資料表] WHERE [條件]
例: SELECT content, LEFT(content,50) FROM contacts 

透過php語法取得欄位中的部分字串:
mb_substr([字串], [起始位置], [取得長度], [編碼])
例: 
$str="abcd甲乙丙0987654321";
$sub=mb_substr($str, 2, 5, "utf8");
echo "sub=$sub";

輸出結果: sub=cd甲乙丙

2020年6月14日 星期日

PHP- 預防SQL injection 字串處理"htmlentities"、"stripslashes"、"real_escape_string"

要避免網頁輸入欄位的SQL injection,基本的方式是針對輸入欄位、POST、GET..
等數值進行處理。

htmlentities():去除字串中的html標籤
stripslashes():讓文字及符號呈現原始輸入的文字,不受html語法影響
real_escape_string():轉換特殊符號

可參考以下範例試試看:
<html>
<form action="trail_string_clear.php" method="post" name="textform">
原始輸入<br>
<textarea id="editor1" name="inputtext" type="textarea" style="width:400px;height:200px;"></textarea><br>
<input class="form_submit" type="Submit" value="Submit"></input>
</form>


</html>

<?php
require_once("fundation_func.php");
$link = new mysqli($dbhost,$dbuser,$dbpass,$db);
$inputtext=$_POST['inputtext'];
$stripslashes=htmlentities($inputtext);
$htmlentities=stripslashes($inputtext);
$real_escape_string=$link->real_escape_string($inputtext);
echo "<font color='black'>未處理字串:$inputtext<br></font>";
echo "<font color='blue'>stripslashes處理後:$stripslashes<br></font>";
echo "<font color='red'>htmlentities處理後:$htmlentities<br></font>";
echo "<font color='green'>real_escape_string處理後:$real_escape_string<br></font>";
?>



輸出畫面:


輸入的字串





2020年6月2日 星期二

Ubuntu 安裝php、mysql、phpmysdmin

記錄常用的Ubuntu安裝動作,
將安裝php、mySQL、phpmyadmin

安裝PHP、Apache
sudo apt-get update
sudo apt-get install apache2 php libapache2-mod-php
安裝後網站路徑為/var/www/html/

修改php.ini設定
設定檔路徑:
sudo vi /etc/php/7.0/apache2/php.ini

extension設定

-extension=php_mbstring.dll

-extension=php_mysqli.dll
檔案上傳設定
-upload_file_maxsize=20MB
-upload_max_filesize = 20M
開發時錯誤顯示,避免發生錯誤時只顯示空白畫面
-display_errors=On

安裝mySQL
$ sudo apt-get install mysql-server
//$ sudo apt-get install mysql-client
//以下為資安考量安裝可省略
//$mysql_secure_installation 
- 會開始設定root的密碼,以及密碼安全性的檢核程度;建議根據已設定密碼的強度來選擇
- 選擇是否要允許遠端;視情況囉
- 選擇是否要移除測試資料庫;建議移除
- 確認重新載入權限表

修改mySQL設定
- 預設MySQL是只允許本機存取,因此要修改成允許遠端存取
-  sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
-  將blind-address這一行的IP改成自己要遠端的IP,若不限制可以加上#註解掉
-在[mysqld]區塊中加上character-set-server=utf8 

設定mySQL root密碼
- 預設mySQL root 密碼為空白需變更,
-sudo mysql -uroot -p
- 進入mysql開始變更root帳號密碼
- >UPDATE mysql.user SET authentication_string=PASSWORD('[密碼]'), plugin='mysql_native_password' WHERE User='root' AND Host='localhost';
- >flush privileges;
- exit;


啟動mySQL
-輸入指令:sudo systemctl start mysql
- 查看運作狀況service mysql status

安裝php-MySQL套件
- 輸入指令:sudo apt install php-mysql

安裝phpMyAdmin
$ sudo apt-get install phpmyadmin
//$ sudo apt-get install php-mbstring

//$ sudo apt-get install php-gettext
- 安裝後會出現設定phpmyadmin的密碼

phpmyadmin設定
設定檔路徑
$sudo vi /etc/dbconfig-common/phpmyadmin.conf
dbc_dbuser='[帳號]'
dbc_dbpass='[密碼]'


在www中設定連結
$ sudo ln -s /usr/share/phpmyadmin /var/www/html/phpmyadmin

啟動apache
- 輸入指令:sudo apachectl start
*如有變更php.ini或mysql設定,需要重新啟動 sudo apachectl restart

測試:
1) php執行: 輸入 [localhost/ip]/
2) phpmyadmin: [localhost/ip]/phpmyadmin
3) 檢查mySQL語系設定,確認是否有非UTF8的語系 
-show variables where Variable_name like '%character_set%'
utf8mb4 兼容UTF8



2020年4月21日 星期二

網站摸索筆記:MySQL 插入中文問題

MySQL 可能因為語系導致寫入資料錯誤,因此需要變更語系設定為UTF-8。

以下列出可能導致中文寫入失敗的部分:
1) 欄位設定
- 一執行insert 指令就會出現某個欄位寫入失敗,建議可以先試試變更欄位語系
- 指令:alter table [資料表名稱] change [原欄位名稱] [新欄位名稱] [資料型態] [語系設定]- 例:alter table product change content content varchar(500) character set utf8;

2) MySQL 設定
- 也許變更資料欄位後問題就解決了,但建議還是檢查一下MySQL設定

-進入後改這一段
[mysqld]
character-set-server=utf8

3) 資料庫設定
- 進入mysql後,可使用以下指令檢查是否有設定不是utf-8
- show variables where Variable_name like '%character_set%';


4) 資料表設定
- 可以透過以下指令查看資料表語系設定
- show create table [資料表名稱]
例:show create table product;

- 變更資料庫語系指令:alter database [資料庫名稱] character set utf8
例:alter database mydb character set utf8

- 變更資料表語系指令:alter table [資料表名稱] character set utf8
例:alter table product character set utf8




2020年4月17日 星期五

網站摸索筆記:MySQL 入門常用指令

整理幾個基本指令

進入MySQL:mysql -r [username] ip [password]; 
- 進入後會看到

離開MySQL:mysql>exit;

查看目前版本:mysql>select version();

顯示目前資料庫:show databases;
- 會列出目前的資料庫

建立資料庫:create database [資料庫名稱],例:create database mydb;
-建立後可再用show databases; 查詢

使用資料庫:use [資料庫名稱],例:use mydb;
- 選擇資料庫後就可使用針對資料庫的資料表操作

顯示目前資料庫:show tables;
- 會列出資料庫mydb中的資料表

建立資料表:create table [資料表名稱](欄位名 屬性 資料型態, 欄位名 資料型態... ),
例:create table test_tb(id integer auto_increment primary key, description varchar(256), po_time datetime);
- 欄位id: integer- 資料型態為整數, auto_increment- 自動增加(整數+1),primary key(資料表索引)
- 欄位description: varchar(256)資料型態為字串,最大長度為256bytes
- 欄位po_time: 資料型態為日期(yyyy-mm-dd hh:mm:ss)

顯示資料表欄位:describe [資料表名稱]
- 列出資料表中的欄位定義


修改欄位名稱、定義:alter table [資料表名稱] change [原欄位名稱] [新欄位名稱] [資料型態]
例:alter table test_tb change po_time post_date date

新增欄位:alter table [資料表名稱] add column ([新欄位名稱] [資料型態])
例:alter table test_tb add column(ps varchar(10));

移除欄位:alter table [資料表名稱] drop column [欄位名稱]
例:alter table test_tb drop column ps;

清空資料表:truncate table [資料表名稱]
- 刪除資料表中的資料內容,資料表欄位不變

刪除資料表:drop table [資料表名稱]

插入欄位資料:insert [資料表名稱] ([欄位名稱], [欄位名稱]...) value('欄位值', '欄位值'..)
例:insert test_tb (name) value('insert from sql');

查詢欄位資料:select  [欄位名稱], [欄位名稱]... from [資料表名稱]]
例:select name,id from test_tb;

查詢所有欄位資料:select * from [資料表名稱]]
例:select * from test_tb;

條件式查詢:select * from [資料表名稱] where (條件1 and/or 條件2)
例1:select * from test_tb where id>1 and id<5  (兩個條件取交集)
例2:select * from test_tb where id<3 or id>5; (兩個條件取聯集)
例3:select * from test_tb where id=3; (等於單一條件)
例4:select * from test_tb where id between 3 and 5; (介於兩個數值之間)

查詢結果資料排序:select * from [資料表名稱] order by  [欄位名稱]
例1:select * from test_tb order by name; (由小->大)
例2:select * from test_tb order by name desc; (由大->大)

以字串查詢欄位內容:select [欄位名稱] from [資料表名稱] where [欄位名稱] like [字串]
例1:select name from test_tb where name like '33'; (字串完全相等於33才會查出)
例2:select name from test_tb where name like '%33%'; (字串包含33就會查出)

刪除欄位資料:delete from [資料表名] where (條件1 and/or 條件2)
例1:delete from test_tb where id=3;
例2:delete from test_tb where id=2 or name like '%33%';

編輯欄位資料:update [資料表名] set [欄位名稱]='欄位值' where(條件1 and/or 條件2)
例:update product set product_content='產品內容文字' where product_id= 4;


2020年4月14日 星期二

網站摸索筆記:PHP讀取網站設定.ini檔

網站在本機開發後,要部屬到伺服器上,
不同環境的DB連線資訊有些不同,因此想將網站設定檔獨立為本機、伺服器兩份,
這樣就不用再因環境不同而修改程式。

新增一個.ini檔案紀錄DB,內容如下:
[database]
db_name'mydb'
db_user'root'
db_password'[root帳號的密碼]'
db_url='localhost:3306'
- [database]: 這是sction,區分ini檔中的各區塊
- 其下的db_name、db_user、db_password、db_url都是參數
- 儲存檔名為 "webconfig.ini"

新增一個php檔案,內容如下:
<?php
//使用parse_ini_file來讀取.ini檔案,會以陣列的方式來存放內容
$ini = parse_ini_file('webconfig.ini',true);

//ini中的sction與參數名會變成陣列的索引 $ini[secion][參數名]
$db=$ini["database"]["db_name"];
$dbhost=$ini["database"]["db_url"];
$dbuser=$ini["database"]["db_user"];
$dbpass=$ini["database"]["db_password"];

//分行列印讀取的陣列資料
echo '<pre>',print_r($ini);'</pre>';

//使用mysqli_connect()來進行DB連線
$link=mysqli_connect($dbhost,$dbuser,$dbpass);
if(! $link) {
    die ('DB連線失敗'mysqli_error($link));
}
echo 'DB連線成功';
?>
- 使用函式 parse_ini_file(),詳見手冊https://www.php.net/manual/en/function.parse-ini-file.php
- 使用print_r()來顯示陣列資料,參閱手冊https://www.php.net/manual/en/function.print-r.php

從瀏覽器看會看到如下畫面

* 透過webconfig.ini區分兩個環境所存取的DB位置
- 對在Google Cloud Platfom上的VM程式來說就是存Localhost的資料庫
- 本機開發則是透過IP連到遠端的DB


2020年4月12日 星期日

網站摸索筆記:GCP 安裝MySQL與設定

GCP VM安裝php, Apache後,再來安裝MySQL;
並讓開發的遠端可以連到MySQL中,這樣開發完成後再把網頁放到VM就上線了。

安裝MySQL
-輸入指令:sudo apt-get install mysql-server 

設定MySQL連線
-輸入指令:mysql_secure_installation 
- 會開始設定mysql的帳號root的密碼
- 以及密碼安全性的相關設定

啟動MySQL
-輸入指令:sudo systemctl start mySQL

確認MySQL服務
- 輸入指令:systemctl status mysql.service
- 出現如下Active 的資訊就表示服務啟動了


修改MySQL設定
- 預設MySQL是只允許本機存取,因此要修改成允許遠端存取
-  sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
- 將blind-address這一行的IP改成自己要遠端的IP,若不限制可以加上#註解掉



重新啟動MySQL
-輸入指令:sudo systemctl restart mySQL

嘗試登入SQL
- 輸入指令:mysql -u root -p
- 再輸入root帳號的密碼,看到以下畫面表示登入成功
- 輸入exit; 離開SQL


安裝php-MySQL套件
- 輸入指令:sudo apt install php-mysql
- 這動作安裝後php存取mysql的程式才能正常運作


接著設定VM的防火牆連線3306
- 因為會在本機開發,連到GCP上的資料庫,所以要調整VM設定
- 點擊GCP選單中的VPC網路>防火牆規則


-新增防火牆規則


-防火牆設定
 輸入名稱、說明,流量方向要選輸入

- 設定目標標記來建立VM跟防火牆規則的關連
  如下在VM中的網路標記就要加上dbserver,VM就會套用這個防火牆規則

測試telnet 
- 完成設定後可以從本機命令提示字元telnet [IP] 3306來測試
- 看到以下畫面就表示可以從本機連線到GCP的資料庫了


測試PHP 存取資料庫
- 以下PHP範例可測試資料庫連線
- sudo vi /var/www/html/dbconnect.php
<?php
$dbhost='localhost:3306';
$dbuser='root';
$dbpass='[root帳號的密碼]';
$link=mysqli_connect($dbhost,$dbuser,$dbpass);
if(! $link) {
    die ('DB連線失敗'. mysqli_error($link));
}
echo 'DB連線成功';
?>
- 出現DB連線成功就表示完成PHP與MySQL的環境設定


接下來就可以在不同電腦上開發程式,然後都連GCP的資料庫了。