2009-03-31

REPLACE INTO 和 INSERT INTO 的區别[MySQL]

REPLACE 與INSERT 在 Syntax 及功能上都很類似
在插入資料遇到 PRIMARY KEY 或 UNIQUE KEY 碰撞時
REPLACE 會將原本的資料刪除再執行新增的動作

這裡特別要注意的是會將資料刪除
並不只是使用複寫方式去處理的

利用 REPLACE for SELECT 來處理資料真的很方便
不必擔心資料碰撞的問題
但請記得 REPLACE 的特性
有時候事情不是想像中那麼快樂的

REPLACE Syntax:
REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name [(col_name,...)]
    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...

-- 或:

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...

-- 或:

REPLACE [LOW_PRIORITY | DELAYED]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...


參考來源:
MySQL Replace INTO的使用
MySQL 5.0 REPLACE Syntax

將查詢結果更新至資料表 UPDATE for SELECT [MySQL]

今天又學到一個 MySQL 新方法,原本就在找利用 SELECT 的結果 UPDATE 至資料表的方法,最後終於在 MySQL 官網中的回應裡找到了
UPDATE
    `t1` AS A,
    (SELECT `b1`, COUNT(*) AS `total` FROM `t2` GROUP BY `c1`) AS B
SET A.`a2`=B.`total`
WHERE A.`a1`=B.`a1`


MySQL5.0: UPDATE Syntax
2009-03-29

iGoogle 小工具製作心得

iGoogle 小工具主要是以 XML 為主體,再加上 HTML、CSS 及 JavaScript 所組成的,基本上只要會後面三種語言,要開發 iGoogle 小工具是非常快樂的一件事。

在這裡我只做一些的教學及心得分享,詳細的規範及 API 說明,請察看官方網站 Google 小工具 API 開發人員指南,開發指南裡面寫的很清楚,還有很多的範例可以參考。

心得建議:
  • 開發時建議 XML 的檔名不要太正式,iGoogle 的平台會 cache XML,造成檢視上會出現不一致情況,等到要發佈時再取一個正式的檔名,避免不必要的問題發生。
  • 如果要使用 session 和 cookie 做登入驗證的話,最好使用 <iframe> 去處理,會比較容易達成且安全問題也比較少。
  • 在 ModulePrefs 中的 category 屬性也記得加上去,在官方的開發人員指南中並沒有說明,共有:
    • politics
    • tools
    • funandgames
    • lifestyle
    • finance
    • communication
    • 等...。

  • 多利用[便條簿]做測試可以減少不少時間。
  • 測試時最好在 iGoogle 上另開一個[分頁],免得自己原本常用的小工具被打亂。
  • 在測試的[分頁]中最好加上[開發人員小工具]這個小工具去管理 cache 問題。

