2023年5月6日 星期六

MSSQL 2022 在 Win11 安裝圖文教學

MSSQL 2022 在 Win11 安裝圖文教學

比起Oracle這東西有圖形介面簡直太方便了,安裝也不是太複雜這邊分三篇說明。

第一篇:MSSQL 2022 在 Win11 安裝圖文教學
第二篇:MSSQL 2022 如何設定防火牆讓其他電腦連接
第三篇:MSSQL 2022 如何設定建立使用者、資料庫與表格
第四篇:MSSQL 2022 如何設定 自簽署SSL證書 加密連接
第四之二篇:MSSQL 2022 快速建構 自簽署SSL證書

本篇是第一篇安裝環境


下載並打開安裝檔案

官方的安裝包在這裡:SQL Server Downloads | Microsoft
這邊個人電腦測試載左邊Developer就好

  • Developer:功能不受限,僅限個人測試
  • Express:功能受限,可以免費用在生產環境



下載之後直接打開即可,然後選擇中間的自訂



媒體位置隨意,只是解壓縮下載的安裝檔臨時放的位置而已,然後下一步就開始下載了



開始下載


再來就能看到安裝介面了




開始安裝

接著選擇第一個開始安裝



如果有購買正版的請在這裡輸入金鑰,沒有的話選開發者版本即可免費試用


同意授權條約



然後是更新的部分,看要不要掛到WindwosUpdate上,這樣這會隨著Windwos更新順便更新SQLServer的版本了



安裝規則的部分防火牆是驚嘆號先不用管他,等會在處理就好



新版本多出來的插件用不上直接取消就好



再來特徵選取打勾第一個就好,底下看位置需不需要改自行決定



再來執行個體的名稱 (英文直翻是實例名稱)
這個會影響到在服務上看到的名稱,沒什麼特別需求預設就好



再來這裡也是預設即可下一步

SQL Server Browser 服務。當同一個服務器中存在多個實例時,可以用實例名稱替代連接埠,舉個用例應該就能馬上理解了。

實例名連接: sqlcmd -S 192.168.1.1\SQLSERVER -U sa -P 12345678

連接埠連接: sqlcmd -S 192.168.1.1,1433 -U sa -P 12345678



這邊驗證模式建議改成”混合模式”,這會啟用 SqlServer 的超級管理者 sa 帳號,之後用其他電腦連接會比較方便

然後底下按一下”加入目前的使用者”,這個是用 Windwos 使用者來驗證登入的,權限預設也是超級管理員



再來驗證一下剛剛的輸入都沒問題就可以按下安裝了



完成後可以看到這個畫面



至此就安裝完畢可以使用搂

安裝檔案資料夾預設在 C:\SQL2022 這個位置,如果不需要了是可以刪除的



下一篇 MSSQL 2022 如何設定防火牆讓其他電腦連接

MacOS視網膜顯示系統的缺陷 無法再高解析度螢幕上使用高DPI滑鼠

MacOS視網膜顯示系統的缺陷 無法再高解析度螢幕上使用高DPI滑鼠

視網膜系統

為什麼位有這個問題是因為蘋果系統中的視網膜系統並不具備有放大的功能,這個就是在Windwos下的縮放,當螢幕解析度越高理論上就需要調整縮放成125%或是150%。

縮放這個功能放大的是UI介面,假設在一個24吋1920x1080解析度裡面有個100x100大小的視窗,從物理上拿尺量該螢幕上的視窗是4公分x4公分,如果把螢幕調成4K的話公分的話那個視窗會變成2公分,如果再縮放成200%的話那麼他將會回到4公分。

這看上去很美好什麼問題都沒有,但是到了蘋果陣營之後基於”視網膜顯示系統”的概念,蘋果並不這麼想,他認為使用者不應該去調整放大倍率,使用者只需要知道自己想要多大解析度的螢幕即可,使用者並不需要調整螢幕解析度。

這是什麼意思呢,白話翻譯一下就是我希望使用1920x1080的螢幕,但是他必須適用在任何螢幕上,接到4K螢幕自動適應我的操作空間依然是[1920x1080]但是顯示是[3840x2160]。


滑鼠DPI 

