SQL Server資料庫版控設定

前言

在寫程式時我們都會有版本控制,以避免重大失誤無法回版,而在程式上作法很簡單就是使用git。
但資料庫要怎版控呢?如果遇到有人直接把資料庫欄位異動了,卻沒通知其他人,程式就會變得難以除錯,所以在這回要介紹如何在資料庫加入版本控制功能。
在這篇範例會以SQL Server搭配Visual Studio去達成版控。

主要以微軟官方提供的:SQL Server Data Tools 來實作。

實作

1.因為要模擬真實情景,先以Visual Studio建立任一個沒版控的專案,在此先以ASP NET CORE MVC為範例。

2.對解決方案點右鍵,為這專案用的資料庫加入”資料庫版控專案”

3.選擇 SQL Server 資料庫專案,如果找不到這個專案記得去這裡裝:https://docs.microsoft.com/zh-tw/sql/ssdt/download-sql-server-data-tools-ssdt?view=sql-server-ver15
就可以出現這範例專案了。

4.我取名叫MyDatabase

5.這時就有一個MyDatabase的資料庫管理專案放進來了

6.再來我們現有的資料庫叫做TodoDB,預計把這DB加入版控

7.選擇匯入>資料庫

8.再來就連DB選擇指定資料庫

9.在此我就選擇資料庫連線、選擇指定資料庫

10.再來點選啟動

11.這樣就匯入完成

12.如此一來就可以版控了也可以設計資料庫

完成!

模擬資料庫欄位變更

1.再來我們模擬資料表變更,新增了一個Email欄位

2.對資料庫專案右鍵點”結構描述比較”

3.之後會跳出這視窗,右邊選擇你遠端的資料庫

4.在這我就選遠端的TodoDB

5.選好後點擊”比較”

6.點完後點擊更新,底下會顯示更新狀態,顯示已經順利完成

7.這時去SQL Server看就成功被更新了

下面是我做的完整專案:
https://github.com/yuhsiang237/SQL-Server-Version-Control

參考資料

2022上半年改變了什麼

在2022的上半年我做了很多大膽的改變與嘗試,包括從待業轉回職場,再從職場下班兼職第二份工作。居所也從高雄來到台北。

「追從自己內心的想法,相信自己。」是我這半年來最有感的,能夠從無化變成有,到最後實際改變現況,讓自己不再徬徨。

在工作上,蠻順利的,至於為什麼呢?
可能是之前2年以上的實務經驗累積,在這先感謝之前公司了。整體來講,做做測試、寫寫程式,釐清業務邏輯,就是日常。

那回家後能不能再幹點什麼,讓自己充實點?
於是我就去找了第二份工作,當一下程式家教。在教人這方面,在大學時就有當過TA經驗,所以算順順的過了,總共教了2個月左右。

而在生活面就是自給自足了,自己三餐自煮,如果勉強來講,也算半個廚師了。在台北如果自己煮能少很多開銷,也比較能管控吃進去的食物。

而旅遊,因為疫情關係一隻手數的出來,就不談了。

整體上算是愜意的生活,但卻還是有不滿足的點就是「成就感」。因為過的很踏實,以致自己畏懼發夢,「夢」往往都是很難達成的事,因為怕失敗,而不敢豪賭。因此,我的2022年下半場將會嘗試這個心臟的能耐,我就敢作夢。

SQL Server 使用GUID當作PK範例

使用GUID需要將型別設定為uniqueidentifier。預設值通常會為NEWID(),即從資料庫生成時自動產生GUID帶入。

1.建立Table

1
2
3
4
5
CREATE TABLE Users (
[GUID] uniqueidentifier NOT NULL DEFAULT NEWID(),
[Name] NVARCHAR(50) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([GUID] ASC)
);

2.再來新增資料

1
2
3
4
5
6
7
INSERT INTO Users
(
[Name]
)
VALUES
('MC HOTDOG'),
('張震嶽')

3.查詢

1
SELECT * FROM Users

結果:

1
2
3
GUID	Name
FB5AFFC7-0802-47F7-AFB3-531BC83B6C26 張震嶽
F8122471-70AE-43C5-9C40-A65ED54FACD5 MC HOTDOG

總結

使用GUID優點:
1.不會讓資料庫造成依賴ex:產生唯一識別碼
2.不用擔心鍵值重複(機率極低)ex:不同時間產的多資料表合成一張資料表
3.不好被猜測ex:F8122471-70AE-43C5-9C40-A65ED54FACD5
缺點:
1.空間使用GUID 16Bytes比整數的4Bytes多。
2.效能(待釐清,似乎眾說紛紜)

