星期五, 12月 30, 2011

CPU 風扇導風散熱裝置

公司同事把電腦搬來,請我幫忙看看是哪裡有問題,為什麼都無法開機,一看到 CPU 風扇導風散熱裝置,整個傻眼,第一次看到灰塵可以積成牽絲的,像是建築物外牆,爬滿藤蔓的感覺。
  • 故意把導風散熱裝置拆下來拍照
CPU 風扇 - 1
  • 整理過後導風散熱裝置原貌
CPU 風扇 - 2
大家都知道把機殼拿掉,可以提高電腦散熱,但往往忽略電腦內積滿灰塵,一樣會散熱不良啦,請定期清理啦 ~~ ^_^

星期五, 12月 23, 2011

[SQL] 流水號跳號

公司內客制的流水號,雖然號稱流水號,但因當時歷史背景和商業邏輯因素,導致會產生流水號不連續或稱跳號的情況下,因此利用 CTE 方式來尋找目前的最小號碼,是跳號的話就把它補齊,沒有跳號的話,就找出目前最小的流水號。

  • 利用 CTE 產生完整的流水號表,再去比對現有資料並找出最小流水號

DECLARE @Temp table (SeqNO smallint)
INSERT INTO @Temp VALUES(1)
INSERT INTO @Temp VALUES(3)
INSERT INTO @Temp VALUES(4)
INSERT INTO @Temp VALUES(9)

;
WITH CTE 
AS
  (
     SELECT 1 AS SeqNO
     UNION ALL 
     SELECT SeqNO + 1
     FROM CTE
     WHERE SeqNO < 5 
  )
SELECT MIN(T1.SeqNO) AS MinNO
FROM CTE AS T1
  LEFT JOIN @Temp AS T2 ON T1.SeqNO = T2.SeqNO
WHERE T2.SeqNO IS NULL 

此作缺點是跑 CTE 會耗費大量 CPU,流水號越多的情況下,此缺點會更明顯。


星期五, 12月 16, 2011

[Challenge] 找出各部門第二高薪人員

Beyond Relational TSQL Beginner's Challenge 1,個人是利用次序函數 RANK() 來做到,次序函數是從 SQL Server 2005 才開始有,在眾多的解法中,有找到非次序函數的解法,可以參考看看。^_^
  • 需求:找出各部門第二高薪人員,而且假如第二高薪有多個人員,也必須一併列出來。
  • 資料來源(題目內有資料來源的 script)
EmployeeID  EmployeeName    Department      Salary   
----------- --------------- --------------- ---------
1           T Cook          Finance         40000.00
2           D Michael       Finance         25000.00
3           A Smith         Finance         25000.00
4           D Adams         Finance         15000.00
5           M Williams      IT              80000.00
6           D Jones         IT              40000.00
7           J Miller        IT              50000.00
8           L Lewis         IT              50000.00
9           A Anderson      Back-Office     25000.00
10          S Martin        Back-Office     15000.00
11          J Garcia        Back-Office     15000.00
12          T Clerk         Back-Office     10000.00
  • 利用次序函數 RANK()
SELECT T.EmployeeID , T.EmployeeName, T.Department, T.Salary
FROM
  (
    SELECT EmployeeID , EmployeeName, Department, Salary ,
            RANK() OVER (PARTITION BY Department ORDER BY Salary DESC) AS RANKNO
     FROM @Employees
  ) AS T
WHERE RANKNO = 2
  • 值得參考的解法
SELECT EmployeeID,EmployeeName,Department,Salary
FROM @Employees e0
WHERE
      (
        SELECT Count(DISTINCT e1.Salary) 
        FROM @Employees e1 
        WHERE e1.Salary >= e0.Salary 
                AND e1.Department = e0.Department
      ) = 2
ORDER BY Department, EmployeeID
  • 結果
EmployeeID  EmployeeName    Department      Salary   
----------- --------------- --------------- ---------
10          S Martin        Back-Office     15000.00
11          J Garcia        Back-Office     15000.00
2           D Michael       Finance         25000.00
3           A Smith         Finance         25000.00
7           J Miller        IT              50000.00
8           L Lewis         IT              50000.00
    參考資料: 

星期五, 12月 09, 2011

[SQL] 利用 T-SQL 語法更改欄位名稱

利用 T-SQL 語法來處理 Table 欄位的需求,直覺會想到利用 ALTER TABLE 語法來處理,但更改欄位名稱無法利用 ALTER TABLE 來達成,必須利用系統預存程序 sp_rename。

-- 新增欄位
ALTER TABLE TableName ADD ColName DataType

-- 刪除欄位
ALTER TABLE TableName DROP COLUMN ColName 

-- 修改欄位資料型態
ALTER TABLE TableName ALTER COLUMN ColName DataType

-- 修改欄位名稱
EXEC sp_rename 'TableName.OldColName','NewColName','COLUMN' 

利用 sp_rename 來更改欄位名稱時,要注意其相依性,EX:函數、預存程序或觸發程序有用到該欄位,必須手動去更新其內容,sp_rename 無法自動更新。
  • 20190515 補述
該欄位存在預設值 (Default)、條件約束 (Check) 時,無法更名欄位,必須先移除相依性,錯誤訊息如下

[SQL] 利用 T-SQL 語法更改欄位名稱

星期五, 12月 02, 2011

[VFP] 判斷電腦是否安裝 AutoCAD

原本想利用 Automation 來判斷電腦是否有安裝 AutoCAD ,但是發現 Automation 好像沒有辦法判斷,下面兩種寫法都失敗,Automation 失敗後只好換個方向,利用 FindExecutable API 來判斷。

  • Automation 判斷 AutoCAD - 無論有沒有安裝 AutoCAD,都沒有辦法產生 Object
loObject = CREATEOBJECT("AutoCAD.Applicat­ion")
loObject = CREATEOBJECT("AutoCAD.AcadApplication")
  • FindExecutable API
-- 宣告 FindExecutable API
DECLARE INTEGER FindExecutable IN shell32 STRING lpFile, STRING lpDir, STRING @lpResult 

lcResult = SPACE(250) -- 接收 FindExecutable API 的回傳值,回傳值為執行檔完整路徑
lcTestFile = ADDBS(GETENV("TEMP")) + "Dummy.DWG" -- 建立測試檔案
STRTOFILE("",(lcTestFile)) -- 在 Windows Temp 資料夾內,建立一個沒有內容的 AutoCAD DWG 檔案
IF FindExecutable ((lcTestFile), "", @lcResult) > 32 -- 大於 32 代表執行成功,有 AutoCAD 軟體
     MESSAGEBOX(lcResult) -- 顯示 AutoCAD 執行檔路徑
ELSE
     MESSAGEBOX("沒有安裝 AutoCAD")
ENDIF
更改測試檔案副檔名(Excel XLS 或 XLSX、Word DOC 或 DOCX),就可以判斷軟體是否安裝在電腦上。

星期三, 11月 30, 2011

與打手之間的對話

人事小姐生 bady 去,由我暫代人事相關業務,今天接到某資委會打手的電話,來詢問公司是否還需要新鮮肝。

打手:我是某某打手,請問是 X 小姐嗎?
  OS:我們不是幾百年前就沒在那徵才。
  Me:X 小姐生 bady 去,我是代理人。
打手:喔!我們這裡有一批新鮮肝,符合貴公司提出新鮮肝的條件,不知道貴公司有沒有
            意願要了解一下。
  OS:人事小姐上個禮拜不就已經跟我說,各個打手的徵才通通關閉了嘛。
  Me:我們公司目前沒有人力缺口,不需要新鮮肝。
打手:喔!你的意思是年關前不再找人,年後才會開始就對了啦,很多公司目前都這樣作,
            我了解、我了解。
  OS:不會吧,我明明說我不需要,我開始懷疑她前一份工作是不是記者,這麼會編故事。
打手:你們人事小姐很認真ㄟ。
  OS:是指現在在產房很認真,還是平時工作很認真,沒頭沒尾的熊熊冒這話出來。
  Me:對阿,她在醫院還會打電話回來關心,交接事項也都寫得很清楚
           (順風車搭一下,總是要給人家台階下)。
  打手:那假如需求新鮮肝的話,可以再連絡我們。

這段對話感覺就像是銀行打來詢問需不需要借貸,只是現在錢變成人而以,Orz ~~

星期五, 11月 25, 2011

[VFP] 預設自訂 Form 物件