假設滑鼠在滑鼠墊上物理的移動3公分正好可以把滑鼠游標移動1920次,這就意味著在1K的螢幕上只需要移動3公分就可以正好移動一個螢幕的跨度從最左到最右。在

所以在Windows陣營上,如果更換4K螢幕之後相對應的你的滑鼠也必須更換較高DPI的滑鼠,以獲取與原本完全對等的操作體驗。


視網膜系統的縮放

在視網膜顯示系統上”縮放”是自動的無法手動調整,這就意味著如果你要放大200%該做的是把解析度調整成物理解析度的一半,這樣輸出的時候就會自動放大200%了。

根據視網膜系統的概念,你可以在[1920x1080]的邏輯解析度操作,但是實際上輸出到螢幕的時候他會自動幫你映射成4K解析度,從而不會看到鋸齒。

看上去很完美對不對,別忘了邏輯解析度只有[1920x1080],這就意味了你的滑鼠不需要更新高DPI滑鼠也可以適用。

這個在不理智果迷上稱做微軟好爛換螢幕還要換滑鼠,蘋果好棒棒都幫你處你好了

問題就出在於如果單純的只是把滑鼠指標2倍映射到4K上那不就代表,會有某些螢幕上的點這滑鼠永遠都指不到了? 

蘋果其實沒那麼笨重新映射到物理解析度的時候使用的是滑鼠加速而不是線性映射,但問題就出在那個滑鼠加速不好用阿,否則電競選手幹嘛買滑鼠呢?


而寫到這裡你應該也發現了,要嘛就忍受超級小的UI然後滑鼠可以正常用高DPI滑鼠,要嘛就乖乖放大,然後滑鼠只能用低DPI+很難操作的滑鼠加速來操作電腦。


重大缺陷

到這我覺得,這個絕對是這個重大缺陷!!!

我可以理解蘋果為什麼要搞視網膜系統,這樣對於電腦白吃就不需要去思考為什麼我要放大了,不需要去思考為什麼我的筆電接上1K跟接上8K操作起來手感不一樣了。

但是我不能理解為什麼要把縮放功能給禁用掉? 這不就注定蘋果系統很難在高解析度螢幕上操作了,因為滑鼠加速絕對沒有比高DPI來的精準好操用。






2023年4月29日 星期六

正則表達處理路徑 獲取檔名或副檔名

正則表達處理路徑 獲取檔名或副檔名

  1. 為了適應 Windows 和 Unix 類操作系統的路徑,使用了 [\/] 來匹配路徑分隔符,這樣可以同時匹配正斜杠(/)和反斜杠(\)。
  2. 正則表達式仍然可能在一些極端情況下失效,例如檔案名稱中含有正則表達式特殊字符等。



正則表達式

這邊用 PowerShell 當範例,打開之後直接貼上就能測試了。

範例路徑

$path = "C:\Users\Username\Documents\example.txt"
$path = "C:\Users\Username\Documents\.git\example"
$path = "C:\Users\Username\Documents\.git\example.fix.txt"
$path = "C:\Users\Username\Documents\.git\.gitignore"

這邊多給兩個比較機車的情況當測試樣本。


檔案名稱

# 使用 -replace 運算符和正則表達式來獲取檔案名稱
$filenameWithoutExtension = $path -replace '^(.*[\\/])([^\\/]+?)(\.[^\\/.]+)?$', '$2'

完整檔案名稱

# 使用 -replace 運算符和正則表達式來獲取檔名(包含副檔名)
$filenameWithExtension = $path -replace '^(.*[\\/])'

副檔名

# 使用 -replace 運算符和正則表達式來獲取副檔名
$extension = $path -replace '^.*[/\\][^/\\]*?(\.[^/\\.]*)?$','$1'
$extension = ($path -replace '^.*[/\\]([^/\\]*)$', '$1') -replace '^.*?\.([^.]*)$|^.*$', '$1'

父資料夾名

# 使用 -replace 運算符和正則表達式來獲取父資料夾名稱
$parentFolderName = $path -replace '^(.*[\\/])?([^\\/]*)[\\/]([^\\/]+)$', '$2'

檔案所在路徑

