C#擷取中英混雜字串

在這篇文中紀錄如何擷取中英混雜的子字串。

以下是我想到的作法,就是利用big5中文兩字元、英文一字元的特性去做。
20220217,使用Linq重構部分程式碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.Text;
using System.Linq;

namespace SubEnglishChineseString
{
public static class Program
{
/// <summary>
/// C#中擷取某長度中英混雜字串範例
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
string str = "TESTWORD測試文字TEST";
Console.WriteLine(SubBig5String(str, 1, 15));
}
/// <summary>
/// C#中擷取Big5子字串
/// </summary>
/// <param name="str">字串</param>
/// <param name="start">擷取起始索引</param>
/// <param name="length">擷取長度</param>
/// <returns>string</returns>
public static string SubBig5String(string str, int start, int length)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
byte[] subByteArray = Encoding.GetEncoding("big5").GetBytes(str).Skip(start).Take(length).ToArray();
return Encoding.GetEncoding("big5").GetString(subByteArray);
}
}
}

專案存庫:https://github.com/yuhsiang237/csharp-notes/tree/master/SubEnglishChineseString

撰寫C#單元測試(Unit Test)

前言

在這回中主要介紹C#的單元測試。
將會以AspNetCore中的xUnit、Moq套件進行範例測試。

至於為什麼要單元測試?
因為能夠快速的驗證結果、在撰寫時也只要執行片段程式碼。
對於有些程式碼容易有改A壞B的問題,能夠透過測試直接幫我們一次測完。
讓我們只需要針對錯誤案例進行程式碼錯誤區塊修改,加快整體專案除錯的時間。

完整測試專案連結:
https://github.com/yuhsiang237/csharp-unit-test

範例

使用Moq套件的Mock建立假的物件,並且設定函式、屬性、返回的值,再使用xUnit提供的驗證方法進行測試。

首先建立我們要測試的介面與類別,一個是IFoo.cs、Bar.cs。

csharp-unit-test/UnitTestProject/Bar.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
using System;
using System.Collections.Generic;
using System.Text;

namespace UnitTestProject
{

public class Bar
{
public virtual bool Submit() { return false; }
}

}

csharp-unit-test/UnitTestProject/IFoo.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System;
using System.Collections.Generic;
using System.Text;

namespace UnitTestProject
{
public interface IFoo
{
Bar Bar { get; set; }
string Name { get; set; }
int Value { get; set; }
bool DoSomething(string value);
}

}

再來建立測試,使用Moq、Xunit。
我們可以對函式返回值、假物件、屬性進行測試。
以下為測試範例:
/csharp-unit-test/UnitTestProjectTests/UnitTest.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using System;

using Xunit;
using Moq;

using UnitTestProject;

namespace UnitTestProjectTests
{
/// <summary>
/// xUnit單元測試,並使用Moq的Mock
/// 參考資料:
/// https://github.com/Moq/moq4/wiki/Quickstart#verification
/// https://vimsky.com/examples/detail/csharp-ex---Mock-VerifySet-method.html
/// https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/206352/
/// </summary>
public class UnitTest
{
/// <summary>
/// 方法單元測試
/// </summary>
[Fact]
public void MethodsTest()
{
// 準備 Mock IFoo 介面
var mock = new Mock<IFoo>();
// 配置準備模擬的方法,當呼叫介面中的 DoSomething 方法,並傳遞引數 "bing" 的時候,返回 true
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
// 現在,你可以:
IFoo foo = mock.Object;
// 檢查使用時返回值為True
Assert.True(foo.DoSomething("ping"));
}
/// <summary>
/// 屬性單元測試
/// </summary>
[Fact]
public void PropertiesTest()
{
// 準備 Mock IFoo 介面
var mock = new Mock<IFoo>();
// 開始 "tracking" 屬性的 sets/gets
mock.SetupProperty(f => f.Name);
// 提供一個預設的值
mock.SetupProperty(f => f.Name, "foo");
// 現在,你可以:
IFoo foo = mock.Object;
// 儲存的值
Assert.Equal("foo", foo.Name);
// 重新設定一個值
foo.Name = "bar";
Assert.Equal("bar", foo.Name);
}
}
}

再來開啟VisualStudio的測試視窗運行,可以得到以下結果:

表示測試成功。

