星期四, 6月 20, 2024

[C#] Steam.CopyTo

根據官方文章 - Stream.CopyTo 內範例來理解如何作業,備註有該段說明
Copying begins at the current position in the current stream, and does not reset the position of the destination stream after the copy operation is complete.
CopyTo() 是從 .NET Framework 4.0 才可以有的功能,來驗證看看
namespace StreamCopyTo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            using FileStream source = File.OpenRead(@"D:\Demo.txt");
            Console.WriteLine($"Source length:{source.Length}");
            Console.WriteLine($"Source Position:{source.Position}");

            Console.WriteLine("");
            Console.WriteLine("----- CASE 1 ------");
            Console.WriteLine("");

            using MemoryStream destination = new MemoryStream();
            source.Position = 0;
            Console.WriteLine($"source Start Position:{source.Position}");

            source.CopyTo(destination);
            Console.WriteLine($"Destination length:{destination.Length}");
            Console.WriteLine($"Source - Destination Position:{source.Position}-{destination.Position}");
            if (destination.Length == destination.Position)
                Console.WriteLine("到達目的端檔案尾");

            Console.WriteLine("");
            Console.WriteLine("----- CASE 2 ------");
            Console.WriteLine("");

            using MemoryStream destination2 = new MemoryStream();
            source.Position = 8933; // 單純為了湊整數而已,沒有意義
            Console.WriteLine($"source Start Position:{source.Position}");

            source.CopyTo(destination2);
            Console.WriteLine($"Destination length:{destination2.Length}");
            Console.WriteLine($"Source - Destination Position:{source.Position}-{destination2.Position}");
        }
    }
}

File.OpenRead() 等同於 FileStream(String, FileMode.Open , FileAccess.Read , FileShare.Read)

星期二, 6月 18, 2024

[SQL] 包含特定條件

論壇問題,把問題化為圖示如下


各 ID 資料內有 Status 為 Y 資料的話,要找出 ID 資料內的日期最大值

環境建置

發問者提供資料,剛好都是 Status = 'Y' 且該日期為最大值,故意加上 ID 005 資料,有 Status = 'Y' 但該筆資料日期不是 ID 內最大值
use tempdb
go 

DROP TABLE IF EXISTS tblA
DROP TABLE IF EXISTS tblB

CREATE TABLE tblA (ID char(3) , Name nchar(6))
INSERT INTO tblA (ID , Name) VALUES
('001' , N'王小明')  , ('002' , N'張小花') ,
('003' , N'李小壯')  , ('004' , N'黃小美') , 
('005' , N'自行加入')

CREATE TABLE tblB (ID char(3) , [Status] char(1) , [Date] date)
INSERT INTO tblB (ID , [Status] , [Date]) VALUES
('001' , 'N' , '2024-01-01') , ('001' , 'N' , '2024-01-10') , ('001' , 'Y' , '2024-01-28') ,
('002' , 'X' , '2024-03-10') , ('002' , 'N' , '2024-03-25') ,
('003' , 'N' , '2024-02-05') , ('003' , 'Y' , '2024-02-13') ,
('004' , 'N' , '2024-01-13') , ('004' , 'R' , '2024-01-25') ,
('005' , 'Y' , '2024-01-13') , ('005' , 'R' , '2024-01-25') -- 有 Y 存在,但 Y 日期並非是最大值

TSQL 解法

加入 ID 005資料
SELECT 
	A.*  , 
	IIF(IsIncludeY > 0 , MaxDate , NULL) AS [Date]
FROM tblA AS A
	JOIN
		(
			SELECT ID ,
				SUM(IIF([Status] = 'Y' , 1 , 0)) AS IsIncludeY ,
				MAX([Date]) AS MaxDate
			FROM tblB
			GROUP BY ID
		) AS B ON A.ID = B.ID

寫完發現發問者有變化需求,然後我也誤會題意,練習題就這樣吧,XD

星期五, 6月 14, 2024

