20120325

SQL2008R2 – 還原資料庫初探

說明

好啦,一時手誤,把資料庫不小心UPDATE了好幾筆……

 

第一件想到的是,怎麼辦,怎麼救?

 

交易記錄檔?看不懂。

 

備份檔?剛建的資料庫還沒作定期備份設定……

 

好吧,只好找出原始檔慢慢比對,重新KEY-IN。

 

順便把這次找到的解法,記錄在「參考」處。

 

 

解決方法

1. 沒備份,所以沒解。

2. 觀看交易記錄檔的語法

DBCC LOG (DBNAME, TYPE={0,1,2,3,4})

3. 快作定期備份吧。

 

 

參考網址

如何:還原到某個時間點 (Transact-SQL)

Rolling back and update command in Sql Server 2000

Introduction to Backup and Restore Strategies in SQL Server

View Transaction Log

[SQL]交易記錄檔 LDF 太大,該如何處理?

如何取得SQL Server交易記錄檔的內容

資料庫沒有備份,該如何使用交易記錄還原

RESTORE (Transact-SQL)

SQL Server - 資料誤刪救援方式

20120321

.NET Framework - 常用例外

說明

例外處理是現代程式語言的一大特點,.NET Framework也提供了相當豐富的例外供程式設計師使用。但是.NET Framework如此浩瀚,要在其中找到一個適用的Exception,可謂是大海撈針,所以我特別在此將常用之例外列出來,以資參考。

 

 

常用例外

Exception

Namespace

Name

Description

ArgumentOutOfRangeException

System

System.ArgumentOutOfRangeException

當引數值超出了叫用 (Invoke) 方法所定義值的容許範圍時所擲回的例外狀況。

DivideByZeroException

System

System.DivideByZeroException

嘗試將整數或小數值除以零時所擲回的例外狀況。

Exception

System

System.Exception

表示應用程式執行期間所發生的錯誤。

IndexOutOfRangeException

System

System.IndexOutOfRangeException

嘗試使用陣列以外的索引來存取陣列的元素時所擲回的例外狀況。 此類別無法被繼承。

InvalidCastException

System

System.InvalidCastException

無效的轉型 (Casting) 或明確轉換所擲回的例外狀況。

OverflowException

System

System.OverflowException

當檢查內容中的算數、轉型 (Casting) 或轉換作業發生溢位時所擲回的例外狀況。

 

參考

Exception 類別

Handling and Throwing Exceptions

Design Guidelines for Exceptions

Exception Handling

ArgumentOutOfRangeException 類別

DivideByZeroException 類別

Exception 類別

IndexOutOfRangeException 類別

InvalidCastException 類別

OverflowException 類別

VS2010 - Project(x.csproj) cannot be opened because its project type (.csproj) is not supported by this version of the application.

說明

剛才同學傳給了專案檔給我,要我幫忙看看,他是用VS2008開發的,但是我用VS2010打開時,卻出現以下訊息:

201200321-1-VS2010 - Project(x.csproj) cannot be opened because its project type (.csproj) is not supported by this version of the application-W

我記得明明VS2010有支援VS2008的專案檔啊?難不成是因為他給我的專案檔已經有Upgrade過了?

 

上網找找,果然有人有同樣問題。照著作,就解決了。

 

 

解決方法

1. 開啟「開始 / 程式集 / Microsoft Visual Studio 2010 / Visual Studio Tools / Visual Studio Command Prompt」

2. 輸入「devenv.exe /resetskippkgs」

3. 開啟之前未能開啟的專案檔。

4. 成功。

 

 

參考

'C:\xxx.csproj' cannot be opened because its project type (.csproj) is not supported by this version of the application.

20120320

T-SQL - 使用MERGE指令組合不同資料表之資料

說明

SQL SERVER 2008中,新增了一項指令「MERGE」。此指令之前僅見於ORACLE中,這次微軟將它加入到SQL SERVER 2008,可謂是從善如流。

 

那這個「MERGE」到底有什麼用呢?

 