總結

撰寫測試能夠改善平常除錯的速度,特別當專案大起來時。
此外有些平台有測試的功能(如Azure DevOps Server的TFS),可以在CI自動整合時跑測試。

參考資料

C# nameof用法

如果在C#中遇到一些重複的String字串變數,是由變數的命名而來,就可以使用nameof直接提取出自串,避免再打一次造成打錯的問題。

nameof

nameof運算式會產生變數、類型或成員的名稱做為字串常數

1
2
3
4
5
6
7
8
9
Console.WriteLine(nameof(System.Collections.Generic));  // output: Generic
Console.WriteLine(nameof(List<int>)); // output: List
Console.WriteLine(nameof(List<int>.Count)); // output: Count
Console.WriteLine(nameof(List<int>.Add)); // output: Add

var numbers = new List<int> { 1, 2, 3 };
Console.WriteLine(nameof(numbers)); // output: numbers
Console.WriteLine(nameof(numbers.Count)); // output: Count
Console.WriteLine(nameof(numbers.Add)); // output: Add

參考資料:

https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/operators/nameof#code-try-0

C# LINQ 延遲執行 (Deferred Execution)

前言

在這篇中主要筆記LINQ 延遲執行的特性。
一般我們如果使用純SQL語言去與資料庫查詢通常一下指令就會被馬上執行,而LINQ卻不一樣,是直到某個觸發點他才會開始運作。
即寫Select時並不會馬上運作。

常見的觸發點

1.foreach(var item in items)
2.轉為ToList(), ToArray(), ToDictionary(),因為需巡覽才能轉型,所以會直接執行。
3.取得彙總結果的聚合函数 Count(), Max(), Sum(), First(), Last()。

主要原因

延遲執行的基礎 - Iterator、yield

  1. 您只要提供 Iterator,它會只往返於類別中的資料結構。當編譯器偵測到您的 Iterator 時,它會自動產生 IEnumerable 或 IEnumerable 介面的 Current、MoveNext 和 Dispose 方法。
  2. Iterator 程式碼會使用 yield return 陳述式輪流傳回各元素。yield break 則會結束反覆運算。

關鍵:使用 yield 關鍵字,C# 會自動將該 block 實作為 iterator 方式執行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections;

namespace DeferredExec
{
class Program
{
public class Data : IEnumerable
{
public IEnumerator GetEnumerator()
{
Console.WriteLine("yield 1");
yield return 1;
Console.WriteLine("yield 2");
yield return 2;
Console.WriteLine("yield 3");
yield return 3;
}
}
static void Main(string[] args)
{
Data data = new Data();
foreach(var item in data)
{
Console.WriteLine(item);
}
}
}
}

實作IEnumerable介面,並且撰寫方法GetEnumerator,yield會把每個區塊視為iterator(迭代器)。
而foreach中取得每個item在逆向工程可以見到其實是呼叫GetEnumerator取得一個IEnumerator(即iterator)。

有這觀念再拉回來看LINQ的方法,可以發現是IEnumerable。
Where:

1
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)

Select:

1
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)

想知道是不是延遲執行可以看返回值是否為以下3種物件:

1
IEnumerable<TSource>
1
IEnumerable<IGrouping<TKey, TSource>>
1
IOrderedEnumerable<TSource>

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace DeferredExec
{
class Program
{
private static void Main(string[] args)
{
var people = GetPeople();
var names = people
.Where(person => person.Age > 18)
.Select(person => person.Name);

foreach (var name in names)
{
Console.WriteLine(name);
}
}

private static IEnumerable<Person> GetPeople()
{
yield return new Person { Id = 1, Name = "John", Age = 36 };
yield return new Person { Id = 2, Name = "Bill", Age = 6 };
yield return new Person { Id = 3, Name = "Steve", Age = 23 };
}

public class Person
{

private int _id;
private string _name;
private int _age;
public int Id {
get {
return _id;
}
set
{
_id = value;
}
}

public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
}
}
}

在這範例中使用泛型(Generic)的IEnumerable

1
IEnumerable<T>

因為Select、Where方法是IEnumerable,所以會在foreach觸發GetEnumerator時執行,進而達到延遲執行的效果。

延遲執行好處

