2016年12月28日 星期三

[ASP.NET MVC] 登入後,自動導向使用者原本Request的Url

練習筆記...


User 驗証未通過,登入後,自動導向User原本Request的Url,三種作法:
1. 使用FormsAuthentication
2. 使用ViewBag
3. 使用讀寫屬性


1. 使用FormsAuthentication
FormsAuthentication.RedirectFromLoginPage(username, false);

2.使用ViewBag

@using (Html.BeginForm("index", "login", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { autocomplete = "off" }))
{
@Html.TextBoxFor(m => m.Account)
@Html.TextBoxFor(m => m.Password)

<button class="btn btn-lg btn-primary btn-block" type="submit">登入</button>
}

[AllowAnonymous, HttpGet]
public ActionResult Index(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}


3.使用讀寫屬性

public string ReturnUrl { get; set; }


@using (Html.BeginForm("index", "login", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { autocomplete = "off" }))
{
@Html.TextBoxFor(m => m.Account)
@Html.TextBoxFor(m => m.Password)

<button class="btn btn-lg btn-primary btn-block" type="submit">登入</button>

}


[HttpGet]
public ActionResult Index(string returnUrl)
{
LoginViewModel model = new LoginViewModel() { ReturnUrl = returnUrl };
return View(model);
}


HttpPost ActionResult


[HttpPost]
public ActionResult Index(LoginViewModel data, string returnUrl)
{
//Todo something

if (string.IsNullOrWhiteSpace(returnUrl))
//RedirectToAction default url or other.
else
return Redirect(returnUrl);

return View();
}


Ref:
1. ASP.net MVC整合FormsAuthentication表單驗證登入
https://dotblogs.com.tw/shadow/archive/2014/03/01/144191.aspx
2. Asp.net MVC 實作登入驗證(1)
http://marco.easyusing.com/2013/10/mvc-1-mvc-mvc-mvc5-build-4.html

[ASP.NET MVC] Cookie與FormsAuthentication表單驗證自動登入

練習筆記...


[寫入Cookie]

寫法一:
HttpCookie cookie = new HttpCookie("UserData");
cookie.Value = JsonConvert.SerializeObject(userData);
cookie.Expires = DateTime.Now.AddDays(1d);

Response.Cookies.Add(cookie);



寫法二:
HttpCookie cookie = new HttpCookie("UserData")
{
       Value = JsonConvert.SerializeObject(userData),
       Expires = DateTime.Now.AddDays(1d),
};
Response.Cookies.Add(cookie); 


[取得Cookie]
HttpCookie authCookie = Request.Cookies["UserData”];


[FormsAuthentication寫入Cookie] 

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
      version: 1,
      name: data.Account,
      issueDate: DateTime.Now,
      expiration: DateTime.Now.AddDays(1),
      isPersistent: false,
      userData: JsonConvert.SerializeObject(userData),
      cookiePath: FormsAuthentication.FormsCookiePath);

var encryptTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptTicket);
cookie.Expires = ticket.Expiration;
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);

※ Cookie name 一定要用FormsAuthentication的CookieName => FormsAuthentication.FormsCookieName


[取得FormsAuthentication寫入的Cookie]

HttpCookie cookie = GetCookie(FormsAuthentication.FormsCookieName);



Ref:
1. 寫入 Authentication Cookie 的 FormsAuthenticationTicket.UserData
2. session與cookies與FormsAuthentication自動登入機制
3. ASP.net MVC整合FormsAuthentication表單驗證登入

2016年12月26日 星期一

[ASP.NET MVC] 空白MVC專案實作BundleConfig

練習筆記...


[實作步驟]

1. 在「App_Start」資料夾自行建立「BundleConfig.cs」

2. 在Global.asax.cs 註冊Bundles


BundleConfig.RegisterBundles(BundleTable.Bundles);


3. Web.Config新增Optimization 命名空間

<namespaces>
    <add namespace="System.Web.Optimization"/>   
</namespaces>


[使用方法]