常常處理資料庫的人就會知道,資料庫最麻煩的地方就是在於「統合」資料。因為資料唯有在和其他資料比對之後,才會出現有意義的資料;所以資料間的統合,就是資料庫最大的賣點。

 

但是這對於我們程式設計師來說,卻是一項惡夢。

 

在沒有「MERGE」這個指令之前,我們若是要統整二張不同的資料表(或是同一張資料表間的資料進行再統合),都需要下不少的T-SQL指令,而且還不一定能夠達成我們想要的結果。

 

甚至有時乾脆利用C#或其他程式語言,來代替T-SQL達到我們想要的結果。其原因就在於目前的T-SQL對於逐筆資料的操作,並不是那麼如其他程式語言那樣地直覺。

 

但是現在有了「MERGE」,我們就可以補上這一塊缺口。

 

例如說,我們有A, B二個資料表,其中A的KEY和B的KEY相同,但是其他欄位不同,所以我們想要將這二個表合成一張新的C資料表。這在以前的T-SQL不知道要花多少工,通常我都是直接利用C#來完成這項工作(因為我不太會用CURSOR)。不過現在我們就可以利用「MERGE」這項指令來完成這項工作。

 

下面看看例子。

 

 

解決方法

語法:

  1: DECLARE @mk int
  2: DECLARE @mBirth datetime
  3: DECLARE @mSex int
  4: DECLARE @MonthAgeMax int
  5: 
  6: SET @mk = 6
  7: SET @mBirth = '2011/10/22'
  8: SET @mSex = 0
  9: SET @MonthAgeMax = 12
 10: 
 11: -- 宣告暫存資料表,用以儲存GROUP BY資料
 12: DECLARE @TEMP_1 TABLE
 13: (
 14:   MonthAge int,
 15:   Height float
 16: )
 17: 
 18: -- 塞入資料
 19: INSERT INTO @TEMP_1
 20:   SELECT
 21:   (DATEDIFF(MM, @mBirth, blTimeRecord)-1) AS MonthAge,
 22:   MAX(blHeight) AS Height
 23: FROM Log
 24: WHERE
 25:   (mk = @mk)
 26: GROUP BY (DATEDIFF(MM, @mBirth, blTimeRecord) -1)
 27: 
 28: -- 宣告回傳用Table
 29: DECLARE @TEMP_2 TABLE
 30: (
 31:   MonthAge int,
 32:   Height float NULL,
 33:   P1 float,
 34:   P3 float,
 35:   P5 float,
 36:   P15 float,
 37:   P25 float,
 38:   P50 float,
 39:   P75 float,
 40:   P85 float,
 41:   P95 float,
 42:   P97 float,
 43:   P99 float
 44: )
 45: 
 46: -- 塞入指定期間之資料
 47: INSERT INTO @TEMP_2
 48: SELECT
 49:   MonthAge, NULL, w.P1, w.P3,w.P5,
 50:   w.P15, w.P25, w.P50, w.P75,
 51:   w.P85, w.P95, w.P97, w.P99
 52: FROM WTO_Height AS w
 53: WHERE 
 54:   (w.Sex = @mSex) AND
 55:   (w.MonthAge <= @MonthAgeMax)
 56: 
 57: -- 塞入資料
 58: MERGE INTO @TEMP_2 AS C2
 59: USING @TEMP_1 AS C1
 60: ON (C1.MonthAge = C2.MonthAge)
 61: WHEN MATCHED THEN
 62:   UPDATE SET C2.Height = C1.Height
 63: WHEN NOT MATCHED BY TARGET THEN
 64:   INSERT (MonthAge, Height)
 65:   VALUES (C1.MonthAge, C1.Height);
 66: 
 67: -- 回傳資料
 68: SELECT * FROM @TEMP_2


說明:

這是一段Stored Procedure,其中,我們先將資料匯入到@TEMP_1, @TEMP_2二個暫存資料表,之後再利用MERGE指令,將@TEMP_1的資料匯總到@TEMP_2中。

 

 

參考網址

MERGE (Transact-SQL)

使用 MERGE 插入、更新,和刪除資料

VS2010 - SQL03070 This statement is not recognized in this context

說明