寫 VFP 多多少少會使用自訂控件,自訂控件可以直接從 Class 或是 Form Control ToolBar ,拖曳進入 Form 中來使用,而其中 Form 物件最特別,因為當產生一個原始 Form 並把自訂 Form 拖曳進原始 Form 時,會自動產生 FormSet,因此要再刪除原始 Form 和 FormSet ,保留下來的才是自訂 Form,雖然不是什麼耗時的動作,但是常作也是挺惹人厭的。

以下說明如何更改 VFP 預設原始 Form 為自訂 Form。
  • VFP 主畫面 => Tools Tab => Options
預設自訂 Form 物件 - 1
  • Options => Forms Tab => Template Class
預設自訂 Form 物件 - 2

只要設定 Template Claas 的 Form 選項,當產生新 Form 時,就會直接產生自訂 Form 物件。

星期五, 11月 18, 2011

Power Link For 840D

一大早就收到 CNC 廠廠長來電,LP 電腦又無法把檔案傳到 CNC 機器,錯誤訊息是 "Following run time error has occurred Item not found in this collection.(HDtoNCcopy)",這個問題存在很久,老實講我也完全不清楚我每次到底是怎麼把它修正的,當下是抱著亂搞心態去處理。

一到現場發現問題並不單純,以往檔案雖然無法傳到 CNC 機器去,這次是連進入 840D 的 NC Manager 都有問題。
  • 左側 MMC HARD DRIVE 內,原本是應該是連上 Server 的資料夾(g:\),但如今卻變成 UNKON,點擊UNKON會造成整個840D當掉。
Power Link For 840D - 1
  • 想說重新設定資料夾就可以解決這個問題,沒想到點擊 Setup 選項後,馬上又跳出 "Run-time error '3265': Item not found in this collection",也是整個840D當掉。
Power Link For 840D - 2

星期五, 11月 11, 2011

HD Tune

使用者告知電腦會莫名其妙就自動關機,用起來也卡卡的,利用 HD Tune來檢查後,發現 Reallocated Sector Count 選項被反黃,再利用 Error Scan 一掃,果然情況不太妙。

HD Tune - 1
HD Tune - 2

Reallocated Sector Count 翻成白話就是 "壞軌",趕快備份資料比較重要。

HD Tune 是套很方便的工具,但是 Health Status 內選項,假如有反黃或是反紅選項時,對硬碟知識不熟的我,也找不出問題點在哪,只能判斷硬碟可能有問題,所以使用 HD Tune 的重點,是要如何解讀 HD Tune 提供的異常訊息,才有辦法對症下藥,真的有問題,直接換掉也許會是更好的辦法吧。

根據這次經驗,檢查後內容和使用者實際情況,都發現硬碟有問題,但 Health Status 卻是 OK ,以往用 HD Tune 時,也發現到常常 Health 內有異常,但 Health Status 是 OK,實在不知道 Health Status 是怎判斷的。

星期五, 11月 04, 2011

[SQL] DELETE 和 TRUNCATE

TRUNCATE 等於沒有 WHERE 的 DELETE,但是 TRUNCATE 的效率比較快,主要是因為資料刪除時,DELETE 會鎖定每一筆資料進行刪除並寫進交易紀錄檔,TRUNCATE 鎖定資料表和資料頁來取消配置(Deallocate)儲存資料的資料頁(Data Page),交易記錄檔內只會記錄資料頁的取消配置,因此相較之下,DELETE 會耗費一些時間。

之前學習 TRUNCATE 時,一直以為 TRUNCATE 不會產生交易紀錄(Log)且不可回復(Rollback),其實 MSDN 上寫得很清楚,TRUNCATE 是會產生交易紀錄只是相較於 DELETE , TRUNCATE 產生的交易紀錄較少,既然有交易紀錄,當然就可以回復囉。