# 使用 -replace 運算符和正則表達式來獲取檔案所在路徑
$filePath = $path -replace '[\\/]([^\\/]*)$'


 

在 PowerShell 中其實有提供以上需求的C#函式,如果不是舊版沒支援建議是直接用內建函式比較妥,至少有保證不會出事。



2023年4月23日 星期日

MSSQL 如何透過 PowerShell 上傳 CSV 到資料庫上

MSSQL 如何透過 Bat 上傳 CSV 到資料庫上

能夠上傳CSV的指令微軟內建有兩個 bcp.exe 跟 BULK INSERT,不過後者是寫在sql中的代碼有個很致命的缺點是只能上傳HOST端上的檔案,無法從其他電腦上傳過去。

還有一點要注意的是雖然文章是寫CSV,不過準確地來講是DATA,內容不能包含檔頭與頭尾雙引號。不能包含是因為他就按照那個樣子傳上去,到時候資料庫上會看到全部都帶有雙引號,也因為沒有雙引號保護的關係,是無法上傳逗號上去的,會被當作下一份資料的分割。




BULK INSERT 的上傳方法

雖然已知這方法有個根本上的致命問題,不過還是筆記一下紀錄,或許會在哪裡用到。要解決這個致命問題其實有另一個解法是把CSV上傳到HOST也能讀取的SAMA上就能傳了。

這個方法好處大概就是可以跳過檔頭吧,代碼中的 “FIRSTROW = 2” 指的是從第二行開始上傳。

$serverName = "localhost"
$databaseName = "CHG"
$userName = "kaede"
$password = "1230"

$csvFilePath = "\\ORACLE-SV\Source\csvfile.csv"
$schemaName = "CHG"
$tableName = "Employees"
$Table = "[$databaseName].[$schemaName].[$tableName]"

$query = @"
BULK INSERT $Table
FROM '$csvFilePath'
WITH
(
    FORMAT = 'CSV',
    FIRSTROW = 2
);
"@

sqlcmd -S $serverName -d $databaseName -U $userName -P $password -Q $query

-




BCP 的上傳方法

因為檔案是要讀取純資料的關係,這邊也寫了一個函式自動處理CSV的轉換。

function Export-CustomCSV {
    param (
        [Parameter(ValueFromPipeline = $true)]
        [psobject[]]$InputObject,
        [string]$InputPath,
        [Parameter(Mandatory = $true)]
        [string]$OutputPath,
        [string]$Delimiter = ',',
        [System.Text.Encoding]$Encoding = (New-Object System.Text.UTF8Encoding $False),
        [switch]$SkipHeader
    )

    begin {
        $writer = New-Object System.IO.StreamWriter -ArgumentList $OutputPath, $false, $Encoding
        $headerProcessed = $false
    }

    process {
        if ($InputObject) {
            foreach ($obj in $InputObject) {
                $line = ""
                $properties = $obj | Get-Member -MemberType Properties
                foreach ($prop in $properties) {
                    if (-not [string]::IsNullOrEmpty($line)) {
                        $line += $Delimiter
                    }
                    $value = $obj.$($prop.Name) -replace '"', '""'
                    $line += $value
                }
                $writer.WriteLine($line)
            }
        } elseif ($InputPath) {
            $reader = New-Object System.IO.StreamReader -ArgumentList $InputPath, $Encoding
            while (-not $reader.EndOfStream) {
                $line = $reader.ReadLine()
                if ($SkipHeader -and -not $headerProcessed) {
                    $headerProcessed = $true
                    continue
                }
                $fields = $line.Split($Delimiter)
                $newLine = ""
                for ($i = 0; $i -lt $fields.Length; $i++) {
                    $cleanField = $fields[$i].Trim('"')
                    if ($i -gt 0) {
                        $newLine += $Delimiter
                    }
                    $newLine += $cleanField
                }
                $writer.WriteLine($newLine)
            }
            $reader.Close()
        }
    }

    end {
        $writer.Close()
    }
}

接下來是上傳的部分

$sourceCsv = 'input.csv'  # 更改為您的源 CSV 文件路徑
$destinationCsv = 'output_existing.csv'  # 更改為您的目標 CSV 文件路徑
Export-CustomCSV -InputPath $sourceCsv -OutputPath $destinationCsv -SkipHeader