我在寫N-Tier程式專案的時候,通常會將資料層的Stored Procedure和AP層的分開,並利用Visual Studio的Database Project,來存放專案會用到的Stored Procedure, Function, Database Definition等等。

 

但是每次編譯的時候,Visual Studio都會跳出如下的訊息

SQL03070: This statement is not recognized in this context

 

這實在是很煩人的訊息,一個Stored Procedure大概可產生三到四個如此的錯誤,但是Database Project對我而言,只是用來存放這些T-SQL物件的地方,而不用真真正正地編譯。所以我一直很想把這個錯誤給隱藏掉。

 

上網找了找,原來是Visual Studio期望存在Stored Procedure中的T-SQL敘述,就是只有從CREATE PROCEDURE開始,但是我還有許多其他的敘述要用啊……

 

就算選擇該Database Project不要列入編譯中,也是無用。還好網友提供了相關的解決方法。

 

 

解決方法

1. 選擇相關的Stored Procedure檔案,右點選「Properties / Build Action / Not In Build」

 

2. 完成,收工

 

 

參考

SQL03070: THIS STATEMENT IS NOT RECOGNIZED IN THIS CONTEXT

20120319

T-SQL - 使用暫存資料表

說明

暫存資料表是使用SQL Server時非常重要的功能,因為很多時候,我們會需要一些特殊欄位的資料表,但是現有的SQL敘述無法滿足我們程式設計師的需求(也可能是因為自己學藝不精@@)。所以這時候我們就需要自己從不同的資料表來取出所需的資料,以便匯總成一個可用的資料表。

 

又有可能是,有些計算,會影響到實際的資料表,但是這並不是我們所希望的,這時候就可以利用暫存資料表,但滿足我們修改資料的需求。

 

以下我們將介紹暫存資料表的用法。

 

 

用法

1. 將暫存資料表建立在硬碟上

語法:

  1: CREATE TABLE #TEMP
  2: (
  3:     KEY int,
  4:     NAME nvarchar(50)
  5: )
  6: 

說明:

在暫存資料表前面加上「#」,則暫存資料表將會建立在系統的「tempdb」資料庫中。此暫存資料表只有建立者可以使用,其他人可以看到,但無法存取;當建立該暫存資料表的連線結束之時,SQL Server會自動將其刪除。

 

2. 將暫存資料表建立在記憶體中

語法:

  1: DECLARE @TEMP TABLE
  2: (
  3:     KEY int,
  4:     NAME nvarchar(50)
  5: )
  6: 

說明:

在暫存資料表前面加上「@」,並使用「DECLARE」來作變數宣告,則暫存資料表將會建立在記憶體中。此暫存資料表,其他人看不到,且建立該暫存資料表的Function, Stored Procedure, Batch結束之時,SQL Server會自動將其刪除。

 

 

參考網址

CREATE TABLE (Transact-SQL)

建立#TempTable與Declare @TempTable有何差別

T-SQL - 以計算值進行GROUP BY

說明

GROUP BY可以說是SQL中最重要的語法了。因為我們搜集資料的目的,就是從大量的資料中找出有用的資訊,其中又以各統計函數 (如SUM(), AVG(), MAX(), MIN(), COUNT())等等所代表的涵意最為重要。但是要利用到這些功能,就需要GROUP BY這個語法來將資料群組化,以便進行群組化。

尤其是常常使用到的功能就是要將計算過後的資料進行群組化,這時候就需要一些小技巧(語法)來達成我們想要的結果了。

 

 

解決方法

1. 以計算值進行GROUP BY

語法:

  1: SELECT
  2:     (DATEDIFF(MM, @mBirth, TimeRecord) – 1) AS MonthValue,
  3:     MAX(Height) AS Height
  4: FROM dbo.HealthLog
  5: WHERE (mk > 0)
  6: GROUP BY (DATEDIFF(MM, @mBirth, TimeRecord) – 1)
  7: 

說明:

這一句是利用「DATEDIFF」這個函式,將原有的日期減去一個特定的日期,以便得到二個日期間「差了幾個月份」,再針對此值進行GROUP BY,以得到我們想要的結果。

 

 