@Styles.Render("~/Content/css”)
@Scripts.Render("~/Scripts/bootstrap”)
@Scripts.Render("~/Scripts/jquery”)



Ref:
http://demo.tc/post/779
http://aspnetmars.blogspot.tw/2016/05/aspnet-mvc-bundleconfig.html

2016年12月25日 星期日

[MVC] Server Error "owin:AutomaticAppStartup"

遇到就筆記一下…


[問題描述]

在空白MVC專案,從NuGet Package 安裝Owin套件後執行,發生錯誤訊息「To disable OWIN startup discovery, add the appSetting owin:AutomaticAppStartup with a value of "false" in your web.config…」


[錯誤訊息]

'/' 應用程式中發生伺服器錯誤。


The following errors occurred while attempting to load the app.
- No assembly found containing an OwinStartupAttribute.
- No assembly found containing a Startup or [AssemblyName].Startup class.
To disable OWIN startup discovery, add the appSetting owin:AutomaticAppStartup with a value of "false" in your web.config.
To specify the OWIN startup Assembly, Class, or Method, add the appSetting owin:AppStartup with the fully qualified startup class or configuration method name in your web.config.



[解決方案]

在Web.config加入
<add key="owin:AutomaticAppStartup" value="false" /> 



Ref: 
OwinStartupAttribute required in web.config to correct Server Error

2016年12月4日 星期日

[LINQ] LINQ to SQL 執行各種 Join 查詢的技巧 (轉貼)

A note to myself.

轉貼自Will 保哥:

http://blog.miniasp.com/post/2010/10/14/LINQ-to-SQL-Query-Tips-INNER-JOIN-and-LEFT-JOIN.aspx


如果要改成 LEFT JOIN 語法,則必須修改成以下 LINQ 語法:
from c in Categories
join o in Products on c.CategoryID equals o.CategoryID into ps
from o in ps.DefaultIfEmpty()
select new { c.CategoryName, o.ProductName }
因為撰在 LINQ 撰寫 LEFT JOIN 時的觀念與 T-SQL 不太一樣,要用「物件」的角度比較能理解其語法所代表的意義,所以上述的語法可以這樣解釋:
取出 Categories 資料並放入 c 變數,接著再與 Products 做 JOIN 並將 JOIN 後的結果放入 ps 變數(注意:並非第二行的 o 變數),這時再宣告一個資料來源 o 其資料來自於「修改過的 ps 變數」,且修改的方式為 ps.DefaultIfEmpty(),意即代表若 ps ( 也就是 Products 經過 join 篩選後的資料 ) 無任何資料時,還是回傳一筆 Default 的資料(也就是預設的 null 資料)。






我發現許多人對使用 LINQ 執行 JOIN 查詢並不是那麼的熟悉,而且語法也不見得像 T-SQL 那樣直覺,但事實上只是我們比較熟悉 T-SQL 的語法與資料庫架構而已,當我們換成 ORM (Object-relational mapping) 技術後所有對資料的操作必須全部改以「物件」與「實體」來思考,所以在這轉換的過程經常轉不過去,連我自己也有時會忘記怎麼寫,也經常利用 Linq Samples and the Sample Query Explorer 幫我查出適當的寫法。
由於大多數人都是先學會 T-SQL 然後才學會 LINQ 的,因此兩者的觀念難免有些模糊不清的地方,尤其是在開發的時候都會不斷的以 T-SQL 語法如何翻譯成 LINQ 語法 這樣的思路在寫 LINQ,因此多少會經歷一些痛苦的轉換期,不過,學習新技術最好的方式是先暫時放下既有的經驗,試圖去瞭解為什麼要有這個新技術的出現,再來思考之間如何做轉換以及應注意的地方。
我們先來一段最基本的 LINQ to SQL 使用類似 T-SQL 的 INNER JOIN 資料查詢語法:
from c in Categories
from o in c.Products
select new { c.CategoryName, o.ProductID, o.ProductName }
我們可以從上述 LINQ 語法上就知道有兩個資料來源(因為有兩個 from 子句),而第二個 from 使用的是第一個 from 資料來源的關連屬性,因此產生 JOIN 需求,這段 LINQ 語法所產生的 T-SQL 語句如下:
SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
FROM [Categories] AS [t0], [Products] AS [t1]
WHERE [t1].[CategoryID] = [t0].[CategoryID]

接著我們來看看另一個 INNER JOIN 的資料查詢語法,我們使用語意更為明確的 join 子句:
from c in Categories
join o in Products on c.CategoryID equals o.CategoryID 
select new { c.CategoryName, o.ProductID, o.ProductName }
我們可以從上述 LINQ 語法上知道有一個 Categories 資料來源,並且 join 另一個 Products 資料來源,當中用這個兩個實體的其中一個 CategoryID 屬性進行 join 動作,這是一個非常明確的 join 語法,其語法與 T-SQL 的 join 語法非常相近,這段 LINQ 語法所產生的 T-SQL 語句如下:
SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]
這兩段 LINQ 語法所執行的結果資料一模一樣,不過產生的 T-SQL 不一樣,所以透過 LINQ to SQL 會自動將設定的 LINQ 語法產生出合適的 T-SQL 語法。不過,我們都知道資料庫查詢的 SQL 語法有很多調校的技巧,透過 LINQ to SQL 之後自然會變的不容易調校,所以針對某些 LINQ 語法還是有可能產生效能不彰的狀況需要自行處理。
舉個例子來說,以下 LINQ 語法除了 join 外還在 select 的地方有隱含的使用了另一個 JOIN 條件:
from c in Categories
join o in Products on c.CategoryID equals o.CategoryID 
select new { o.Category.CategoryName ,o.ProductID, o.ProductName }
因此會產生出一個詭異且無效率的 T-SQL 語法如下,同時有 INNER JOIN 與 LEFT OUTER JOIN 的狀況:
SELECT [t2].[CategoryName], [t0].[ProductID], [t0].[ProductName]
FROM [Products] AS [t0]
INNER JOIN [Categories] AS [t1] ON [t0].[CategoryID] = ([t1].[CategoryID])
LEFT OUTER JOIN [Categories] AS [t2] ON [t2].[CategoryID] = [t0].[CategoryID]
這時我們修正 LINQ 語法如下:
from c in Categories
join o in Products on c.CategoryID equals o.CategoryID 
select new { c.CategoryName, o.ProductID, o.ProductName }
這時就會產生預期的 T-SQL 語法:
SELECT [t0].[CategoryName], [t1].[ProductID], [t1].[ProductName]
FROM [Categories] AS [t0]
INNER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]
雖然 LINQ 出現的目的就是希望你改用「物件」與「實體」的角度來思考資料的查詢方式,不過如果你能瞭解從 LINQ 轉換到 T-SQL 的過程將有助於你寫出更有效率的 LINQ 查詢語法。

瞭解 INNER JOIN 之後,我們再來看一個 T-SQL 中常見的 LEFT JOIN 語法的 LINQ 要如何撰寫:
from o in Products
select new { o.Category.CategoryName, o.ProductID, o.ProductName }
這段 LINQ 語法我們只取出一個 Products 資料來源,但是在 select 子句卻額外取得 Category 關連實體的資料,這個關連是「多對一」的關連,所以一個 Product 實體只會取得一個 Category 實體,所以轉換 T-SQL 之後你會發現 LEFT JOIN 的左邊就是 Products,而右邊就變成 Categories,其所產生的 T-SQL 語句如下:
SELECT [t1].[CategoryName], [t0].[ProductID], [t0].[ProductName]
FROM [Products] AS [t0]
LEFT OUTER JOIN [Categories] AS [t1] ON [t1].[CategoryID] = [t0].[CategoryID]
雖然你看到的是一個 LEFT JOIN 語法,不過這並不是我們常見的那種 JOIN 狀況,比較複雜的狀況是當我們左側的實體為 Categories 以及右側的實體為 Products 的狀況,這是「一對多」的關連,複雜度相對提高一些。
由於 INNER JOIN 是 交集(AND) 的概念,當兩個 JOIN 的實體都有資料時才有資料。而 LEFT JOIN的概念卻是「左邊的資料全部都要有,即便右邊沒有資料也要以 null 代替」,因此我們的 LINQ to SQL 語法如下就要特別注意資料來源出現的順序性:
我們先重寫文章稍早出現的過的 INNER JOIN 語法如下:
from c in Categories
join o in Products on c.CategoryID equals o.CategoryID 
select new { c.CategoryName, o.ProductName }
如果要改成 LEFT JOIN 語法,則必須修改成以下 LINQ 語法:
from c in Categories
join o in Products on c.CategoryID equals o.CategoryID into ps
from o in ps.DefaultIfEmpty()
select new { c.CategoryName, o.ProductName }
因為撰在 LINQ 撰寫 LEFT JOIN 時的觀念與 T-SQL 不太一樣,要用「物件」的角度比較能理解其語法所代表的意義,所以上述的語法可以這樣解釋:
取出 Categories 資料並放入 c 變數,接著再與 Products 做 JOIN 並將 JOIN 後的結果放入 ps 變數(注意:並非第二行的 o 變數),這時再宣告一個資料來源 o 其資料來自於「修改過的 ps 變數」,且修改的方式為 ps.DefaultIfEmpty(),意即代表若 ps ( 也就是 Products 經過 join 篩選後的資料 ) 無任何資料時,還是回傳一筆 Default 的資料(也就是預設的 null 資料)。
這一段 LINQ 所產生的 T-SQL 如下:
SELECT [t0].[CategoryName], [t1].[ProductName] AS [ProductName]
FROM [Categories] AS [t0]
LEFT OUTER JOIN [Products] AS [t1] ON ([t0].[CategoryID]) = [t1].[CategoryID]
因此當你需要撰寫「多對一」關連情況下正確的使用 LINQ 查詢語法做 LEFT JOIN 就必須這樣來撰寫!
不過有一點必須注意,那就是當 o 取得的物件為 null 時,雖然 select 子句中的 o.ProductName 不會引發例外,而且會回傳 null,但是若你在 select 子句中設定 o.ProductID 的話,那就會引發例外,因為 null 並無法正確轉型成 Int32 型別,錯誤訊息是:InvalidOperationException - 無法將 Null 值指派給型別 System.Int32 的成員,該型別不可為 Null 值。
相關連結

[MVC][Razor][C#] How to populate dropdown list with numbers


A note to myself


@Html.DropDownListFor(m=>m.Name, Enumerable.Range(1, 10).Select(i => new SelectListItem { Text = i.ToString(), Value = i.ToString() }))



@Html.DropDownListFor(m => m.NumberOfTickets, Enumerable.Range(1, 10).Select(i => new SelectListItem { Text = i.ToString(), Value = i.ToString() }))



Ref:
1. How to populate dropdown list with numbers
http://stackoverflow.com/questions/29659911/asp-net-mvc-how-to-populate-dropdown-list-with-numbers
2. SelectList for years
http://stackoverflow.com/questions/13959098/selectlist-for-years

2016年11月21日 星期一

[MS SQL] [T-SQL] HAVING COUNT()


A note to myself...


//Filter records only 1 row: HAVING count(1) = 1
SELECT OrderID FROM [Order Details] (NOLOCK) GROUP BY OrderID HAVING count(1) = 1


//Filter records more than one row: HAVING count(1) > 1
SELECT OrderID FROM [Order Details] (NOLOCK) GROUP BY OrderID HAVING count(1) > 1


Ref: http://www.w3resource.com/sql/aggregate-functions/count-having.php

2016年11月14日 星期一

[C#] 使用 String.Join 串連陣列或字串

遇到就筆記一下…



IEnumerable yearList = Enumerable.Range(DateTime.Now.Year, 5);
Console.WriteLine(string.Join(" ", yearList));

2016 2017 2018 2019 2010


int[] arr = {1, 3, 5, 7, 9};
Console.WriteLine(string.Join(" - ", arr));

1 - 3 - 5 - 7 - 9


var numsFromOneToTen = string.Join(",", Enumerable.Range(1, 10));
Console.WriteLine(numsFromOneToTen);

1,2,3,4,5,6,7,8,9,10


//Join不同類型
object[] data = {string.Empty, "test", 123, .998, DateTime.Now};
string variousObjects = string.Join(" : ", data);
Console.WriteLine(variousObjects);

//Join不同類型
//var variousObjects = string.Join("-", "A", DateTime.Now, 3.14);
//Console.WriteLine(variousObjects);

: test : 123 : 0.998 : 11/14/2016 4:13:49 PM

Ref:
1. MSDN:
    https://msdn.microsoft.com/en-us/library/57a79xd0.aspx
2. C# 中奇妙的函数–7. String Split 和 Join
    http://www.cnblogs.com/multiplesoftware/archive/2011/09/17/2179380.html
3. [.NET]Enumerable.Range
    https://dotblogs.com.tw/rainmaker/2013/04/24/102208




C# 中奇妙的函数–7. String Split 和 Join

很多时候处理字符串数据,比如从文件中读取或者存入 - 我们可能需要加入分隔符(如CSV文件中的逗号),或使用一个分隔符来合并字符串序列。

很多人都知道使用split()的方法,但使用与其对应的Join()方法的人就没有那么多。今天,让我们看看它们的应用。

Split() – 根据分隔符切割字符串成几部分


分割符可以是以下几种形式中的一种:
  • 只有一个字符的数组:
    • 比方对于“A,B,C,D,E,F” 可以使用 ‘,’ 或者 new [] { ‘,’ }  
  • 有多个字符的数组:
    • 比方对于“A,B-C,D*E,F”使用 new [] { ‘,’ ‘-‘ ‘*’ } :
  • 只有一个字符串的数组:
    • 比方对于 “A=>B=>C=>D=>E=>F” new [] { “=>” } 
  • 有多个字符串的数组 :
    • 比方对于 “A=>B<=C=>D<=E=>F”使用 new [] { “=>”, “<=” }
让我们在实例中看看:

string testString = "James Hare,1001 Broadway Ave,St. Louis,MO,63101";
//传递的分割可以是一个数组
string[] results = testString.Split(new[] { ',' });
//或者在asp.net 4.0 下传递单独的一个char
results = testString.Split(',');
得到的结果如下
ScreenShot022 
 
对待同样的字符串,我们使用 ‘,’ 和 ‘ ‘ (空格):

string testString = "James Hare,1001 Broadway Ave,St. Louis,MO,63101";
//传递一个数组作为分割的标记
string[] results = testString.Split(new[] { ','' ' });
//或者在4.0 下可以直接这样传递
results = testString.Split(','' ');
得到下面的结果:
ScreenShot023

使用 string 作为分割符用法是基本一样的:
string testString = "James Hare,,1001 Broadway Ave,St. Louis,MO,63101";
string[] results = testString.Split(new[] { ",," }, StringSplitOptions.None);
结果:
ScreenShot024

注意在这里我们必须要提供一个 StringSplitOptions 的选择. 

这个枚举的类型有两个值:
  • StringSplitOptions.None: 包含返回的数组中的空数组元素.
  • StringSplitOptions.RemoveEmptyEntries:  省略返回的数组中的空数组元素.

最后, Split() 有一个形式是让你可以限制返回数组元素数量的. 在这种情况下,前面 n-1 的 元素基于你的条件生成,最后一个则是剩下的没有被分割的部分:
string testString = "James Hare,,1001 Broadway Ave,,,St. Louis,MO,63101";


//返回含有两个元素的数组.  

string[] results = testString.Split(new[] { ',' }, 2, StringSplitOptions.None);


for (int i = 0; i < results.Length; i++)
{
    Console.WriteLine("\tElement {0}: \"{1}\"", i, results[i]);
}
使用限制数量的结果是:
ScreenShot025

注意第二个元素还包含了’,’。

Join() – 串联对象数组的各个元素,其中在每个元素之间使用指定的分隔符

参数
separator
类型:System.String 要用作分隔符的字符串。
values
类型:System.Object[] 一个数组,其中包含要连接的元素。
返回值
类型:System.String
一个由 values 的元素组成的字符串,这些元素以 separator 字符串分隔。

看下面的例子,用StringBuilder来实现串联一组字符串:

string[] parts = { "Apple", "Orange", "Banana", "Pear", "Peach" };


var builder = new StringBuilder();

for (int i = 0; i < parts.Length; i++)
{
    builder.Append(parts[i]);


    // 将最后一个','去掉

    if (i != parts.Length - 1)
    {
        builder.Append(", ");
    }
}


// 结果是 "Apple, Orange, Banana, Pear, Peach"

var result = builder.ToString();

用 string.Join() 可以轻松实现:
 
string[] parts = { "Apple", "Orange", "Banana", "Pear", "Peach" };
 var result = string.Join(", ", parts);
 
很多人可以没有意识到 Join() 可以合并任何类型,如 int, DateTimedouble, 或其他自定义的类型! 
当调用 string.Join() 合并非字符串的数值时,它实际上会让每一个元素 ToString().  也就是说这些元素 ToString() 的定义是符合你的需求的才行 – 虽然大部分asp.net库中的类型都已经有了.
举例子:

// 合并整型 "1,2,3,4,5,6,7,8,9,10"


var numsFromOneToTen = string.Join(",", Enumerable.Range(1, 10));


// 合并不同类型的数值 ==> "1-3.1415927-9/16/2011 12:52:22 PM"

var variousObjects = string.Join("-", new object[] { 1, 3.1415927, DateTime.Now });
最后, Join() 明显是支持 IEnumerable<T> 和 object[], string[]:

string[] arr = { "one", "two", "three" };
Console.WriteLine(string.Join(",", arr)); 

//.net 4.0 中你可以直接列出所有数值,不必要生成数组
var numsFromOneToTen = string.Join(",", "A", "B", "C", "D", "E");

var variousObjects = string.Join("-", 1, 3.1415927, DateTime.Now);
       

结论

如果你想将一个字符串分割或者串联一些元素到一个字符串,想想能否用 Split()Join().  它们在很多方面都非常有用.
更多精彩的相关文章,请阅读喜乐的ASP.NET(Alex Song)

2016年11月2日 星期三

[MS SQL] [T-SQL] ISNULL Function

遇到就筆記一下...


-- 使用 ISNULL 函數,用 N/A 字串來取代所有 NULL 項目
SELECT CustomerID, City, ISNULL(Region, 'N/A') Region, Country


-- 使用 ISNULL 函數,用 0 來取代所有 NULL 項目
SELECT ProductName,UnitPrice*(UnitsInStock+ISNULL(UnitsOnOrder,0))
FROM Northwind..Products

以下轉貼自:http://sharedderrick.blogspot.tw/2012/06/t-sql-isnull.html

SQL Server:認識 ISNULL 函數

ISNULL 函數:以指定的取代值來取代 NULL。
語法:
ISNULL ( check_expression , replacement_value )

check_expression
這是要檢查 NULL 的運算式。check_expression 可以是任何類型。

replacement_value
這是 check_expression 是 NULL 時所傳回的運算式。replacement_value 必須是能夠隱含地轉換成 check_expresssion 類型的類型。

請參考以下的範例程式碼


EX1. 認識 ISNULL 函數

?
1
2
3
4
5
6
7
8
9
10
11
USE Northwind
GO
--
SELECT CustomerID, City, Region, Country
FROM Customers
GO
-- 使用 ISNULL 函數,用 N/A 字串來取代所有 NULL 項目
SELECT CustomerID, City, ISNULL(Region, 'N/A') Region, Country
FROM Customers
GO
-- 01_使用 ISNULL 函數,用 NA 字串來取代所有 NULL 項目




EX2. 彙總函數與 NULL

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 建立資料表:tbAggs
USE tempdb
GO
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tbAggs]') AND type in (N'U'))
<span class="Apple-tab-span" style="white-space: pre;"> </span>DROP TABLE [dbo].[tbAggs]
GO
CREATE TABLE tbAggs
(rid int, sales int)
GO
INSERT tbAggs VALUES(1,10),(2,20)
INSERT tbAggs(rid) VALUES(3)
GO
-- 查詢資料表內容
SELECT * FROM tbAggs
GO

-- 02_查詢資料表內容


?
1
2
3
4
-- 使用 SUM 函數、AVG 函數
SELECT SUM(sales) N'總和', AVG(sales) N'平均值'
FROM tbAggs
GO

-- 03_使用 SUM 函數、AVG 函數


?
1
2
3
4
-- 使用 ISNULL 函數,用 0 來取代所有 NULL 項目
SELECT rid, ISNULL(sales, 0) 'sales'
FROM tbAggs
GO

-- 04_使用 ISNULL 函數,用 0 來取代所有 NULL 項目


?
1
2
3
4
-- 加入 AVG 函數,搭配使用 ISNULL 函數
SELECT AVG(ISNULL(sales, 0)) N'平均值'
FROM tbAggs
GO

-- 05_加入 AVG 函數,搭配使用 ISNULL 函數



參考資料
ISNULL (Transact-SQL)
http://msdn.microsoft.com/zh-tw/library/ms184325.aspx

COALESCE (Transact-SQL)
http://msdn.microsoft.com/zh-tw/library/ms190349(v=sql.110).aspx