參考資料

PostgreSQL INSERT INTO MULTIPLE

前言

在SQL有時需要手動建立測資,但又不想逐行insert into時可以使用。

語法:

1
2
3
4
5
6
INSERT INTO table_name (column_list)
VALUES
(value_list_1),
(value_list_2),
...
(value_list_n);

舉例:

1
2
3
4
5
6
7
8
INSERT INTO USER
(
NAME,
BIRTHDAY
)
VALUES
('胖虎','1993-1-1'),
('小夫','1993-2-1')

C# 文字組合的4種方式

前言

在此紀錄C#中常見的組字串方式。

實作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;

namespace StringSol
{
internal class Program
{
static void Main(string[] args)
{
var name = "Yu Hsiang";
string str1 = "你好" + name;
string str2 = String.Concat("你好", name);
string str3 = String.Format("你好{0}", name);
// $是c# 6.0 的語言特性,功能類似string.format()
string str4 = $"你好{name}";

Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3);
Console.WriteLine(str4);
}
}
}

輸出結果:

1
2
3
4
你好Yu Hsiang
你好Yu Hsiang
你好Yu Hsiang
你好Yu Hsiang

C# LINQ GroupBy用法

前言

最近很常使用GroupBy去處理資料,因此稍作整理。
GroupBy主要用來分組,以”群”、”組”有關的都可以使用他。

實作

目標:使用GroupBy將每個班級的人數列出。

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
using System;
using System.Collections.Generic;
using System.Linq;

namespace linq_groupby
{
internal class Program
{
public class Student
{
/// <summary>
/// 編號
/// </summary>
public int Id { get; set; }

/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }

/// <summary>
/// 教室
/// </summary>
public char Classroom { get; set; }
}

static void Main(string[] args)
{
var students = new List<Student>
{
new Student {Id = 1, Name = "大雄",Classroom = 'A'},
new Student {Id = 2, Name = "多拉A夢",Classroom = 'B'},
new Student {Id = 3, Name = "胖虎",Classroom = 'A'},
};
var classRoomGroup = students
.GroupBy(x => x.Classroom)
.Select(x => new
{
ClassRoom = x.Key,
StudentCount = x.Count(),
}).ToList();

foreach (var item in classRoomGroup)
{
Console.WriteLine($"Classroom:{item.ClassRoom} - StudentCount:{item.StudentCount}");
}
}
}
}

輸出結果:

1
2
Classroom:A - StudentCount:2
Classroom:B - StudentCount:1

A班級2人,B班級1人。

總結

使用LINQ GroupBy能夠節省建立資料結構如字典、HashSet等,直接去做分組統計。

SQL Server PARTITION BY 分割分組語法

前言

最近處理到一些複雜需求,使用到了PARTITION BY。
於是記錄一下PARTITION BY的用法。
主要是能在分組時取得第一筆資料、與分組有關的操作。

PARTITION BY

Divides the query result set into partitions. The window function is applied to each partition separately and computation restarts for each partition.

PARTITION BY 可將查詢結果集分成幾個資料分割。

語法:

1
OVER ( [ PARTITION BY value_expression ] [ order_by_clause ] )  

實作

目標:要取得每個以UserId分組的第一筆資料

資料表:[DBO].[TODOS]

首先先使用PARTITION製造出分割出群組編號

1
2
3
4
5
SELECT 
ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY ID) ROW_ID,
*
FROM
[DBO].[TODOS]

可以見到ROW_ID出現在列表中,即代表這是這個UserId組的第幾筆資料。
依序為:
UserId為1的第1筆資料
UserId為3的第1筆資料
UserId為3的第2筆資料
UserId為3的第3筆資料
UserId為4的第1筆資料
UserId為5的第1筆資料

再來只要把這結果集外部包一個搜尋,使用條件就能拿到第一筆資料,如下設定:
ROW_ID為1代表取得每個分組的第一筆資料。

1
2
3
4
5
6
7
8
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(PARTITION BY USERID ORDER BY ID) ROW_ID,
*
FROM
[DBO].[TODOS]
) TEMP
WHERE TEMP.ROW_ID = 1

最終成功拿到每個UserId分組的第一筆資料

參考資料

C# LINQ JOIN 函式效果

前言

因為平時都是寫lambda寫法的LINQ,而在近期看到函式方式的寫法,所以紀錄一下作法。

JOIN函式定義