參考網址

CAST 和 CONVERT (Transact-SQL)

20120318

兒童生長曲線

說明

生命中有了一個新生命之後,要作的事也隨之越來越多。

之前對照小朋友的生長曲線之時,都是使用兒童健康手冊上所附的圖,但是很小又不好對,乾脆自己來寫一隻程式對應之。

但是要找到生長曲線的原始資料,才能畫出如兒童健康手冊上的圖。

利用Google,毫不費力地就找到了原始資料。特此作個記錄,以免日後忘記。

 

 

參考

新版兒童生長曲線圖(自98年5月18日正式啟用)

新版兒童生長曲線(0-5歲)原始數據

The WHO Child Growth Standards

T-SQL - 對bit格式欄位進行GROUP BY

說明

GROUP BY可以說是SQL中最重要的語法了。因為我們搜集資料的目的,就是從大量的資料中找出有用的資訊,其中又以各統計函數 (如SUM(), AVG(), MAX(), MIN(), COUNT())等等所代表的涵意最為重要。但是要利用到這些功能,就需要GROUP BY這個語法來將資料群組化,以便進行群組化。

 

但是如果我們要統計的欄位,其格式是「bit」的話,那要怎麼辦呢?

 

 

解決方法

語法:

  1: SELECT
  2:     CONVERT(CHAR(8), TimeRecord, 112) AS RecordDate,
  3:     SUM(CONVERT(int, IsSold)) AS SoldTimes
  4: FROM dbo.Baby_Log
  5: WHERE
  6:     (mk = @mk) AND
  7:     (IsSold = 1)
  8: GROUP BY CONVERT(CHAR(8), TimeRecord, 112)
  9: ORDER BY RecordDate DESC
 10: 

說明:

這一句,我是利用「CONVERT」這個函式,將原有的bit欄位「IsSold」改型別為int;如此一來就可以利用統計函式(如SUM()),來進行GROUP BY,以得到我們想要的結果。

 

 

參考網址

CAST 和 CONVERT (Transact-SQL)

SQL Aggregate BIT Columns with Group By

ASP.NET - 加入Chart控制項後,出現HTTP Error 500.23 錯誤

說明

今天在寫一隻記錄女兒生長記錄的ASP.NET程式的時候,出現了以下錯誤:

201200318-1-ASP.NET-加入Chart控制項後,出現HTTP Error 500.23錯誤-W

在此之前,我只不過是在網頁上加入了Chart控制項,有可能是這個問題嗎?

 

網頁上已經有提供了幾種解決方式:

1. 將定義Chart的Configuration移到system.webServer區段。

2. 或是將system.webServer/validation@validateIntegratedModeConfiguration改為「false」。

3. 或是將應用程式改至Classic Application Pool。

 

 

解決方法

試了第一種方法之後,果然成功地解決了這個問題。

也就是將原本放在system.web的設定

  1: <system.web>
  2: 
  3: <httpHandlers>
  4: 
  5: <add path="ChartImg.axd" verb="GET,HEAD,POST" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
  6: 
  7: validate="false" />
  8: 
  9: </httpHandlers>
 10: 

將它改放到system.webServer(其實本來就有了,所以我就把system.web的設定給隱藏起來),這樣就解決了這個問題囉。

  1: <system.webServer>
  2: 
  3: <handlers>
  4: 
  5: <remove name="ChartImageHandler" />
  6: 
  7: <add name="ChartImageHandler" preCondition="integratedMode" verb="GET,HEAD,POST"
  8: 
  9: path="ChartImg.axd" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 10: 
 11: </handlers>
 12: 
 13: </system.webServer>
 14: 

完成。

 

 

參考

[IIS]IIS7.0發生An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode.錯誤

Error: An ASP.NET setting has been detected that does not apply in Integrated managed pipeline mode

20120317

T-SQL - 以月份或是日期進行GROUP BY

說明

GROUP BY可以說是SQL中最重要的語法了。因為我們搜集資料的目的,就是從大量的資料中找出有用的資訊,其中又以各統計函數 (如SUM(), AVG(), MAX(), MIN(), COUNT())等等所代表的涵意最為重要。但是要利用到這些功能,就需要GROUP BY這個語法來將資料群組化,以便進行群組化。

 