小工具範例:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs
title="單位換算"
description="更方便的介面處理單位制度上的換算"
directory_title="單位換算"
author="Jax"
author_email="weskerjax+feed@gmail.com"
thumbnail=
"http://weskerjax.googlepages.com/unit_converter_thumbnail.png"
screenshot=
"http://weskerjax.googlepages.com/unit_converter_screenshot.png"
title_url="http://jax-work-archive.blogspot.com/"
category="tools"
height="300">
<Locale lang="zh-tw" country="TW"/>
<Require feature="tabs"/>
<Require feature="dynamic-height"/>
</ModulePrefs>
<UserPref
name="type"
display_name="預設開啟的頁籤"
default_value="長度"
datatype="enum">
<EnumValue value="長度"/>
<EnumValue value="重量"/>
<EnumValue value="面積"/>
<EnumValue value="體積"/>
</UserPref>
<Content type="html">
<![CDATA[
<style type="text/css">
.JContent table{
margin-top:5px;
width:100%;
}
.JContent th{
background-color:#99CCFF;
padding-top:5px;
}
.JContent label{
text-align:center;
padding:3px;
display:block;
font-size:12px;
}
.JContent label input{
display:block;
text-align:left;
line-height:1.1em;
font-size:11px;
width:95%;
}
</style>
<script type="text/javascript">
var prefs = new _IG_Prefs(__MODULE_ID__);
function set_event__MODULE_ID__(tabId){
var inputs=_gel(tabId).getElementsByTagName('input');
for (var i=0, j=inputs.length; i<j; i++){
el=inputs[i];
/*設定 onkeyup 時處理單位換算*/
el.onkeyup=function(){
this.value=this.value.match(/[0-9]+[\.]?[0-9]*/);
var rate=this.getAttribute('rate');
var value=parseFloat(this.value)/parseFloat(rate);

var table=this;
while(table.tagName!="TABLE"){table=table.parentNode;}

var inputs=table.getElementsByTagName('input');
for (var i=0, j=inputs.length; i<j; i++){
chg=inputs[i];
r=chg.getAttribute('rate');
if(r==rate){continue;}

if(this.value){chg.value=value*parseFloat(r);}
else{chg.value='';}
};
};
/*設定 onfocus 選取所有文字*/
el.onfocus=function(){this.select()};
};
/*讓小工具能夠自行調整大小*/
_IG_AdjustIFrameHeight();
}
function init() {
/*建立頁籤並選定預選頁籤*/
var tabs = new _IG_Tabs(__MODULE_ID__,prefs.getString("type"));
tabs.addTab("長度","J_length",set_event__MODULE_ID__);
tabs.addTab("重量","J_weight",set_event__MODULE_ID__);
tabs.addTab("面積","J_area",set_event__MODULE_ID__);
tabs.addTab("體積","J_volume",set_event__MODULE_ID__);
}
_IG_RegisterOnloadHandler(init);/*載入時呼叫的事件處理常式*/
</script>
<div class="JContent" id="J_length">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>公尺<input rate="1" type="text" /></label></td>
<td><label>公里<input rate="0.001" type="text" /></label></td>
<td><label>海里<input rate="0.00053996" type="text" /></label></td>
<tr>
<td><label>英吋<input rate="39.370" type="text" /></label></td>
<td><label>英呎<input rate="3.2808" type="text" /></label></td>
<td><label>英碼<input rate="1.0936" type="text" /></label></td>
</tr>
<td><label>台尺<input rate="3.3003" type="text" /></label></td>
<td><label>市里<input rate="2e-3" type="text" /></label></td>
<td><label>市引<input rate="0.03" type="text" /></label></td>
</tr>
</table>
</div>
<div class="JContent" id="J_weight">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>公斤<input rate="1" type="text" /></label></td>
<td><label>公克<input rate="1e+3" type="text" /></label></td>
<td><label>公噸<input rate="1e-3" type="text" /></label></td>
</tr>
<tr>
<td><label>英磅<input rate="2.2046" type="text" /></label></td>
<td><label>盎司<input rate="35.273" type="text" /></label></td>
<td><label>英噸<input rate="9.8421e-4" type="text" /></label></td>
</tr>
<tr>
<td><label>美噸<input rate="0.0011023" type="text" /></label></td>
<td><label>格令<input rate="15432" type="text" /></label></td>
<td><label>克拉<input rate="5000" type="text" /></label></td>
</tr>
<tr>
<td><label>台斤<input rate="1.6667" type="text" /></label></td>
<td><label>台兩<input rate="26.667" type="text" /></label></td>
<td><label>市擔<input rate="0.02" type="text" /></label></td>
</tr>
</table>
</div>
<div class="JContent" id="J_area">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>公畝<input rate="100.00" type="text" /></label></td>
<td><label>公頃<input rate="1" type="text" /></label></td>
<td><label>平方公里<input rate="0.01" type="text" /></label></td>
</tr>
<tr>
<td><label>平方英寸<input rate="155e+5" type="text" /></label></td>
<td><label>平方英尺<input rate="107640" type="text" /></label></td>
<td><label>平方碼<input rate="11960" type="text" /></label></td>
</tr>
<tr>
<td><label>英畝<input rate="2.4711" type="text" /></label></td>
<td><label>平方英里<input rate="0.003861" type="text" /></label></td>
<td> </td>
</tr>
</table>
</div>
<div class="JContent" id="J_volume">
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td><label>立方公尺<input rate="1" type="text" /></label></td>
<td><label>公升<input rate="1e+3" type="text" /></label></td>
<td><label>毫升<input rate="1e+6" type="text" /></label></td>
</tr>
<tr>
<td><label>英國加侖<input rate="219.97" type="text" /></label></td>
<td><label>液體加侖<input rate="264.17" type="text" /></label></td>
<td><label>固體加侖<input rate="227.02" type="text" /></label></td>
</tr>
</table>
</div>
]]>
</Content>
</Module>