1
2
3
4
5
6
7
8
public static System.Collections.Generic.IEnumerable<TResult> 
Join<TOuter,TInner,TKey,TResult> (
this System.Collections.Generic.IEnumerable<TOuter> outer,
System.Collections.Generic.IEnumerable<TInner> inner,
Func<TOuter,TKey> outerKeySelector,
Func<TInner,TKey> innerKeySelector,
Func<TOuter,TInner,TResult> resultSelector,
System.Collections.Generic.IEqualityComparer<TKey>? comparer);

參數部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
outer
IEnumerable<TOuter>
要聯結的第一個序列。

inner
IEnumerable<TInner>
要加入第一個序列的序列。

outerKeySelector
Func<TOuter,TKey>
用來從第一個序列各個項目擷取聯結索引鍵的函式。

innerKeySelector
Func<TInner,TKey>
用來從第二個序列各個項目擷取聯結索引鍵的函式。

resultSelector
Func<TOuter,TInner,TResult>
用來從兩個相符項目建立結果項目的函式。

comparer
IEqualityComparer<TKey>
用來雜湊及比較索引鍵的 IEqualityComparer<T>。

實作

簡單來講就是拿主表資料去JOIN另一張關聯表,而x、y則是塞進去的key值。
在這裡以User為主表,UserDetail為關聯表。
原本4筆資料的User,經過與UserDetail JOIN關聯,於是剩下兩筆資料。

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
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace JoinSample
{

public class User
{
public int Id { get; set; }
public string Name { get; set; }
}

public class UserDetail
{
public int UserId { get; set; }
public string PhoneNumber { get; set; }
}


public class UserData
{
public int Id { get; set; }

public string UserName { get; set; }
public string PhoneNumber { get; set; }
}

internal class Program
{
static void Main(string[] args)
{
var users = new List<User>
{
new User
{
Id =1,Name="大雄",
},
new User
{
Id =2,Name="多拉A夢",
},
new User
{
Id =3,Name="胖虎",
},
new User
{
Id =4,Name="小夫",
}
};

var userDetails = new List<UserDetail> {
new UserDetail{ UserId=1,PhoneNumber="0911111111"},
new UserDetail{ UserId=2,PhoneNumber="0922222222"}
};

var userData = users.Join(
userDetails,
x => x.Id,
y => y.UserId,
(x, y) => new UserData
{
Id = x.Id,
PhoneNumber = y.PhoneNumber,
UserName = x.Name
});

foreach (var item in userData)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.UserName);
Console.WriteLine(item.PhoneNumber);
}
}
}
}

output:

1
2
3
4
5
6
1
大雄
0911111111
2
多拉A夢
0922222222

參考資料

[Day7]C#建立不會停止的背景Task

前言

在上回 Post not found: Task運行處理-Run、Start、RunSynchronously-C-SyncAndAsync [Day6]Task運行處理(Run、Start、RunSynchronously) ,我們學習了Task的各種啟動方式。
而今回主要來撰寫不會停止的背景Task。

實作

不終止的非同步事件 ex:多個while(true)常駐。

主要使用以下的模板去製作常駐程式:

1
2
3
4
5
6
7
var endlessTask = Task.Run(async () =>
{
while (true)
{
// Todo
}
});

簡單來說就是開一個異步的Task讓他跑即可。

在以下的範例中endlessTask1、endlessTask2會不停的印出資料。

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
using System;
using System.Threading.Tasks;

namespace EndlessTaskAsync
{
class Program
{
/// <summary>
/// 主程式
/// </summary>
/// <returns></returns>
public static async Task Main()
{
var endlessTask1 = EndlessTask(1);
var endlessTask2 = EndlessTask(2);

await PreventToStop();
}

/// <summary>
/// 製作無止盡的 while task
/// </summary>
/// <param name="number">編號</param>
/// <returns></returns>
private static Task EndlessTask(int number)
{
Console.WriteLine("Start EndlessTask" + number);
var endlessTask = Task.Run(async () =>
{
while (true)
{
Console.WriteLine("EndlessTask" + number);
await Task.Delay(100);
}
});
return Task.CompletedTask;
}

/// <summary>
/// 避免視窗關閉,使用ReadKey();
/// </summary>
/// <returns></returns>
private static Task PreventToStop()
{
Console.ReadKey();
return Task.CompletedTask;
}
}
}

運行結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2
EndlessTask1
EndlessTask2

直到關掉程式都會一直印。

總結

在這回中練習了背景常駐的Task,通常會在監聽某個請求while中使用。
如果是以目前處理過的code,就是在socket處理上會大量使用。

專案存庫:
https://github.com/yuhsiang237/EndlessTaskAsync