[C#] 繪製格線

FB 論壇上問題,之前作自訂控件時,也常常遇上繪製線條效果不如預期,這算是數學邏輯練習題,大神很數學的回答
寬度要 10n + 1 才能畫 n + 1 條線

C# WinForm Code
  • PicutreBox:用來繪製格線
  • ComboBox:設定 PictureBox 長寬
namespace GraphicsNETSample
{
    public partial class frmGridLine : Form
    {
        private int _cellLength { get; init; } = 50;
        private Pen _gridLine { get; init; } = new Pen(Color.Black, 1);
        private int _gridSizeInit { get; set; } = 500;

        public frmGridLine()
        {
            InitializeComponent();

            comboBox1.Items.Add(_gridSizeInit);
            comboBox1.Items.Add(501);
            comboBox1.SelectedIndex = comboBox1.FindStringExact(_gridSizeInit.ToString());

            SetPictureBoxSize(_gridSizeInit);
        }

        private void SetPictureBoxSize(int size)
        {
            pictureBox1.Width = size;
            pictureBox1.Height = size;
        }

        private void comboBox1_SelectionChangeCommitted(object sender, EventArgs e)
        {
            int size = Convert.ToInt32(comboBox1.Text);
            SetPictureBoxSize(size);
            pictureBox1.Refresh();
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            DrawGridLine(e.Graphics);
        }

        private void DrawGridLine(Graphics g)
        {
            RectangleF bound = g.ClipBounds;
            int boundWidth = (int)bound.Width;
            int boundHeight = (int)bound.Height;

            for (Point topLeft = new Point(0, 0); topLeft.Y <= boundHeight; topLeft.Offset(0, _cellLength))
                g.DrawLine(_gridLine, topLeft, new Point(boundWidth, topLeft.Y));

            for (Point topLeft = new Point(0, 0); topLeft.X <= boundWidth; topLeft.Offset(_cellLength, 0))
                g.DrawLine(_gridLine, topLeft, new Point(topLeft.X, boundWidth));
        }
    }
}

執行效果



星期四, 6月 13, 2024

[CCNA] Cisco Packet Tracer - 字型大小

不論學習何種技術,起手式已經變成調整 IDE 字型大小,已經不是 Hello World 了

Menu 選單 => Options => Preferences


Font Tag,預設為 8,也可以調整字型




使用版本為 8.2.2

星期六, 6月 08, 2024

[Win11] 觸控式鍵盤

同事移機後,詢問我右下角輸入鍵盤不見了,找了老半天才找到,重點在於關鍵字,那是觸控式鍵盤,不是螢幕小鍵盤

右下角的觸控式鍵盤圖示
觸控式鍵盤圖示其實是一直開啟的,但要設定一律顯示,讓它固定在那

觸控式鍵盤、螢幕小鍵盤傻傻分不清楚,其實外觀真的蠻像的,我鍵盤盲

星期五, 6月 07, 2024

[SQL] 資料列運算

在論壇上看見的問題 - 不良率呈現,同一個資料來源有兩種需求,筆記如下

資料來源
use tempdb
go

DROP TABLE IF EXISTS tblQ

CREATE TABLE tblQ (庫別 char(1) , 日期 char(2) , 類別 nvarchar(10) , 數量 int)
INSERT INTO tblQ (庫別 , 日期 , 類別 , 數量)
SELECT 'A' , '01' , N'螺絲-次' ,2 
UNION ALL  		  
SELECT 'A' , '01' , N'螺絲-全' ,1000 
UNION ALL  		  
SELECT 'B' , '01' , N'螺絲-次' ,3 
UNION ALL  		  
SELECT 'B' , '01' , N'螺絲-全' ,1100
UNION ALL  		  
-- 以下為自行加入資料
SELECT 'C' , '02' , N'螺絲-次' , 999
UNION ALL  		  
SELECT 'C' , '02' , N'螺絲-全' , 0
Q1:資料列運算

要把資料列進行百分比運算後並產生一筆百分比資料
SELECT *
FROM
	(
		SELECT 庫別 , 日期 , 類別 , 數量
		FROM tblQ
		UNION ALL
		SELECT 庫別 , 日期 , N'螺絲-率' , [螺絲-次] * 1.0 / NULLIF([螺絲-全] , 0) * 1.0
		FROM tblQ AS P
			PIVOT
				(
					SUM(數量) FOR 類別 IN ([螺絲-次] , [螺絲-全])
				) AS PV
	) AS F
ORDER BY 
	庫別 , 
	日期 , 
	CASE 類別 
		WHEN N'螺絲-次' THEN 1
		WHEN N'螺絲-全' THEN 2
		WHEN N'螺絲-率' THEN 3
		ELSE 4
	END , 
	數量
  
Q2:資料轉置

把 A1 百分比資料進行轉置
;
WITH CTE AS
(
	SELECT 庫別 , 日期 , 類別 , 數量
	FROM tblQ
	UNION ALL
	SELECT 庫別 , 日期 , N'螺絲-率' , [螺絲-次] * 1.0 / NULLIF([螺絲-全] , 0) * 1.0
	FROM tblQ AS P
		PIVOT
			(
				SUM(數量) FOR 類別 IN ([螺絲-次] , [螺絲-全])
			) AS PV
)
SELECT PV.* 
FROM CTE AS P
	PIVOT
	(
		SUM(數量) FOR 日期 IN ([01] , [02])
	) AS PV
ORDER BY 
	庫別 , 
	CASE 類別 
		WHEN N'螺絲-次' THEN 1
		WHEN N'螺絲-全' THEN 2
		WHEN N'螺絲-率' THEN 3
		ELSE 4
	END

星期四, 6月 06, 2024

[SQL] Key Lookup

延續 [SQL] Index Seek 讀取全部資料 內容,在 try 該主題執行計畫時,無意中看到沒有出現過的執行計畫執行方式 - 從 Index Scan 出發的 Key Lookup
SELECT [BusinessEntityID] , LastName , MiddleName , FirstName
FROM Person.Person
WHERE LastName LIKE '%old%'
Nonclustered index 是由 Index Key、included column 和 Clustered Key 組成,利用 Nonclustered index 搜尋資料,會先利用 Index Key 來搜尋,假如利用 Index Key 就搜尋完全部資料,此情況稱為 Covering Index(覆蓋索引);相反地,無法在 Index Key 上找到全部資料,就會進一步利用 Clustered Key 進入 Clustered Index 內去搜尋所需要資料,此行為稱為索引鍵查閱(Key Lookup),2005 SP2 之前稱為書籤查詢(Bookmark Lookup),會增加鎖定和執行時間
該說明只強調 nonclustered index,並沒有提到一定要從 Index Seek 出發,以往看見的都是 Index Seek、Nested Loop、Key Lookup 這三個 operator 組合,第一次看見是 Index Scan 出發

第一眼看見該執行計畫,直覺為什麼不是跑 Clustered Index Scan 阿

星期三, 6月 05, 2024

[SQL] Index Seek 讀取全部資料

延續 [SQL] 數學運算 - Constant Scan 發現下述 where 條件會跑出 Index Seek 讀取全部資料執行計畫後
WHERE UnitPrice >= 1.3282 -- UnitPrice 最小值
再找些不同 where 條件來觀察
SELECT SalesOrderID, UnitPrice
FROM [Sales].[SalesOrderDetail]
WHERE UnitPrice >= 1.3282        -- UnitPrice 最小值
	AND UnitPrice <= 3578.27 -- UnitPrice 最大值

SELECT SalesOrderID, UnitPrice
FROM [Sales].[SalesOrderDetail]
WHERE UnitPrice > 0

星期六, 6月 01, 2024

[SQL] 數學運算 - Constant Scan

延續 [SQL] 避免對欄位進行數學運算 筆記,官方範例原寫法如下
SELECT
	T.* ,
	UnitPrice * CAST(0.10 as money) [10% Commission]
FROM
	(
		SELECT DISTINCT SalesOrderID, UnitPrice
		FROM [Sales].[SalesOrderDetail]
                -- 官方範例寫法
		WHERE UnitPrice > 300 / 0.1
                -- 自行修正寫法
		WHERE UnitPrice > 3000
	) AS T

實際執行後發現是從 Constant Scan 開始跑,沒想到 300 / 0.1 有這樣效果,分析 operator 發現 GetRangeWithMismatchedTypes 存在,又多看見一個 Scalar Function Operator


加碼測試,找出 UnitPrice 最小值來當成條件,等同於會抓出全部資料,原本是期待會跑出 Index Scan,但還是從 Constant Scan 開始跑
WHERE UnitPrice >= 1.3282 -- UnitPrice 最小值
從執行計畫就可以看到抓出全部資料的 Index Seek,違和感很強大
把整個 where 條件都移除才會跑 Index Scan