尤其是常常使用到的功能就是要將資料依「月份」或是「日期」來進行群組化,這時候就需要一些小技巧(語法)來達成我們想要的結果了。

 

 

解決方法

1. 以日期進行GROUP BY

語法:

  1: SELECT
  2: 
  3: CONVERT(CHAR(8), RecordTime, 112) AS Day,
  4: 
  5: SUM(Money) AS DailyAmount
  6: 
  7: FROM Sales
  8: 
  9: WHERE (KEY = 3)
 10: 
 11: GROUP BY CONVERT(CHAR(8), RecordTime, 112)
 12: 
 13: ORDER BY Day DESC
 14: 


說明:

這一句,我是利用「CONVERT」這個函式,將原有的日期改為一個型別為char(8)的字串,然後針對此字串進行GROUP BY,以得到我們想要的結果。其中的112代表的是ISO制定的標準日期格式,也就是yyyymmdd。詳見參考中的「CAST 和 CONVERT (Transact-SQL)」。

 

 

2. 以月份進行GROUP BY

語法:

  1: SELECT
  2: 
  3: CONVERT(CHAR(6), RecordTime, 112) AS Day,
  4: 
  5: SUM(Money) AS DailyAmount
  6: 
  7: FROM Sales
  8: 
  9: WHERE (KEY = 3)
 10: 
 11: GROUP BY CONVERT(CHAR(6), RecordTime, 112)
 12: 
 13: ORDER BY Day DESC
 14: 

說明:

這一句,我是利用「CONVERT」這個函式,將原有的日期改為一個型別為char(6)的字串,然後針對此字串進行GROUP BY,以得到我們想要的結果。其中的112代表的是ISO制定的標準日期格式,也就是yyyymmdd。詳見參考中的「CAST 和 CONVERT (Transact-SQL)」。

 

各位看倌可能注意到了,這二句的差別只在轉換出來的char長度,因為格式是yyyymmdd的關係,若是長度為8則成為一個完整的日期;若長度為6則只是月份,這就是控制GROUP BY顯示資料的語法。

 

 

參考

CAST 和 CONVERT (Transact-SQL)

20120316

20120314

C# –文字方塊保持在最下方(也就是「自動捲軸」囉)

說明

TextBox是設計程式時常用到的元件,但是大量更新的時候,我們通常會想要將文字方塊保持在最下面,持續顯示更新的訊息。

 

剛好最近比較閒,上網找一下解決方法。

 

 

解決方法

不廢話,重點二行程式先秀出來。

  1: textbox1.SelectionStart =textbox1.Text.Length
  2: 
  3: textbox1.ScrollToCaret()
  4: 

其實,就是將游標移到文字方塊的游標移到最後,並將文字方塊設定顯示至游標處。

 

 

參考

VB.NET - TextBox 中的scrollbar 捲軸自動滾到最底端

C# – 防止文字方塊更新時閃爍

說明

TextBox是設計程式時常用到的元件,但是大量更新的時候,往往看它閃個不停。

 

剛好最近比較閒,上網找一下解決方法。

 
 
解決方法

不廢話,重點二行程式先秀出來。

  1:                 textBox1.SelectionStart = textBox1.Text.Length;
  2:                 textBox1.SelectedText = "-" + i.ToString() + "-" + Environment.NewLine;
  3: 

其實,就是將游標移到文字方塊的游標移到最後直接將文字插入。

 

 

參考

无闪烁地快速附加字符串到TextBox控件

C# – 如何快速地更新文字方塊(TextBox)的內容

說明

TextBox是設計程式時常用到的元件,但是每次使用的時候,我都有些疑惑:

 

1. 設定TextBox.Text最快的方式為何?

2. 若要不斷更新大量文字,那是直接指定TextBox.Text的值會比較快?還是藉由StringBuilder儲存更新文字才套用至TextBox.Text比較快?

 

剛好最近比較閒,所以就寫了隻程式比較一下。

 

 