範例預覽:

範例原始檔:unit_converter.xml


第一個開發的小工具:
2009-03-27

[PHP] 利用表單傳遞多維陣列

有時候在表單傳遞上會需要具有結構性的變數傳遞,在後端的資料處理上會比較方便,不會在變數名稱上的處理花時間,PHP 有提供可以處理多維陣列的傳遞方式,在多維陣列處理上必須要有 inedx 名稱,如果只要傳遞一維無序陣列就不用設定 inedx 名稱,只需要將 name="data[]"就可以了。

表單的命名方式:

<form action="" method="post">
<ul>
<li>
<input type="checkbox" name="data[0][is]" value="1" />
<input type="text" name="data[0][value]" value="1" />
<select name="data[0][unit]">
<option value="km">公里</option>
<option value="m">公尺</option>
<option value="cm">公分</option>
</select>
</li>
<li>
<input type="checkbox" name="data[1][is]" value="1" />
<input type="text" name="data[1][value]" value="1" />
<select name="data[1][unit]">
<option value="km">公里</option>
<option value="m">公尺</option>
<option value="cm">公分</option>
</select>
</li>
<li>
<input type="checkbox" name="data[2][is]" value="1" />
<input type="text" name="data[2][value]" value="1" />
<select name="data[2][unit]">
<option value="km">公里</option>
<option value="m">公尺</option>
<option value="cm">公分</option>
</select>
</li>
</ul>
<input type="submit" />
</form>


PHP 的接收格式:

<?php
print_r($_POST['data']);
/*
Array
(
[0] => Array
(
[is] => 1
[value] => 1
[unit] => km
)

[1] => Array
(
[is] => 1
[value] => 1
[unit] => m
)

[2] => Array
(
[is] => 1
[value] => 1
[unit] => cm
)

)
*/
?>
2009-03-26

Excel 圖片隨著單元儲存格排序

Excel 真的是一個很好用的文書工具,這幾天為了圖片排序的問題,扒了不少文章,順便做一下心得紀錄。

Excel 插入圖片
選擇從檔案插入圖片。

Excel 插入圖片
選擇需要的圖片全部插入。

Excel 選取全部的圖片
按下[Ctrl]鍵+滑鼠選取全部的圖片。

Excel 設定圖片格式
設定圖片格式。

Excel 圖片大小設定
在[大小]的頁籤中,建議先將圖片縮小到預定大小的 3/2,在拖移時會比較方便操作。
如果要將圖片填滿整個單元儲存格,建議將[鎖定長寬比]取消。

Excel 圖片隨著單元儲存格排序
在[摘要資訊]的頁籤中決定圖片的定位方式,建議選擇第一項[大小位置隨儲存格而變],因為儲存格必須完全包含整張圖片,如果超過單一範圍的儲存格都會讓排序失效,所以建議將圖片填滿整個儲存格,並且隨儲存格變動,避免圖片超過儲存格的意外。

Excel 設定列高

Excel 設定列高
先將[列高]及[欄寬]調整到所需要的大小。

Excel 滑鼠拖移及縮放鎖定
按下[Alt]鍵+滑鼠拖移圖片至儲存格。
[Alt]鍵具有格線鎖定的功能,會將滑鼠拖移及縮放鎖定在格線上,可以精確的將圖片填滿整個儲存格。

Excel 選擇排序範圍
選擇需要排序的範圍。

Excel 選擇排序方式
選擇排序方式。

Excel 圖片隨著單元儲存格排序
呈現的結果。
2009-03-19

動態調整 PHP 最大記憶體上限(memory_limit)

在使用 php 寫 script 去做排程時
這類的 script 執行次數通常不會很多
可是卻會使用大量的 memory
雖然一個好的程式不應該如此肥胖
但為了開發上的效率和整體結構
就允許這小小的肥胖吧!