1.可以再添加額外的表達式,如主要的查詢表達式後面可以添加子表達式過濾作為最終結果。
2.取得資料是最新的,因為當下才執行

總結

可以得知C#的LINQ為什麼能夠延遲執行是因為採用IEnumerable介面,裡面會有yield區塊形成迭代器,所以直到foreach執行時才會開始觸發。

參考資料

https://dotblogs.com.tw/hatelove/2013/09/10/csharp-linq-deferred-execution-introduction
https://dotblogs.com.tw/hatelove/2012/05/10/introducing-foreach-ienumerable-ienumerator-yield-iterator
https://dotblogs.com.tw/regionbbs/2012/01/12/linq_deferred_execution

C# Properity(屬性) 與 Field(欄位)

在這篇主要介紹Properity(屬性)、Field(欄位)在物件導向class中的差別。

Properity(屬性)

1.以public為主,能夠讓外部能存取。
2.包含get、set訪問器(能要求欄位只能讀或只能寫)。
3.可以增加邏輯處理,在改變一個欄位的值的時候希望改變物件的其它一些狀態,舉例:更改某外部公開屬性值x為1時,另一個內部私有欄位y需要連動更改數值為2。
4.不佔有實際內存,主要為get;set;存取私有欄位資料。

Field(欄位)

1.以private為主(有時會以protected),主要以class內部使用為主。
2.命名會加_在前面。
3.可能為靜態值所以設定為readonly
4.佔有實際內存、位址。

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class User
{
private string _name;// _name為欄位
public string Name // Name為屬性,它含有程式碼塊
{
get
{
// 可以在此添加額外會影響的私有變數
return _name;// 讀取(返回_name值)
}
set
{
_name = value;// 為_name賦值
// 可以在此添加額外會影響的私有變數
}
}
}

總結

為什麼要使用屬性為什麼不用欄位就好?
因為能夠確保內部私有資料的安全性,並且能夠透過get;set;方式訪問時能夠增加邏輯處理、方便限制可讀、可寫。

參考資料

https://kevintsengtw.blogspot.com/2011/09/property-field.html?m=1#:~:text=Field%EF%BC%9A_FullDescription%E7%82%BA%E7%89%A9%E4%BB%B6%E7%A7%81%E6%9C%89,%E4%BE%86%E5%AD%98%E6%94%BE%E5%B1%AC%E6%80%A7%E7%9A%84%E8%B3%87%E6%96%99%E3%80%82&text=%E7%AF%80%E9%8C%84%E6%95%B4%E7%90%86%EF%BC%9A,%E9%9C%80%E8%A6%81%E5%AE%8C%E5%85%A8%E7%9B%B8%E5%90%8C%E7%9A%84%E8%AA%9E%E6%B3%95%E3%80%82
https://www.itread01.com/content/1548110544.html

C# 同步非同步實作與介紹

前言

在這篇中簡易介紹C#同步與非同步的作法。
一般我們在做一些任務時有時需要:
1.等待上個任務完成
2.同時處理多個任務
這時就會需要用到非同步、同步的作法,可以節省時間(在同個時間內處理多個任務)。
可能用到Thead或是用Task作法asyncawait。在這篇中則以:
https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/concepts/async/
作為範例,簡易的操作一個需要處理同步/非同步的範例。

同步範例實作

簡單來說,就是每個任務都是會等待上面的任務完成才依序執行。
下方以製作一份早餐的同步範例,1~7步驟都要等上面的步驟完成才會繼續。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Threading.Tasks;

namespace async
{
class Program
{
static void Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");

Egg eggs = FryEggs(2);
Console.WriteLine("eggs are ready");

Bacon bacon = FryBacon(3);
Console.WriteLine("bacon is ready");

Toast toast = ToastBread(2);
ApplyButter(toast);
ApplyJam(toast);
Console.WriteLine("toast is ready");

Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}

private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}

private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");

private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");

private static Toast ToastBread(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
Task.Delay(3000).Wait();
Console.WriteLine("Remove toast from toaster");

return new Toast();
}

private static Bacon FryBacon(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
Task.Delay(3000).Wait();
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
Task.Delay(3000).Wait();
Console.WriteLine("Put bacon on plate");

return new Bacon();
}