解決方法

首先一定要先加入「using System.Diagnostics」,因為將使用到其中的StopWatch類別,用以計算執行的時間。

 

測試的方式是重複將「-1-」(中間數字會遞增至1000),以TextBox顯示,並會捲動捲軸至最新的資料。

 

我想到了四種設定方式,來測試到底何種方式較快。

 

1. 將要更新的文字放入StringBuilder中,然後再套用至TextBox.Text。

  1:             textBox1.Text = string.Empty;
  2:             StringBuilder sb = new StringBuilder(100000);
  3: 
  4:             Stopwatch sw = new Stopwatch();
  5:             sw.Start();
  6:             for (int i = 0; i < 1000; i++)
  7:             {
  8:                 sb.AppendLine("-" + i.ToString() + "-");
  9:                 textBox1.Text = sb.ToString();
 10:                 textBox1.SelectionStart = textBox1.Text.Length;
 11:                 textBox1.ScrollToCaret();
 12:             }
 13:             sw.Stop();
 14:             MessageBox.Show(sw.ElapsedMilliseconds.ToString());
 15: 

2. 直接指定TextBox.Text的文字

  1:             textBox1.Text = string.Empty;
  2: 
  3:             Stopwatch sw = new Stopwatch();
  4:             sw.Start();
  5:             for (int i = 0; i < 1000; i++)
  6:             {
  7:                 textBox1.Text += "-" + i.ToString() + "-" + Environment.NewLine;
  8:                 textBox1.SelectionStart = textBox1.Text.Length;
  9:                 textBox1.ScrollToCaret();
 10:             }
 11:             sw.Stop();
 12:             MessageBox.Show(sw.ElapsedMilliseconds.ToString());
 13: 

3. 直接將文字插入至TextBox.Text的最後面 (就方法論而言應該是最快的吧)

  1:             textBox1.Text = string.Empty;
  2: 
  3:             Stopwatch sw = new Stopwatch();
  4:             sw.Start();
  5:             for (int i = 0; i < 1000; i++)
  6:             {
  7:                 textBox1.SelectionStart = textBox1.Text.Length;
  8: 
  9:                 textBox1.SelectedText = "-" + i.ToString() + "-" + Environment.NewLine;
 10:                 textBox1.ScrollToCaret();
 11:             }
 12:             sw.Stop();
 13:             MessageBox.Show(sw.ElapsedMilliseconds.ToString());
 14: 

4. 將要更新的文字放入StringBuilder中,然後再套用至TextBox.Text的最後面。(有點多此一舉)

  1:             textBox1.Text = string.Empty;
  2:             StringBuilder sb = new StringBuilder();
  3: 
  4:             Stopwatch sw = new Stopwatch();
  5:             sw.Start();
  6:             for (int i = 0; i < 1000; i++)
  7:             {
  8:                 sb = new StringBuilder();
  9:                 sb.Append("-" + i.ToString() + "-" + Environment.NewLine);
 10:                 textBox1.SelectionStart = textBox1.Text.Length;
 11:                 textBox1.SelectedText = sb.ToString();
 12:                 textBox1.ScrollToCaret();
 13:             }
 14:             sw.Stop();
 15:             MessageBox.Show(sw.ElapsedMilliseconds.ToString());
 16: 
 17: 
 18: 

5. 程式介面如下圖

201200313-1-如何快速地更新文字方塊(TextBox)的內容-W

統計結果如下 (單位是微秒(ms),最後一行是平均值)

201200313-2-如何快速地更新文字方塊(TextBox)的內容-W

 

 

結論

經過了十次的比較,我得出了以下的結論:

 

1. StringBuilder在一般添加文字較快,但在此處差異不大 (方法1和方法2約差0.2秒;方法3和方法4約差0.02秒)。

2. 直接將文字填入TextBox.Text的最後是最快的。(好像在說廢話)

3. 方法1和方法2因為是重新填入大量資料,所以TextBox閃爍得很厲害。

 

以上的結論和大家分享一下囉。

 

 

參考

Stopwatch 建構函式

无闪烁地快速附加字符串到TextBox控件