$serverName   = "localhost"
$databaseName = "CHG"
$userName     = "kaede"
$password     = "1230"
$schemaName = "CHG"
$tableName = "TEST"
$Table = "[$databaseName].[$schemaName].[$tableName]"

$csv = $destinationCsv
$output = & bcp $Table in $csv -c -t ',' -r "\n" -S $serverName -U $userName -P $password
$hasError = $false
$numRowsCopied = 0

$outputString = $output -join "`n"
if ($outputString -match "(\d+) rows copied\.") {
    $numRowsCopied = [int]$matches[1]
    if ($numRowsCopied -eq 0) {
        $hasError = $true
    }
}

if ($hasError) {
    Write-Host "BCP 命令執行失敗,錯誤信息:"
    Write-Host $outputString
} else {
    Write-Host "BCP 命令執行成功,共複製了 $numRowsCopied 行"
}

-


追加寫完之後發現 PowerShell 還有一個工具 System.Data.SqlClient.SqlConnection 這個應該才是標準解,專門為編程而生的,搞定了再放上來。

2023年4月11日 星期二

正則如何抓出所有雙引號並修改特定字串

正則如何抓出所有雙引號並修改特定字串

這個問題之前看PTT版討論可能好像是無解,不過今年因為GPT出了正則變得更容易使用了,不需要花大量時間,少樣本學習直接丟就有答案了。

這邊用的語言是 Powershell 可以直接打開終端機輸入就可以驗證了



匹配雙引號中的字串

先來個範例樣本

$csv_string = '"a", "b", "c"'

對應的代碼是

$csv_string = '"a", "b", "c"'
$pattern = '(?<=\")[^"\s]*(?=\")'
$matches = [regex]::Matches($csv_string, $pattern) | ForEach-Object { $_.Value }

$matches

如此一來就可以取出 abc 的陣列了,後面的 ForEach-Object { $_.Value } 只是把regex物件中的字串給抓出來而已


不過這有個問題如果字串是相連的 '"dd1"ffff"dd2"' 會抓到中間值,抓出三個連帶ffff也抓了。對於這個的解法是

$csv_string = '"dd1"ffff"dd2"'
$pattern = '(?<=\")[^"\s]*?(?=\"(?:[^"]*"[^"]*")*[^"]*$)'
$matches = [regex]::Matches($csv_string, $pattern) | ForEach-Object { $_.Value }

$matches

這樣可以準確避開了,不過我想如果情況再複雜一點可能也會出bug,在長下去也沒意義了,太長了無法閱讀之外也容易埋雷,依照情況適當選用就好。



匹配雙引號中的字串並取代替特定字串

進階一點換一個範例,這次除了要抓出雙引號之外還附加要修改雙引號內特定的字串

$csv_string = '"ahuchgnde@#", "gokerjorb", "eokgchgjoec", chg, "chg"'

以這個字串來說我要把chg改成[CHG],並且設置了檢查項目其中有一個chg是不帶雙引號的

$csv_string = '"ahuchgnde@#", "gokerjorb", "eokgchgjoec"'
$pattern = '((?<=")[^"]*?)chg(([^"]*?)(?="))'
$replacement = '$1[CHG]$3'

$new_csv_string = $csv_string -replace $pattern, $replacement
$new_csv_string



匹配雙引號中的雙引號

難的地方在於雙引號沒辦法區分頭尾,雖然用看得看的出來但是真的要寫實在是無從下手。

經過反覆確認如果是沒有給定條件是判斷不出來的,這邊用CSV的文本當範例可以用逗號輔助判斷頭尾雙引了,沒這逗號replace是做不到的。

$csv_string = 'some data,"AAA""這裡""AA", "BBBBBB",more data,"", "CCCDDD""EEE"""'

以這個範例來說我要消除雙引號中的雙引號,消除到只剩一個

$csv_string = 'some data,"AAA""這裡""AA", "BBBBBB",more data,"", "CCCDDD""EEE"""'
$regex = '(?<=[^,])""(?=[^,])'
$csv_string = $csv_string -replace $regex, '"'
$csv_string