private static Egg FryEggs(int howMany)
{
Console.WriteLine("Warming the egg pan...");
Task.Delay(3000).Wait();
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
Task.Delay(3000).Wait();
Console.WriteLine("Put eggs on plate");

return new Egg();
}

private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}

private class Coffee
{
}

private class Egg
{
}

private class Toast
{
}

private class Juice
{
}

private class Bacon
{

}
}
}

結果:

可以發現這樣很難節省時間,所以其實能把某些部分拆成異步來做,有助於節省時間。(雖然同時間可能記憶體耗能會加大)

異步範例實作

準備早餐程式碼的簡單非同步版本看起來像下列程式碼片段:
FryEggsAsync、FryBaconAsync、MakeToastWithButterAndJamAsync更新為Task,函式使用Async
這時會變成先做第一步,之後2、3、(4+5)步是併發執行,並使用while做判斷,依序把完成的Task移除List,仍需處理的Task數量為0就跳出,代表完成了!
再由下個任務6繼續。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace async
{
class Program
{
static async Task Main(string[] args)
{
Coffee cup = PourCoffee();
Console.WriteLine("coffee is ready");

var eggsTask = FryEggsAsync(2);
var baconTask = FryBaconAsync(3);
var toastTask = MakeToastWithButterAndJamAsync(2);

var breakfastTasks = new List<Task> { eggsTask, baconTask, toastTask };
while (breakfastTasks.Count > 0)
{
Task finishedTask = await Task.WhenAny(breakfastTasks);
if (finishedTask == eggsTask)
{
Console.WriteLine("eggs are ready");
}
else if (finishedTask == baconTask)
{
Console.WriteLine("bacon is ready");
}
else if (finishedTask == toastTask)
{
Console.WriteLine("toast is ready");
}
breakfastTasks.Remove(finishedTask);
}

Juice oj = PourOJ();
Console.WriteLine("oj is ready");
Console.WriteLine("Breakfast is ready!");
}
static async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
var toast = await ToastBreadAsync(number);
ApplyButter(toast);
ApplyJam(toast);

return toast;
}

private static Juice PourOJ()
{
Console.WriteLine("Pouring orange juice");
return new Juice();
}

private static void ApplyJam(Toast toast) =>
Console.WriteLine("Putting jam on the toast");

private static void ApplyButter(Toast toast) =>
Console.WriteLine("Putting butter on the toast");

private static Toast ToastBread(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
Task.Delay(3000).Wait();
Console.WriteLine("Remove toast from toaster");

return new Toast();
}

private static async Task<Bacon> FryBaconAsync(int slices)
{
Console.WriteLine($"putting {slices} slices of bacon in the pan");
Console.WriteLine("cooking first side of bacon...");
await Task.Delay(3000);
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("flipping a slice of bacon");
}
Console.WriteLine("cooking the second side of bacon...");
await Task.Delay(3000);
Console.WriteLine("Put bacon on plate");

return new Bacon();
}


private static async Task<Egg> FryEggsAsync(int howMany)
{
Console.WriteLine("Warming the egg pan...");
await Task.Delay(3000);
Console.WriteLine($"cracking {howMany} eggs");
Console.WriteLine("cooking the eggs ...");
await Task.Delay(3000);
Console.WriteLine("Put eggs on plate");

return new Egg();
}

private static Coffee PourCoffee()
{
Console.WriteLine("Pouring coffee");
return new Coffee();
}
private static async Task<Toast> ToastBreadAsync(int slices)
{
for (int slice = 0; slice < slices; slice++)
{
Console.WriteLine("Putting a slice of bread in the toaster");
}
Console.WriteLine("Start toasting...");
await Task.Delay(3000);
Console.WriteLine("Remove toast from toaster");

return new Toast();
}
private class Coffee
{
}

private class Egg
{
}

private class Toast
{
}

private class Juice
{
}

private class Bacon
{

}
}
}

結果:
可以發現為異步執行!
FryEggsAsync:原本需6秒
FryBaconAsync:原本需6秒
MakeToastWithButterAndJamAsync:原本需3秒
以同步執行的話需要:15秒
在異步執行只需取其中最大的秒數:6秒
大幅度的減省時間花費。

TaskAPI 包含兩種方法, Task.WhenAll 和 Task.WhenAny 撰寫非同步程式碼,能在多個背景工作上執行非封鎖等候。
await Task.WhenAny
await Task.WhenAll
更多可參考:
https://gist.github.com/relyky/52b4abf32b44d5d00a674b9cd34ca3a3