TRUNCATE 限制:
  1. 無法使用 在 Foreign Key 連結的 Table:父子關係 Table 且設有Foreign Key,父 Table 無法使用TRUNCATE ,子 Table 可以。
  2. TRUNCATE 無法觸發 Trigger。
  3. 資料表內欄位有設定識別規格,TRUNCATE 會重設至初始值。
    • 關聯刪除
    DECLARE @Data1 Table (NO char(5))
    DECLARE @Data2 Table (NO char(5))
     
    INSERT INTO @Data1 VALUES ('1')
    INSERT INTO @Data1 VALUES ('2')
    INSERT INTO @Data1 VALUES ('3')
    INSERT INTO @Data1 VALUES ('4')
    INSERT INTO @Data1 VALUES ('5')
    INSERT INTO @Data2 VALUES ('1')
    INSERT INTO @Data2 VALUES ('3')
    INSERT INTO @Data2 VALUES ('5')
    
    -- 方法 1 利用 JOIN
    DELETE T1
    FROM @Data1 AS T1 JOIN @Data2 AS T2 ON T1.NO = T2.NO
      
    -- 方法 2 利用 IN
    DELETE FROM @Data1
    WHERE NO IN (SELECT NO FROM @Data2)
    
    • 分批刪除大量資料
    大量刪除資料的過程中也可能導致使用者存取效能降低,因此透過分批的方式,降低對SQL Server的影響。
    SET NOCOUNT ON
    
    WHILE  1 = 1 -- 一直進入迴圈
      BEGIN
        DELETE TOP (1000) -- 利用 TOP 限制刪除筆數(1000為使用者自訂筆數、括號一定要存在)
        FROM TableName
        WHERE Condition -- 篩選條件
    
        IF @@ROWCOUNT = 0 -- 假如沒有刪除任何資料,則跳出迴圈
          BREAK
      END
    
    使用上述語法必須注意 @@ROWCOUNT 只會傳回前一個 T-SQL 影響的資料數,假如該 Table 上有設定 Delete Trigger 或 Foreign Key 的 Delete Cascade 的話,@@ROWCOUNT 的回傳值,並不是真正該 Table 的刪除資料數。

    星期五, 10月 28, 2011

    [Challenge] 累計加總(Runing Total)

    Beyond Relational 的 TSQL Challenge 65
    • 資料來源(題目內有資料來源的 script)
    Date       CustomerID Type  Amount
    ---------- ---------- ----- --------
    2011-01-01 CUST1001   INV   12000.00
    2011-01-02 CUST1001   PAY    3000.00
    2011-01-03 CUST1001   INV    8000.00
    2011-01-04 CUST1001   PAY    9000.00
    2011-01-04 CUST1002   INV    1000.00
    2011-01-05 CUST1002   PAY    5000.00
    2011-01-05 CUST1002   INV    6000.00
    
    • 結果
    Date       CustomerID Type  Amount   Balance
    ---------- ---------- ----- -------- ---------
    2011-01-01 CUST1001   INV   12000.00  12000.00
    2011-01-02 CUST1001   PAY    3000.00   9000.00
    2011-01-03 CUST1001   INV    8000.00  17000.00
    2011-01-04 CUST1001   PAY    9000.00   8000.00
    2011-01-04 CUST1002   INV    1000.00   1000.00
    2011-01-05 CUST1002   INV    6000.00   7000.00
    2011-01-05 CUST1002   PAY    5000.00   2000.00
    
    • 規則:
      1. 同一個客戶同一天會有多筆 INV 和 PAY 資料
      2. 同一個客戶同一天內的全部的 INV 資料必須先計算,之後再計算 PAY 資料
      3. 結果必須根據 CustomerID , Date , Type , Amount 來排序
      4. Balance 可以為負

    星期五, 10月 21, 2011

    [SQL] 字串欄位轉置

    利用尋找各班級前三名,來解釋字串欄位要如何轉置,在此不討論前三名是否有同分的情況。

    -- 建立測試資料
    DECLARE @Temp Table (class char(10),SdtName char(10),Score smallint)
    INSERT INTO @Temp VALUES ('小叮噹班','大雄',10)
    INSERT INTO @Temp VALUES ('小叮噹班','阿福',90)
    INSERT INTO @Temp VALUES ('小叮噹班','技安',70)
    INSERT INTO @Temp VALUES ('小叮噹班','宜靜',100)
    INSERT INTO @Temp VALUES ('海賊王班','魯夫',20)
    INSERT INTO @Temp VALUES ('海賊王班','娜美',90)
    INSERT INTO @Temp VALUES ('海賊王班','騙人布',65)
    INSERT INTO @Temp VALUES ('海賊王班','香吉士',30)
    INSERT INTO @Temp VALUES ('海賊王班','索隆',20)
    INSERT INTO @Temp VALUES ('網球王子班','不二',95)
    INSERT INTO @Temp VALUES ('網球王子班','英二',75)
    INSERT INTO @Temp VALUES ('網球王子班','手塚',99)
    INSERT INTO @Temp VALUES ('網球王子班','越前',80)
    INSERT INTO @Temp VALUES ('網球王子班','河村',20)
    

    • CASE 搭配 MAX()

    轉置的第一個要點是必須要有一個基準欄位來辨別前三名,在此利用 ROW_NUMBER() 來產生此基準欄位。
    SELECT * ,
           ROW_NUMBER() OVER (PARTITION BY class ORDER BY Score DESC) AS ROWNO
    FROM @Temp
    
    [SQL] 字串欄位轉置 - 1

    星期五, 10月 14, 2011

    [SQL] 群組字串連結

    設計資料庫,常常會有一對多邏輯介面(檔頭、檔身設計),這樣的設計在產生報表時,為方便使用者閱讀,都會希望把檔身的多筆資料,整合在一行內(多筆字串資料合併成一行字串)。

    公司在月底時,人事通常會提供一份報表 - 下個月員工排休表,給課長確認是否有哪一天太多人排休,會導致產線人力不足,就利用這份排休表來說明這個主題。
    -- 建立測試資料
    IF OBJECT_ID (N'Leave',N'U') IS NOT NULL
        DROP TABLE Leave
     
    CREATE TABLE Leave (Date datetime,EmpName varchar(8))
    INSERT INTO Leave VALUES('2011-08-01','張三')
    INSERT INTO Leave VALUES('2011-08-02','張三')
    INSERT INTO Leave VALUES('2011-08-22','張三')
    INSERT INTO Leave VALUES('2011-08-01','李四')
    INSERT INTO Leave VALUES('2011-08-22','李四')
    INSERT INTO Leave VALUES('2011-08-01','王五')
    INSERT INTO Leave VALUES('2011-08-23','王五')
    INSERT INTO Leave VALUES('2011-08-24','王五')
    INSERT INTO Leave VALUES('2011-08-25','王五')
    
    使用者自訂函數
    IF OBJECT_ID(N'dbo.getCommaString', N'FN') IS NOT NULL
        DROP FUNCTION dbo.getCommaString
    
    -- 建立 FUNCTION
    CREATE FUNCTION getCommaString(@date datetime) 
    RETURNS varchar(500)  --500若不夠,請加大 
    BEGIN
        DECLARE @string varchar(500)  --500若不夠,請加大 
        SET @string = ''
     
        SELECT @string = @string + EmpName + ','
        FROM Leave
        WHERE Date = @date
        ORDER BY EmpName
     
        SET @string = LEFT(@string,LEN(@string)-1) -- 把最後面的逗號後刪除
        RETURN @string
    END
    
    -- 使用自定函數來進行字串連結 
    SELECT 
         CONVERT(char(10),Date,120) AS [日期],
         DATENAME(dw,Date) AS [星期],
         dbo.getCommaString(Date) AS [請假人員]
    FROM Leave
    GROUP BY Date
    

    Cursor
    -- 宣告一個 Table 變數來承接 CURSOR 跑完的結果
    DECLARE @Temp table (Date datetime,String varchar(100))
     
    DECLARE curTemp CURSOR
      FOR
          (
            SELECT Date
            FROM Leave
            GROUP BY Date
          )
     
    OPEN curTemp
     
    DECLARE @date as datetime
    DECLARE @string as varchar(100)
    
    FETCH NEXT FROM curTemp INTO @date 
      WHILE (@@FETCH_STATUS = 0) 
        BEGIN  
    
            SET @string = ''
    
            SELECT @string = @string + EmpName + ','
            FROM Leave
            WHERE Date = @date
    
            SET @string = LEFT(@string,LEN(@string)-1)
    
            INSERT INTO @Temp (Date,String)
              VALUES(@date,@string)
     
            FETCH NEXT FROM curTemp INTO @date
        END
     
    CLOSE curTemp 
    DEALLOCATE curTemp 
    
    SELECT 
        CONVERT(char(10),Date,120) AS [日期],
        DATENAME(dw,Date) AS [星期],
        String AS [請假人員]
    FROM @Temp
    
    CTE
    ;
    WITH CTE AS
    (
      SELECT 
        Date , 
        CAST('' AS nvarchar(100)) AS Data ,
        CAST('' AS nvarchar(100)) AS String ,
        0 AS Counts ,
        COUNT(*) AS Total -- 資料總筆數
      FROM Leave 
      GROUP BY Date
      UNION ALL
      SELECT 
        L.Date , 
        CAST(L.EmpName AS NVARCHAR(100)) , 
        CAST(String + ',' + L.EmpName AS nvarchar(100)) , 
        Counts + 1 , 
        Total
      FROM CTE AS T
        JOIN Leave AS L ON T.Date = L.Date
          AND T.Data < L.EmpName -- 遞迴停止重要關鍵
    )
    SELECT 
      CONVERT(char(10),Date,120) AS [日期],
      DATENAME(dw,Date) AS [星期],
      STUFF(String,1,1,'') AS [請假人員]
    FROM CTE
    WHERE Counts = Total -- 利用資料總筆來判斷哪一筆是最後一筆
    ORDER BY Date
    
    FOR XML PATH 應用
    SELECT 
      Date AS 日期,
      DATENAME(dw,Date) AS 星期 ,  
      (
        STUFF -- 說明 3
          (
            (
              SELECT ',' + EmpName -- 說明 2
              FROM LEave T2
              WHERE T2.Date = T1.Date
              FOR XML PATH('') -- 說明 1
            )
            , 1, 1, '' 
          )
      ) AS [請假人員]
    FROM Leave T1
    GROUP BY Date
    
    • 說明
      1. 依預設,PATH 模式會針對結果集的每個資料列產生 <row> 元素包裝函數。 您可以選擇性地指定元素名稱。 如果您有選擇,則會將指定名稱做為包裝函數的元素名稱。 如果您提供空白字串 (FOR XML PATH ('')),就不會產生包裝函數元素。
      2. 不要給欄位名稱,任何沒有名稱的資料行都將予以內嵌。
      3. 利用 STUFF() 來取代第一個逗號

    STRING_AGG()

    SQL Server 2017 推出的新功能
    SELECT
      [Date] AS 日期,
      DATENAME(dw,Date) AS 星期 ,  
      STRING_AGG(EmpName , ',') AS [請假人員]
    FROM Leave
    GROUP BY [Date]
    
    這五種作法中,CURSOR 和 CTE 比較不會應用在實務上,個人練習用。

    星期五, 10月 07, 2011

    [SQL] 判斷第一碼為數字或是字母

    VFP 中可以利用 ISDIGIT() 來判斷字串最左邊字元是否為數字,ISALPHA() 來判斷字串最左邊字元是否為英文字母,SQL Server內可以透過 LIKE 來達成。
    CREATE FUNCTION [dbo].[ISDIGIT]
    (
       @string as nvarchar(250)
    )
    RETURNS bit
    AS
      BEGIN
        DECLARE @true bit
      
        IF @string LIKE '[0-9]%'
           SET @true = 1
        ELSE
           SET @true = 0
     
        RETURN @true
      END
    
    CREATE FUNCTION [dbo].[ISALPHA]
    (
       @string as nvarchar(250)
    )
    RETURNS bit
    AS
      BEGIN
        DECLARE @true bit
     
        IF @string LIKE '[A-Z]%' -- 不區分大小寫
           SET @true = 1
        ELSE
           SET @true = 0
      
        RETURN @true
      END
    
    SELECT Val,
        '數字判斷' = CASE WHEN dbo.ISDIGIT(Val) = 1 THEN '數字' ELSE '' END,
        '字母判斷' = CASE WHEN dbo.ISALPHA(Val) = 1 THEN '字母' ELSE '' END
    FROM
         (
           SELECT '123' AS Val
           UNION ALL
           SELECT '456'
           UNION ALL
           SELECT 'ABC'
           UNION ALL
           SELECT 'def' -- 故意小寫
         ) AS T
    
    • 結果
    判斷字串第一個字
      參考資料:
    • LIKE in MSDN

    星期五, 9月 30, 2011

    [SQL] 日期 - 基本應用

    • 日期資料型態的預設格式
    1. datetime:yyyy-mm-dd hh:mm:ss.mmm
    2. smalldate:yyyy-mm-dd hh:mm:ss
    3. date:yyyy-mm-dd
    • 基底日期
    以 datetime 來表示為 1900-01-01 00:00:00.000 有兩種表示方式
    SELECT CAST(0 AS datetime)
    SELECT CAST('' AS datetime)
    
    • 搭配 REPLACE 應用
    -- 利用 REPLACE 把 連接號(-)、空格和冒號(:)拿掉
    SELECT
     REPLACE(
       REPLACE(
         REPLACE(CONVERT(varchar(20), GETDATE(), 120 ),'-','') -- 把連結號拿掉
       ,' ','') -- 把空格拿掉
     ,':','') -- 把冒號拿掉
    
    • 搭配 DATEADD、DATEDIFF 應用
    第一天日期計算:
    邏輯 1. 用 DATEDIFF 計算從基底日期至欲計算日期,總共有多個年(月、日、季或週)。
    邏輯 2. 用 DATEADD + 步驟一的計算值,就可以找到年(月、季或週)的第一天日期 或 當天的午夜時間。
    -- 當年第一天
    SELECT 
     DATEADD(yy,
                DATEDIFF(yy,'',GETDATE()) -- 邏輯 1 計算值
            ,'')
    
    -- 當月第一天
    SELECT 
     DATEADD(mm,
                DATEDIFF(mm,'',GETDATE()) -- 邏輯 1 計算值
            ,'') 
    
    -- 當季第一天
    SELECT 
     DATEADD(qq,
                DATEDIFF(qq,'',GETDATE()) -- 邏輯 1 計算值
            ,'')
    
    -- 當週星期一日期
    SELECT 
     DATEADD(wk,
                DATEDIFF(wk,'',GETDATE()) -- 邏輯 1 計算值
            ,'')
    
    最後一天日期計算
    邏輯 1. 同 第一天日期計算邏輯,先算出第一天日期
    邏輯 2. 第一天日期 減 一天,即為最後一天日期
    -- 上月最後一天
    SELECT 
     DATEADD(dd,-1,                                         -- 減 1 天
                   DATEADD(mm,DATEDIFF(mm,'',GETDATE()),'') -- 當月第一天日期
            )
    
    -- 去年最後一天
    SELECT 
     DATEADD(dd,-1,                                         -- 減 1 天
                   DATEADD(yy,DATEDIFF(yy,'',GETDATE()),'') -- 當年第一天日期
            )
    
    -- 本月最後一天
    SELECT 
     DATEADD(dd,-1,                                             -- 減 1 天
                   DATEADD(mm,DATEDIFF(mm,'',GETDATE()) + 1,'') -- 計算值 加 1 個月,找出下個月第一天
            )
    
    -- 本年最後一天
    SELECT 
     DATEADD(dd,-1,                                             -- 減 1 天
                   DATEADD(yy,DATEDIFF(yy,'',GETDATE()) + 1,'') -- 計算值 加 1 年,找出明年第一天
     )
    
    • 當天午夜時間
    -- 方法一:搭配 DATEADD、DATEDIFF 應用
    SELECT
     DATEADD
        (dd,
            DATEDIFF(dd,'',GETDATE())
        ,'')
    
    -- 方法二:利用轉換資料形態
    SELECT 
     CAST
        (
          CONVERT(char(10),GETDATE(),120) -- 把 GETDATE() 轉為字串,因限定字元因素,只會產生 yyyy-mm-dd
          AS Datetime
        ) -- 再把 yyyy-mm-dd 轉為 datetime 變成午夜時間
    
    • 每個月的最後一天
    -- 方法一:搭配 DATEADD、DATEDIFF 應用
    SELECT 
     DATEADD(dd,-1,                                             
                   DATEADD(mm,DATEDIFF(mm,'',GETDATE()) + 1,'') 
            )
    
    -- 方法二:利用 2012 提供的新函數 EOMONTH
    --         EOMONTH 回傳值為 date 資料型態
    SELECT EOMONTH(GETDATE())
    

    星期五, 9月 16, 2011

    [VFP] Class definition MSXML2.DOMDOCUMENT.4.0 is not found

    在 Win7 32 bit 上安裝 VFP 9.0,安裝完畢後,一打開就看到下列圖示訊息,Task Pane Manager 竟然不正常,重灌也是同樣的情況,OrZ。

    Class definition MSXML2.DOMDOCUMENT.4.0 is not found

    根據錯誤訊息,檢查有 VFP 9.0 正常運作的電腦,發現有安裝 MSXML 4.0,果然把它安裝上去後,就 OK 啦。
    • 備註:Download Center 中的 MSXML 4.0 Service Pack 2 內有多個檔案,我只安裝 msxml.msi 而已

    星期五, 9月 02, 2011

    [Win] Windows 7 桌面圖示全部消失

    從另外一個廠回到座位時,公司小姐急急忙忙把我叫住,並說明桌面上的圖示,通通不見啦,即使重新開機也不會出現,當時心中只有一個想法,OOXX 不會是中毒了吧,後來檢查了一下,發現只是設定值被她改掉而已,虛驚一場。
    • 在桌面上右鍵 => 檢視 => 勾選顯示桌面圖示
    [Windows] Windows 7 桌面圖示全部消失 - 1
    特地到 Windows XP 中尋找,原來 XP 中也有這個選項,果然是我少見多怪。
    [Windows] Windows 7 桌面圖示全部消失 - 2

    星期五, 8月 26, 2011

    [SQL] 字串填補函數

    在 VFP 中有兩個函數 PADL() 和 PADR(),可以把字串填入特定字元至指定長度,而在 SQL Server 內則是可以利用 REPLICATE()、RIGHT() 、 LEFT() 和 LEN() 來達到相同的效果。
    • 首先建立使用者自定函數,SQL 語法如下,在此以 PADL() 為例說明。
    IF OBJECT_ID(N'dbo.PADL', N'FN') IS NOT NULL
        DROP FUNCTION dbo.PADL
    
    CREATE FUNCTION [dbo].[PADL]
    (
      @String nvarchar(100),    -- 字串來源
      @PaddingChar nvarchar(1), -- 填補字元
      @StringLen tinyint        -- 字串長度
    )
    RETURNS nvarchar(200)
    AS
    BEGIN
      DECLARE @Result nvarchar(200)
       
      -- 方法一
      SET @Result = RIGHT(REPLICATE(@PaddingChar,@StringLen) + @String,@StringLen)
       
      -- 方法二
      SET @Result = REPLICATE(@PaddingChar,@StringLen - LEN(@String)) + @String
       
      RETURN @Result
    END
    GO
    

    星期五, 8月 19, 2011

    [VFP] Automation 在 Excel 上的應用

      常用語法:
    1. loExcel.ActiveSheet..... 和 loExcel.... 皆代表對現在Excel 上擁有控制權的 Sheet 進行動作。
    2. 指定 Sheet 的方法有三種:ActiveSheet 現在 Excel 上擁有控制權的 Sheet、Sheets(Var) 和 WorkSheets(Var) 為指定 Sheet 的兩種方式,Var 可以為 Sheet 名稱或是索引值。
    -- 以下語法大多利用 ActiveSheet 來指定 Sheet,當然也可以利用 Sheet(Var)來達到相同效果
    
    loExcel = CREATEOBJECT("Excel.Application") 
      -- 建立 Excel 物件
    
    loExcel.SheetsInNewWorkBook = liSheetQty 
      -- 指定 Excel Sheet 數目
    
    loExcel.WorkBooks.Add 
      -- 根據 SheetsInNewWorkBook 的設定值,把 Sheet 加入 Excel 內
    
    lnSheetQty = loExcel.Sheets.Count 
      -- 查詢 Excel 內有多少個 Sheet
    
    loExcel.Sheets(Var).NAME = SheetName
      -- Sheet 名稱更名
    
    loExcel.ActiveSheet.Delete() 
    loExcel.Sheets(Var).Delete() 
      -- 刪除 Sheet
    
    loExcel.Visible = .T. 
      -- 顯示 Excel 物件,預設為不顯示
    
    loExcel.WorkSheets(Var).Activate -- 書上列的
    loExcel.Sheets(Var).Activate -- 自己常用
      -- 指定 Excel Sheet
    
    loExcel.WorkBooks.OPEN((lcExcelPath)) 
      -- 打開 Excel 檔案 ; lcExcelPath 必須包含副檔(XLS、XLSX)
      
    loExcel.ActiveSheet.Cells(lnRows,lnColumns) = Values
    loExcel.Sheets(Var).Cells(lnRows,lnColumns) = Values
    loExcel.Cells(lnRows,lnColumns).Value = Values
      -- 設定儲存格的資料,EX:Cells(3,5)代表第三行、第五列(欄)
      -- 前兩種方式沒有 Value 屬姓
    
    loExcel.ActiveSheet.Rows(lnRows).FONT.SIZE = lnFontSize
    loExcel.ActiveSheet.Columns(lnColumns).FONT.SIZE = lnFontSize
      -- 設定第 lnRows 行和第 lnColumns 列的字形大小
    
    loExcel.ActiveSheet.Rows(lnRows).RowHeight = lnHeight
    loExcel.ActiveSheet.Columns(lnColumns).ColumnWidth = lnWidth
      -- 設定第 lnRow 行的高度;設定第 lnColumns 的寬度
    
    loExcel.ActiveSheet.Range(lcRange).Select
      -- 選定區域;lcRange 為儲存格範圍,EX:A1:D10
    loExcel.SELECTION.Locked = .F.
      -- 解除選取範圍內的鎖定
    loExcel.ActiveSheet.Protect(Password)
      -- 保護現有Sheet,Password 為保護密碼
    loExcel.ActiveSheet.unProtect(Password)
      -- 取消保護現有Sheet,Password 為保護密碼
    
    loExcel.ActiveSheet.Range(lcRange).Borders.LineStyle = nLineInt -- 設定上下左右的線條
    loExcel.ActiveSheet.Range(lcRange).Border(nInt).LineStyle = nLineInt -- 依據 nInt 值設定哪一邊的線條
      -- lcRange 為儲存格範圍,EX:A1:D10
      -- nLineInt,1 和 7 為細實線、2 為細虛線、4 為點虛線、9 為雙細實線
      -- nInt 參數為:1 - 左、2 - 右、3 - 上、4 - 下、5 - 左斜、6 - 右斜
    
    loExcel.ActiveSheet.Range(lcRange).Borders.Weight = nInt
      -- 設定邊框線粗細
    
    loExcel.ActiveSheet.Cells(lnRows,lnColumns).VerticalAlignment = lnValue
    loExcel.ActiveSheet.Rows(lnRows).VerticalAlignment = lnValue
    loExcel.ActiveSheet.Columns(lnColumns).VerticalAlignment = lnValue
      -- 設定垂直對齊方式,lnValue 1 為靠上對齊、2為置中對齊、3為靠下對齊
    
    loExcel.ActiveSheet.Cells(lnRow,lnColumns).HorizontalAlignment = lnValue
    loExcel.ActiveSheet.Rows(lnRows).HorizontalAlignment = lnValue
    loExcel.ActiveSheet.Columns(lnColumns).HorizontalAlignment = lnValue
      -- 設定水平對齊方式,lnValue 1 為向右對齊、2為向左對齊、3為置中對齊
    
    loExcel.ActiveSheet.Rows(lnRows).Insert
      -- 在第 lnRows 行前插入一行
    
    loExcel.ActiveSheet.PageSetup.PaperSize = nPrinterSetting 
      -- 設定 Sheet 的紙張大小,常見設定值: 8 為 A3、9 為 A4
      -- 查詢 Help 中的 PrtInfo() 可以查到全部紙張的 nPrinterSetting 
    
    loExcel.ActiveSheet.PageSetup.Orientation = nPrinterSetting 
      -- 設定 Sheet 紙張方向, 1 為直向、2 為橫向
    
    loExcel.ActiveSheet.Range(lcRange).Merge
      --合併資料格,lcRange 為儲存格範圍,EX:A1:D1
    
    loExcel.ActiveSheet.PageSetup.TopMargin = 1 / 0.035 -- 上邊界
    loExcel.ActiveSheet.PageSetup.BottomMargin = 1 / 0.035 -- 下邊界
    loExcel.ActiveSheet.PageSetup.LeftMargin = 1 / 0.035 -- 左邊界
    loExcel.ActiveSheet.PageSetup.RightMargin = 1 / 0.035 -- 右邊界
      -- 設定邊界,1 / 0.035 = 1 mm
    
    loExcel.ActiveSheet.PageSetup.LeftHeader = lcContent -- 頁首左邊
    loExcel.ActiveSheet.PageSetup.CenterHeader = lcContent -- 頁首中間
    loExcel.ActiveSheet.PageSetup.RightHeader = lcContent -- 頁首右邊
    
    loExcel.ActiveSheet.PageSetup.LeftFooter = lcContent -- 頁尾左邊
    loExcel.ActiveSheet.PageSetup.CenterFooter = lcContent -- 頁尾中間
    loExcel.ActiveSheet.PageSetup.RightFooter = lcContent -- 頁尾右邊
    
    loExcel.ActiveSheet.Columns(lnColumns).NumberFormatlocal = Format
      --  Format 為欲設定格式
      -- "@" 設定為文字
      -- "G/通用格式" 設定為通用格式
      -- "#,##0_ " 設定資料為數值,且有千分位符號
      -- "[$-404]e/m/d;@"  西元年格式改為民國年格式
      -- "[>99999999]0000-000-000;000-000-000" 行動電話、呼叫器號碼
    
    loExcel.ActiveSheet.Cells(lnRows,lnColumns).Formula = Formula
      -- Formula 設定公式
      -- "=SUM(A1:B1)" 加總
      -- "=AVERAGE(A1:B1)" 平均
      -- 簡易實務範例:
      -- loExcel.ActiveSheet.Cells(lnRows,lnColumns).Copy 選定某一格的公式
      -- loExcel.ActiveSheet.RANGE(lcRange).SELECT 目標儲存格
      -- loExcel.ActiveSheet.PASTE 進行公式複製
    
    loExcel.SELECTION.WrapText = .T.
      -- 自動換列
    
    lcPrintTitleRange = "lnROWStart:lnROWEnd" -- EX: 1:3
    loExcel.ActiveSheet.RANGE(lcPrintTitleRange).SELECT
    loExcel.ActiveSheet.PageSetup.PrintTitleRows = lcPrintTitleRange
      -- 設定列印標頭
    
    loExcel.ActiveWindow.SplitColumn = lnCol
    loExcel.ActiveWindow.SplitRow = lnRow
    loExcel.ActiveWindow.FreezePanes = .T.
      -- 凍結視窗設定
      -- SplitColumn = lnCol 代表凍結前 N Column
      -- SplitRow = lnRow 代表凍結前 N Row
    
    loExcel.ActiveSheet.COLUMNS(lnColumns).HIDDEN = Visible
    loExcel.ActiveSheet.ROWS(lnRows).HIDDEN =  Visible
      -- 隱藏 Column 或 Row;. Visible  為 T.為隱藏、.F.為顯示(預設值)
    
    loExcel.DisplayAlerts = .F.
      -- 關閉 Excel 警示,
      -- EX1:未儲存前,嘗試關閉 Excel,會詢問是否要儲存
      -- EX2:刪除 Sheet 時,會 DBCheck 是否要刪除 Sheet 
      -- EX3:合併儲存格會跳出警告
    
    loExcel.ActiveWorkbook.Save
      -- 對 Excel 進行儲存
    
    loExcel.ActiveWorkbook.SaveAs("D:\Excel.XLSX")
      -- 對 Excel 進行另存新檔
    
    loExcel.ActiveWorkbook.SaveAs("D:\Excel.XLS" , FileFormat)
      -- 對 Excel 進行另存新檔並轉為其他格式
      -- FileFormat 為 56:97 - 2003 xls 格式
      -- FileFormat 為 6:csv 格式
    
    loExcel.Quit
      -- 關閉 Excel
    
      資料匯出
    SELECT curData -- 欲匯出資料 Cursor
    SCAN
       FOR lnCount = 1 TO FCOUNT("curData")
           lcField = EVALUATE(FIELD(lnCount)) -- 利用 Evaluate() 抓值
           -- 假設已事先打開 Excel 物件
           loExcel.Sheets(Var).cells(RECNO("curData"), lnCount) = lcField
           -- 或 loExcel.ActiveSheet.cells(RECNO("curData"), lnCount) = lcField
       ENDFOR
    
       SELECT curData
    ENDSCAN
    
      利用錄製巨集來了解 VBA 語法
    以此為例子說明如何利用錄製巨集了解 VBA 語法:在 cell(1,1) 輸入手機號碼,並設定格式為"行動電話、呼叫器號碼"。
    1. 開啟錄製巨集
    2. 在 cell(1,1)內輸入手機號碼 0916123456,輸入完後在 cell(1,1) 內會顯示 916123456
    3. 儲存格格式內,數值 Tag -> 類別(特殊)-> 類型(行動電話、呼叫器號碼)
    4. 編輯已錄製的巨集
    -- 巨集內容
    Sub Macro1()
        ActiveCell.FormulaR1C1 = "916123456"
        Range("A1").Select
        Selection.NumberFormatLocal = "[>99999999]0000-000-000;000-000-000"
        Application.Goto Reference:="Macro1"
    End Sub
    
    HighLight 的 "[>99999999]0000-000-000;000-000-000" 就是行動電話、呼叫器號碼的格式。

    星期五, 8月 05, 2011

    Fuji Xerox DocuPrint M205 b 掃描初值設定值

    M205 b 掃描的預設值,檔案格式為 PDF、解析度為 200 x 200 dpi,第一次使用時就覺得很麻煩,每次掃描都會依據預設值進行掃瞄動作,偏偏原廠預設值又不符合需求,每次使用都必須設定也是挺煩人的,好在可以設定掃描預設值,而每次掃描後 30 秒內,都可以直接繼續掃描 (多檔案掃描 ),超過30秒後,又會回到M205 b預設狀態,要掃描請在重新按掃描鍵,並選擇儲存位置,沒有重新選取的話,此時會動作的可是複印功能喔。
    • 機器確認/規格設定(有 i 符號的按鈕,按下去後會有藍光顯示) => 初值設定 => 掃描功能初值設定,在這裡就可以調整預設值。
    Fuji Xerox DocuPrint M205 b 掃描初值設定值 - 1
    Fuji Xerox DocuPrint M205 b 掃描初值設定值 - 2
    Fuji Xerox DocuPrint M205 b 掃描初值設定值 - 3

    星期五, 7月 29, 2011

    [SQL] CURSOR

    SQL Server DML 語法(SELECT、UPDATE 和 DELETE)是以資料集為資料處理單位,方便且有效率,而 Cursor 則是以記錄為資料處理單位,對於資料操作彈性較大。

    SQL Cursor 的基礎架構
    DECLARE curTemp CURSOR Local Fast_Forward -- 宣告 Cursor 及其資料來源
      FOR
          (
            SELECT Col1,Col2,Col3......
            FROM SourceTable
            WHERE Condition
          )
     
    OPEN curTemp -- 打開 Cursor,並建立 Cursor 與資料表關連
     
    DECLARE @var1 as .....
    DECLARE @var2 as .....
     
    FETCH NEXT FROM curTemp INTO @var1,@var2 -- 將資料存進變數中
      WHILE (@@FETCH_STATUS = 0) -- 檢查是否有讀取到資料
        BEGIN  
      
            .................... 
     
            FETCH NEXT FROM curTemp INTO @var1,@var2  
        END
     
    CLOSE curTemp -- 關閉 Cursor,並關閉 Cursor 與資料表連結
    DEALLOCATE curTemp -- 將 Cursor 物件移除
    
      使用 Cursor 會導致 SQLServer 效能不彰,應視為最後手段,但假如使用時請注意下列事項:
      1. 盡量由前往後讀取資料就好 FORWARD_ONLY 和 FETCH NEXT 為預設值,不要使用 SCROLL 和 FETCH PRIOR、FETCH FIRST、FETCH LAST 等語法,個人習慣通常都會設定 FAST_FORWARD 來提高效率。
      2. 不要利用 Cursor 來修改和刪除資料,能明確指定為 READ_ONLY 較好。
      3. 避免在 Cursor 中進行排序

      判斷 Cursor 中的最後一筆資料
       
      利用 @@CURSOR_ROWS 來查詢最近一次 OPEN 的 Cursor 中有多少筆資料。
      DECLARE @Temp Table (EmpNO char(5),EmpName nchar(8))
      INSERt INTO @Temp VALUES ('00001','張三')
      INSERt INTO @Temp VALUES ('00002','李四')
      INSERt INTO @Temp VALUES ('00003','王五')
      
      -- Cursor 的 T-SQL 延伸語法
      DECLARE curTemp CURSOR STATIC -- 宣告此 Cursor 為 STATIC
        FOR
           (
             SELECT EmpNO,EmpName
             FROM @Temp
             WHERE EmpNO IN ('00001','00002')
           )
      
      OPEN curTemp
       
      DECLARE @EmpNO as char(5),@EmpName nchar(8)
      DECLARE @Count as smallint 
      
      SET @Count = 0 -- 設定一個計數變數
      
      FETCH NEXT FROM curTemp INTO @EmpNO,@EmpName
        WHILE (@@FETCH_STATUS = 0)
          BEGIN  
            SET @Count = @Count + 1
       
            IF @Count = @@CURSOR_ROWS
                PRINT '最後一筆資料為 ' + @EmpName
         
            FETCH NEXT FROM curTemp INTO @EmpNO,@EmpName
          END
       
      CLOSE curTemp
      DEALLOCATE curTemp
      
        說明:
      1. 由於動態資料指標會反映所有變更,因此,Cursor 內資料列數會不斷改變,@@CURSOR_ROWS 永遠不可能明確指出 Cursor 內有多少資料列數,也因此必須把 Cursor 設為靜態指標(STATIC)。
      2. 宣告 Cursor 為 STATIC,會先把資料放進 TempDB 內,應盡量縮小資料量,以免 TempDB 瞬間爆增,影響效能。
      • 2013 DBA 天團試題

      星期五, 7月 22, 2011

      [SQL] 數學運算-除法

      當一個運算子(EX:加減乘除四則運算)結合兩個不同資料類型的運算式(EX:被乘法乘法、被除數除數)時,資料類型優先順序的規則,會指定將低優先順序的資料類型,轉換為高優先順序的資料類型。如果轉換不是支援的隱含轉換,就會傳回錯誤。如果這兩個運算元運算式的資料類型相同,則作業結果就含有該資料類型。

      除法 Dividend / Divisor

      製作報表時,常常需要用百分比表示,因此會利用到除法來進行計算,使用除法有兩件注意事項
        分母不得為零
      當 T-SQL 語法中分母為零會出現 發現除以零錯誤 的錯誤訊息。
      SELECT 1.0 / 0 -- 模擬除以零錯誤
      
        NULLIF() 說明:
      • 語法:NULLIF ( express1 , express2 )
      • 傳回類型:當 express1 等於 express2 時,會傳回 NULL;當 express1 不等於 express2 時,傳回 express1 值。
      利用 NULLIF() 函數來處理分母,把分母為零轉換成 NULL ,搭配 NULL 本身的特性(任何數值除以 NULL 結果為 NULL ),就可以避免錯誤發生,而 NULLIF() 其實也算是 CASE WHEN 的應用之一。
      SELECT 
            1.0 / NULLIF(T.[分母], 0) AS [利用 NULLIF], 
            1.0 / CASE WHEN T.[分母] = 0 THEN NULL ELSE T.[分母] END AS [利用 CASE WHEN 1],
            CASE WHEN T.[分母] = 0 THEN NULL ELSE 1.0 / T.[分母] END AS [利用 CASE WHEN 2],
            CASE WHEN T.[分母] = 0 THEN 0 ELSE 1.0 / T.[分母] END AS [利用 CASE WHEN 3],
            CASE WHEN T.[分母] = 0 THEN '分母為0' ELSE '分母不為0' END AS [文字敘述]
      FROM 
            (
                SELECT 0 AS [分母]
                UNION ALL
                SELECT 3
            ) T
      
      除零錯誤

      星期五, 7月 15, 2011

      iGoogle 還原功能

      我都利用 iGoogle 的便利貼來記錄些重要或待辦事項,某天進入 iGoogle 時,嚇了一跳,我的便利貼竟然不見了,即使我把便利貼再加回來,便利貼的內容也都歸零了,當下一整個臉都綠了 ~~

      • 在 Google 搜尋頁面的右上角可以看到列圖示,請點擊 設定 => iGoogle 設定。
      iGoogle 還原功能 - 1
      • iGoogle 設定 => 一般 Tab 下方有個 疑難排解 / 回復 功能,請選擇下拉式選單,選擇要回復的時間點,再點擊立刻回復,我的便利貼內容就回來啦,感動 ~~
      iGoogle 還原功能 - 2

      星期五, 6月 17, 2011

      記憶體配置錯誤

      把 AutoCAD LT 2000 安裝在 Windows 7 32 bit 上使用,使用者回報說,AutoCAD 本身都抓不到 Windows 內的印表機,錯誤訊息是 "記憶體配置錯誤",在官方網站搜尋到修正檔案,沒想到安裝後竟然只有錯誤訊息變成英文,有注意到安裝過程中有警告訊息說語言不同,但是卻找不到中文修正檔。OrZ ~~
      •  未安裝更新前的錯誤訊息。
      記憶體配置錯誤 - 1
      記憶體配置錯誤 - 2
      • 安裝更新後,第一個錯誤訊息變成英文,第二個則是沒變。
      記憶體配置錯誤 - 3
      • 安裝更新時,語言版本不同的警告訊息。
      記憶體配置錯誤 - 4

      星期五, 5月 27, 2011

      [VFP] Windows Script Host - FileSystemObject

      之前利用COPY FILE 命令搬移公司派工圖檔時才發現,COPY FILE 命令複製檔案時,會把檔名全部變成小寫,為了避免這個問題,因此改用 Windows Script Host(WSH)- FileSystemObject(FSO)來複製檔案,就可以避免這個問題。
      oFSO = CreateObject("Scripting.FileSystemObject")
      oFSO.CopyFile((cOldFilePath),(cNewFilePath))
      RELEASE oFSO
      • 20151223 
      執行 oFSO.CopyFile 時,一直出現下面錯誤訊息

      CopyFile Error

      後來才發現沒有 Server 端寫入權限,帳號明明是 administrator,Orz

      而在VFP中,並沒有可以重新命名資料夾的指令,可以利用 FSO 的 MoveFolder 來達成。
      oFSO = CreateObject("Scripting.FileSystemObject")
      oFSO.MoveFolder((cOldDirPath),(cNewDirPath))
      RELEASE oFSO
      
      MoveFolder可以用來搬移檔案,進階使用更改資料夾名稱,而更改檔案名稱也是一樣的用法。
      oFSO = CreateObject("Scripting.FileSystemObject")
      oFSO.MoveFile((cOldFilePath),(cNewFilePath))
      RELEASE oFSO
      
      利用 RMDIR 或 RD 命令刪除資料夾時,出現 "The directory is not empty(目錄不是空的)" 錯誤,才發現資料夾內假如有隱藏的系統檔案,會無法刪除資料夾,EX:Thumbs.db,利用 FSO 即使有系統檔案也可以刪除資料夾。
      oFSO = CreateObject("Scripting.FileSystemObject")
      oFSO.DeleteFolder((lcDirPath))
      RELEASE oFSO
      
      備註:作業系統從 Windows 98 開始有 WSH;只有 Windows 95 和 Windows NT 4.0 沒有

      星期五, 5月 20, 2011

      電腦機殼外接風扇

      現在電腦機殼為了讓散熱變得好一些,通常機殼內會有風扇幫忙散熱,或是機殼本身空氣流通的範圍會增加,最近幫朋友修電腦時,看到自製外接風扇,當下有點傻眼,因為通常散熱不良的話,大家會採取的方法是把外殼拿掉,第一次看到用暴力法去改善散熱的方式。
      • 從外部看風扇,風扇要接上電源,上面開關喔
      電腦自製風扇 - 1
      • 從內部看風扇
      電腦自製風扇 - 2
      • 這張就可以很明顯看出來,是用工具強行挖個洞,再把風扇給鎖上去。
      電腦自製風扇 - 3

      好奇心驅使下,把電源打開,真是有夠吵得,為了散熱而進行的改造,換來的是噪音值飆升,還不如不安裝機殼,增加空氣流通範圍。

      星期五, 5月 06, 2011

      [SQL] BACKUP 權限

      之前在 SQL Server 2005 Express 上用 BACKUP 語法去備份資料時,都會出現下列這個錯誤,因為線上的SQL 2005 Standard 備份時,並沒有發生這個現象,所以這個問題就自動被忽略掉。
      Backup
      這幾天把 MSDN 上的 BACKUP T-SQL 介紹拿出來看看,在文中說明權限時發現這段文字
        SQL Server 必須能夠讀取和寫入裝置;執行 SQL Server 服務的帳戶必須有寫入權限
      馬上去開啟組態管理員來檢查啟動 SQL Server 的登入身分,是"網路服務",改為"本機系統",再去進行備份就可以啦,當初安裝時,只要安裝過程沒有出現錯誤就好,沒有注意到網路服務,沒有存取磁碟權限這個問題。

      Backup 2

      設定 Windows 的服務帳戶 這篇文章內提到,SQL Server 2005 Express 的 SQL Server 服務,安裝預設是內建帳戶的網路服務,但又說 "Microsoft 建議您不要對 SQL Server 或 SQL Server Agent 服務使用網路服務帳戶。這些 SQL Server 服務較適用於本機使用者或網域使用者帳戶",都已經建議,為什麼不乾脆預設值就設好,^_^ \\ ~~
      •  版本:SQL Server 2005 Express with Advance SP3

        星期五, 4月 29, 2011

        Fuji Xerox DocuPrint M205 b 過熱保護

        這幾天需要大量列印資料,資料大約有270頁左右,但是當列印至250頁左右出現過熱警訊,等待約 5 分鐘左右,M205 b 才又開始進行列印。
        •  操作面板上警示
        Fuji Xerox DocuPrint M205 b 過熱保護 1
        • Windows 上警示
        Fuji Xerox DocuPrint M205 b 過熱保護 2
        在操作說明書內(發生故障時 => 列印故障),有找到這個說明:
        • 故障:印表機於列印期間停止工作。
        • 處置方式:檢查 LCD 面板或印表機設定公用程式上是否顯示訊息。若顯示「冷卻中請稍後幾分鐘」訊息,說明印表機溫度過高,在降溫中。請稍候數分鍾。 待降溫後,印表機便會重新啟動。 
        畢竟是台小機器,沒有辦法像公司大機器一樣,一次列印這麼多,根據這次經驗,M205 列印個 200 張,最好讓它休息一下,大約250張就會出現過熱警訊。

        星期五, 4月 22, 2011

        [VFP] SPT Updatable

        在 VFP 中對 SQL Server 進行資料存取,有三種模式分別為 Remote View、SQL Pass Through(SPT) 和 CursorAdapter(CA),我一直是以 CA 為主來對資料進行存取、SPT 為查詢資料主力。

        無論是 SPT 或 CA 在前端產生的 Cursor 要對後端資料庫進行新增、更新和刪除動作(updatable),有四個屬性一定要設定,分別為 Table、KeyFieldList、UpdatableFieldList、UpdateNameList,在 CA 可以利用勾選方式輕鬆完成設定,但在 SPT 中就必須一個一個 Key,其中又以 UpdatableFieldList 和 UpdateNameList 兩個屬性最讓人討厭,因此才會想寫個 PRG 來設定屬性。
        • 參數說明 :
        • tcConnection:傳入連線。
        • tcSQL: 傳入產生此 CURSOR 的 T-SQL 語法。
        • tcTableName:SQL Server 內的 TableName,因會利用 INFORMATION_SCHEMA 的 VIEW,所以使用者必須明確指定要抓取 SQL Server 內的哪一個 Table。
        • tcAlias:當使用者用 SPT 抓取資料後,可能會另外給 CURSOR 別名,此時必須針對此 CURSOR 別名進行設定。
        • tnBuffering:設定資料緩衝,預設為 5

        星期五, 4月 15, 2011

        [Apple] 利用iTune把CD轉MP3

        之前幫大嫂把胖妞要聽的CD轉成mp3來播放,原本想說這是一件苦差事,沒想到iTune就可以簡單達到,雖然Windows Media Player也可以作到,但是它有版本的限制,老實講並不方便,假如大家有此需求,建議安裝iTune來處理。

        當把CD放進光碟機,iTune會詢問是否要把CD轉成mp3,只要按"是",iTune就會把檔案轉成mp3並放置在預設的檔案夾中;預設檔案夾位置 使用者文件夾 => 我的音樂(My Music) => iTune資料夾,以我的電腦來說,就是 C:\Documents and Settings\NB-IC\My Documents\My Music , 操作步驟如下:
        • 把CD放進光碟機,iTune會出現詢問訊息。
        [Apple] 利用iTune把CD轉MP3 - 1
        • 按下確定後,iTune就會進行轉檔的動作。
        [Apple] 利用iTune把CD轉MP3 - 2

        星期五, 3月 25, 2011

        [Win] 利用 NET USE 語法建立網路磁碟機

        Windows NT 的電腦常常發生看不到區域網路內其他電腦的情況,但放段時間又抓的到,假如用 ping 去確定電腦是否存在,又都 ping 的到,每次臨時要重設網路磁碟時,遇上這問題,真的是會讓人抓狂,總不可能在那賭運氣,等電腦抓到。

        利用 NET USE 即使看不到區域網路上的電腦,但只要 ping 的到,還是可以順利建立網路磁碟機。

        命令提示字元內,打出下列語法就可以連結
        -- 一:(*)不指定磁碟機名稱,電腦會自動指派一個可用名稱
        NET USE * \\ComputerName\ShareName
        
        -- 二:(DeviceName)則是自己指派,EX:Z:。
        NET USE DeviceName \\ComputerName\ShareName
        
        -- 三:輸入使用者帳密
        NET USE * \\ComputerName\ShareName password /user:UserName
        

        星期五, 3月 18, 2011

        UNION

        UNION 將兩個或更多查詢的結果集結合成單一結果集(縱向連結資料),個人覺得 UNION 最好用的地方在於連接歷史資料庫,尤其是習慣把每一年資料拆成一個 Table 來整理,EX:Order98、Order99。

          SQL UNION 使用限制:
        • 欄位數目和順序需要一致
        • 欄位資料型態必須相容(隱含式轉換)
          VFP UNION 使用限制:
        • 除了上述限制外,在 8.0 和 9.0 版本裡假如資料行有 Memo 資料型態,一定要用 UNION ALL,用 UNION 會錯誤,8.0 之前版本則是沒有這個限制。
          SQL、VFP UNION 使用上需要注意的地方:
        • UNION 和 UNION ALL的差異:UNION 會自動過濾重複資料,而 UNION ALL 則是會把全部資料都列出來;因為 UNION 會過濾重覆資料,所以在效率上,UNION ALL會比較快一些。
        • 欄位名稱以第一個資料集為依據。
        • Order By 必須放在整個 T-SQL 語法的最後。
        -- 建立範例資料
        DECLARE @NY table (EmployeeID char(4),Employee char(8),Birthday datetime)
        DECLARE @TW table (EmployeeID char(4),Employee char(8),Birthday datetime)
         
        -- Ray 和 Doris 這兩個人名,同時存在 @TW 和 @NY 中  
        INSERT INTO @NY VALUES('NY01','Emma','19860606')
        INSERT INTO @NY VALUES('NY02','Ray','19840404')
        INSERT INTO @NY VALUES('NY03','Doris','19870707')
        INSERT INTO @NY VALUES('NY04','Peggie','19890909')
        INSERT INTO @NY VALUES('NY05','Angel','19810101')
        INSERT INTO @TW VALUES('TW01','Terry','19901010')
        INSERT INTO @TW VALUES('TW02','Ray','19820202')
        INSERT INTO @TW VALUES('TW03','Doris','19830303')
        INSERT INTO @TW VALUES('TW04','Fanny','19880808')
        INSERT INTO @TW VALUES('TW05','Jarry','19850505')
        

        星期五, 3月 11, 2011

        [SQL] Trigger - inserted & deleted Table

        deleted Table 和 inserted Table 為 Triiger 使用的兩個特殊暫存資料表(交易紀錄的檢視表),其欄位名稱、順序和資料型態都跟原來的 Table 一致,可以利用它們了解 INSERT、UPDATE 和 DELETE T-SQL 語法觸發 Triiger 時,插入、修改或是刪除哪些資料。

        inserted Table 會儲存 INSERT 和 UPDATE 前的資料、deleted Table 則會儲存 UPDATE 後和 DELETE 的資料。
        •  利用表格表示
        Trigger
        • 利用圖形表示
        [SQL] Trigger - inserted & deleted Table - 2
        SQL Server 會在 TempDB 中自動建立並管理,無法直接修改資料表內的資料或是修改其結構(EX:CREATE INDEX),當Trigger 結束時,暫存的 deleted Table 和 inserted Table 會自動消失。
        • 整合 inserted 和 deleted 並判斷類別(新增、更新或刪除)
        利用 FULL JOIN 把 inserted Table 和 deleted Table 整合在一起,再透過判斷主要連結欄位是否為 NULL 或 相等,來判斷資料是新增、修改或是刪除。
        SELECT 
          COALESCE(I.KeyFields,D.KeyFields) AS KeyFields, -- 利用 COALESCE() 來找出 KeyFields
          'Kind' = CASE
                     WHEN D.KeyFields IS NULL THEN '新增' -- 利用 D.KeyFields IS NULL 來判斷是否為新增
                     WHEN I.KeyFields IS NULL THEN '刪除' -- 利用 I.KeyFields IS NULL 來判斷是否為刪除
                     WHEN I.KeyFields = D.KeyFields THEN '更新' -- 利用 I.KeyFields = D.KeyFields 來判斷是否為更新
                   END
        FROM 
          inserted AS I 
          FULL JOIN -- 利用 FULL JOIN 來連結兩個暫存資料表
          deleted AS D ON I.KeyFields AND D.KeyFields
        
        • 利用 EXISTS 來判斷資料是否存在 inserted 和 deleted
        -- 新增  
        IF EXISTS(SELECT 1 FROM inserted) AND NOT EXISTS(SELECT 1 FROM deleted)
        
        -- 更新
        IF EXISTS(SELECT 1 FROM inserted) AND EXISTS(SELECT 1 FROM deleted)
        
        -- 刪除
        IF NOT EXISTS(SELECT 1 FROM inserted) AND EXISTS(SELECT 1 FROM deleted)
        

        星期五, 3月 04, 2011

        [VFP] GOMONTH() 應用

        說明:
        GOMONTH(dExpression | tExpression, nNumberOfMonths);
        對於給定的日期或日期時間,傳回其指定之前或之後月份數目的日期。

        參數說明:
        1. dExpression | tExpression:輸入 Date 或是 DateTime 資料型態
        2. nNumberOfMonths:正數表示加給個月份;負數代表減幾個月。
        回傳值:Date 資料型態
        備註: GOMONTH() 不支援 1753年01月01日之前的日期
        • 計算月份的最後一天、當月總共有幾天
        邏輯:要計算當月份的最後一天,先找到下個月的第一天,再減一天就是當月的最後一天;最後一天同時也代表著當月份的總天數。
        LOCAL dDate,dLastDay AS date
        LOCAL iTotalDay AS integer 
        
        dDate = DATE() -- 使用者自訂日期
        
        -- 先利用DATE() 來找出自訂日期月份的第一天,
        -- 然後利用GOMONTH() 加一個月找到下個月第一天,
        -- 再減一天,找到自訂日期月份的最後一天。
        dMonthLastDate = GOMONTH(DATE(YEAR(dDate),MONTH(dDate),1),1)-1
        
        -- 邏輯同上,最後再利用DAY()函數把天數抓出來就行
        iTotalDay = DAY(dMonthLastDate)
        

        星期日, 1月 09, 2011

        [Win] Win7 和 內碼輸入法

        在 Win 7 上要利用內碼輸入法來輸入特殊符號,請依下列步驟:
        1. 切換到微軟「新注音」或「新倉頡」輸入法,並確認在「中文模式」下(「英數模式」無法使用內碼輸入法)。
        2. 入前導字元「`」(鍵盤上橫排數字鍵的左邊按鍵),就接著輸入「b」(不用刻意區分大小寫),再加上內碼(EX:A148為?)。
        內碼輸入法 0

        星期日, 1月 02, 2011

        [Win] 消失的語言列

        下圖為語言列在Win 7上的圖形

        消失的語言列0

        原本是在測試 Zebra Win7 32 bit 的 Driver,沒想到要打中文時,竟然完全都不能打,而且語言列也不見,臉都綠了,>.<。

        一開始我是先到控制台內嘗試把語言列給叫出來,想說叫出來就可以搞定這個問題,沒想到語言列的相關設定都設定好,也一樣無解。
        • 開始功能表 => 控制台 =>  變更鍵盤或其他輸入方法 => 鍵盤與語言 => 變更鍵盤 => 語言列;確定語言列是否勾選到"隱藏",建議勾選"固定在工作列"並取消 "當語言列不在作用中時,將它顯示為透明"。
        消失的語言列0-1
        消失的語言列0-2