如此一來就可以抓出來了,如果要完全消除就把後面的雙引號留空白就好

不過這還是有個小問題是如果引號中的引號不是兩個一組出現,就無法處理了。試了很久沒出來估計是正則做不到了。




2023年4月9日 星期日

VMware 出現 侧通道缓解 的錯誤信息

VMware 出現 侧通道缓解 的錯誤信息

信息是:

您在运行该虚拟机时启用了侧通道缓解。侧通道缓解可增强安全性,但也会降低性能。
要禁用缓解,请在虚拟机设置的“高级”面板中更改侧通道缓解设置。有关更多详细信息,请参阅 VMware 知识库文章 79832,网址为

會出現這個是因為安裝了 docker 被打開系統中的虛擬機功能導致的,雖然有個解決辦法是依照網址操作把那功能給官掉就好了,不過虛擬機性能變的超級差,最後還是得復原才能正常。

關掉的方法是先移除 docker 然後在確保這兩個功能關閉即可。



如果電腦也有開 wsl 記得要轉回來 ws1 不然可能會無法使用

wsl --set-version Ubuntu-20.04 1


還有一個問題是這頓操作過程可能會新增一個 Hyper-V 的虛擬網卡出來,會導致VM預設去讀那張卡,因為已經刪掉docker並且關掉虛擬功能了,那張卡會沒網路。

需要手動那張卡刪除或是從VM的設定中選中自己的自己網卡,不然自動狀態會優先讀 Hyper-V 的網卡導致梅網路。



2023年4月5日 星期三

JavaScript 轉譯 XML 特殊符號

JavaScript 轉譯 XML 特殊符號

因為只有5個而已沒有線程的函式庫可以用,自己刻了一個又覺得直接替換好像有點太簡單,姑且看了一下怎麼用一張映射表來轉譯。

這個可以透過修改映射表任意變更對應的關係,相對來說應用在別的對方要修改可能會方便不少。


代碼

先上最簡單的直接替換掉

// 將實體字符轉換為特殊字符
const encodeXml = str => str.replace(/&/g, '&amp;')
                            .replace(/</g, '&lt;')
                            .replace(/>/g, '&gt;')
                            .replace(/"/g, '&quot;')
                            .replace(/'/g, '&apos;');

// 將特殊字符轉換為實體字符
const decodeXml = str => str.replace(/&amp;/g, '&')
                            .replace(/&lt;/g, '<')
                            .replace(/&gt;/g, '>')
                            .replace(/&quot;/g, '"')
                            .replace(/&apos;/g, "'");

再來這個是統一拉到映射表理管理的做法

// 映射表
const entitiesMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&apos;',
}; const rvEntitiesMap = Object.fromEntries(Object.entries(entitiesMap).map(([k, v]) => [v, k]));

// 將實體字符轉換為特殊字符
const encodeXml = str => {
  const regex = new RegExp(`[${Object.keys(entitiesMap).join('|')}]`, 'g');
  return str.replace(regex, m => entitiesMap[m]);
};
// 將特殊字符轉換為實體字符
const decodeXml = str => {
  const regex = new RegExp(`(${Object.keys(rvEntitiesMap).join('|')})`, 'g');
  return str.replace(regex, m => rvEntitiesMap[m]);
};

// 測試
const text = '<root><node id="1">Hello & World</node></root>';
const encodedText = encodeXml(text);
const decodedText = decodeXml(encodedText);
console.log('原始文本:', text);
console.log('編碼後文本:', encodedText);
console.log('解碼後文本:', decodedText);

結果

原始文本: <root><node id="1">Hello & World</node></root>
編碼後文本: &lt;root&gt;&lt;node id=&quot;1&quot;&gt;Hello &amp; World&lt;/node&gt;&lt;/root&gt;
解碼後文本: <root><node id="1">Hello & World</node></root>




版本問題

反轉哈希表的部分需要ES2019才能跑,不能跑可以替換成這個舊版的寫法

const rvEntitiesMap = Object.entries(entities).reduce((acc, [k, v]) => {
  acc[v] = k;
  return acc;
}, {});

-