用紅筆畫起來部分,表示其併發執行。

結論

以Async為開頭的函數內步才能夠進行併發的操作。
並且搭配可以搭配await做Task的停頓。
即讓每個可Async的Task充分利用時間。

在工作上可能遇到需要併發、可同時執行時會使用,如有N個迴圈任務且沒有順序性,則可以寫入Task,或是需要用後端呼叫HTTP請求,可以一次併發,增加系統效率。或是有順序性執行的任務就很適合採用Task拆成子項目。

如果要再深入探討可以參考官方:
https://docs.microsoft.com/zh-tw/dotnet/csharp/async

參考資料

https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/concepts/async/
https://gist.github.com/relyky/52b4abf32b44d5d00a674b9cd34ca3a3
https://docs.microsoft.com/zh-tw/dotnet/csharp/async

SQL Server Stored Procedure 介紹&實作

在這篇文章中簡易的介紹Stored Procedure。

Stored Procedure(預存程序)

A stored procedure is a prepared SQL code that you can save, so the code can be reused over and over again.

So if you have an SQL query that you write over and over again, save it as a stored procedure, and then just call it to execute it.

You can also pass parameters to a stored procedure, so that the stored procedure can act based on the parameter value(s) that is passed.

簡單來說就是一種預存程序,寫在資料庫裡面,可以藉由外部傳入參數去呼叫數值,而得到結果。

優點

1.能夠讓不同應用程式直接呼叫,核心邏輯不用分散。
(但目前有微服務架構能改用API了,因此除非是特別有必要,否則還是很少碰到)

缺點

1.撰寫因為沒辦法中斷點Debug所以除錯困難。

簡易寫一個Stored Procedure

1.建立一段searchProduct的Stored Procedure。用來查詢特定Id的商品。

1
2
3
4
5
CREATE PROCEDURE searchProduct 
@productId int
AS
SELECT * from Products
where Id = @productId

2.執行後可以在資料庫的「資料庫>Programmability>Stored Procedures」裡面找到

3.執行

1
exec searchProduct 6

即可得到結果:

4.這樣就完成了一段最簡單的Stored Procedure。
但在實作上主要維護時會很花時間,如果是千行T-SQL,無法使用中斷點會像是天書那樣。

總結

以目前寫過系統來說都是在後端程式裡面寫,而Stored Procedure算是一個新的體驗。
除非,真的有必要需求,否則還是用API式輕量化,因為比較好DEBUG。

SQL Server 常見SQL語法筆記

前言

在這裡整理一些專案常用的SQL語法。

語法

1.新增一筆資料

1
insert into Todos (Name) Values ('123')

2.更新一筆資料

1
update Todos set Name = '4123',IsComplete = 1 where Name = '123'

3.刪除一筆資料

1
delete from Todos where id = 17

4.查詢該表所有資料

1
select * from Todos;

5.使用查詢結果新增資料

1
insert into Todos (Name) select Name from Todos where Name = '4123'

6.INNER JOIN 主表跟次要表都有相同的值才撈出

1
2
select * from ShipmentOrderDetails as a 
join Products as b on a.ProductId = b.Id

7.LEFT JOIN 主表值為主嘗試撈取次要表值,次要表有值就撈,沒值就NULL

1
2
select * from ShipmentOrderDetails as a 
left join Products as b on a.ProductId = b.Id

8.GROUP BY 取得以哪個欄位作為群,並且操作該群的集合資料

1
2
select OrderId,sum(ProductPrice * ProductUnit) sum from ShipmentOrderDetails 
group by OrderId

9.多對多資料處理(即使用left join/join的組合技)

1
2
3
select a.Id,a.Name,c.Id as ProductCategoryId,c.Name as ProductCategoryName from Products as a
left join ProductProductCategoryRelationships as b on a.Id = b.ProductId
left join ProductCategory as c on c.Id = b.ProductCategoryId

總結

這裡整理SQL常見用法。
因為在寫C#時其實內部會使用LINQ,所以就會對不常用的原生SQL生疏,因此在此整理在專案上常見的使用方法,有需要時就能節省再熟悉的時間。