雖然可以在 php.ini 中設定 memory_limit 的值
但這並不是一個很好的方法
因為在 php.ini 中屬於全域設定
這代表每一支 script 都可以使用這麼大 memory
再開發時沒注意到的話
這只會讓胖胖的程式愈來愈多
這不是一件好事

所以呢?(廢話這麼多)
在程式中動態調整所需的 memory 會是比較好的作法
只要在程式一剛開始的地方做設定就好了
這樣也不用為了少數幾支肥胖的程式去調整 php.ini

<?php
ini_set("memory_limit","2048M");
//.......
?>

[Shell] 利用 tar 作資料備份

一般在 console 使用 tar 做備份壓縮時,都會習慣使用相對路徑做壓縮,在解壓縮時也比較方便,可是再寫 Shell 做 crontab 排程時,也想要使用相對路徑做壓縮的話,必須用一些方法,下面的 script 還加上過濾檔案的機制,可以排除一些隱藏檔或特定目錄的備份。

#!/bin/bash
# Program : 備份指定目錄
# History : 2009/03/19
# Author : Jax
# E-mail : weskerjax@gmail.com
# Website : http://jax-work-archive.blogspot.com/

PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH

# 排除不需要備份的檔案類型
EXCLUDE=""
FILTER=(
"*.bak"           # 排除副檔名為 .bak 的檔案
".*"              # 排除所有隱藏檔
"/CVS/"           # 排除所有目錄為 CVS 的目錄
"Smarty/cache"    # 排除路徑為 Smarty/cache 的目錄
"Smarty/tpl_c"    # 排除路徑為 Smarty/tpl_c 的目錄
)
for i in "${FILTER[@]}" ; do
    EXCLUDE="$EXCLUDE --exclude=$i"
done

# 時間參數
DATE=$(date +%Y%m%d)

# 配份目錄
TARGET_DIR="/home/web"

# 備份檔名路徑目錄
ZIP_FILE="/home/backup/backup_$DATE.tar.bz2"

# 執行壓縮指令
tar -jcf $ZIP_FILE $EXCLUDE -C $TARGET_DIR $(ls $TARGET_DIR)

exit 0;


原始檔:server_backup.sh
2009-03-04

製作 sitemap 的心得

最近在為網站製作 sitemap 產生器,花了半小時去看 sitemaps.org - 通訊協定,這跟 Google 網站管理員工具的定義是一樣的,基本上 sitemap 的格式是很簡單的,詳細說明請察看官方文件。

網路上有很多 sitemap 產生器,但產生出來的結果不如期望,為了做出更好的 sitemap 清單,我就自己作網站的 sitemap 產生器。


需要注意的小細節:
  1. sitemap 索引與 sitemap 中 url 引入的 xsd 是不一樣的
  2. 注意檔案大小 10MB 及筆數的上限 50,000 筆 URL。
  3. 檔案如果很大最好用 gzip 壓縮,壓縮率會有 10 倍以上的落差。
  4. 一定要用驗證器確認格式是否正確,在壓縮前請先確認格式,驗證器無法解析 gzip
  5. 一份 sitemap 中的 priority 值不能全部一樣,Google 會出現 warning。
  6. 如果檔案已經封存不會變動,在 changefreq 的值最好設定為 never ,這樣會得到較好的文件索引。


Sitemap:
<?xml version='1.0' encoding='UTF-8'?>
<urlset 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9"
    url="http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
    xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
>
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
   <url>
      <loc>http://www.example.com/catalog?item=12&desc=v_hawaii</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
   <url>
      <loc>http://www.example.com/catalog?item=83&desc=v_usa</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset>


Sitemap 索引檔:
<?xml version='1.0' encoding='UTF-8'?>
<sitemapindex 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9"
    url="http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd"
    xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
>
   <sitemap>
      <loc>http://www.example.com/sitemap1.xml.gz</loc>
      <lastmod>2004-10-01T18:23:17+00:00</lastmod>
   </sitemap>
   <sitemap>
      <loc>http://www.example.com/sitemap2.xml.gz</loc>
      <lastmod>2005-01-01</lastmod>
   </sitemap>
</sitemapindex>


Sitemap 驗證器:
Google Sitemap(s) Validator


參考文章:
Peter的部落格: Google Sitemaps 教學
網站登錄與提交sitemap(Yahoo!) @ 神鵰蝦