2025年4月30日 星期三

[研究] Microsoft SQL Server 2022 版本比較、授權、定價、訂價、價格

[研究] Microsoft SQL Server 2022 版本比較、授權、定價、訂價、價格

2022-04-30

SQL Server 2022 (16.0.1000.6) 於2022年11月16日發行

Microsoft SQL Server Versions List

SQL Server 2022, 2019, 2017 版本比較

SQL Server 2022 Datasheet (資料供作表),了解 SQL Server 2022 目前提供的功能及優點。

Double click 可以看100% 原始圖

因為官方可能不定時調整,所有資訊以官方網站最新版資訊為準,本網頁資訊僅供參考。

敝人對雲端版興趣不高,請自行研究。

Microsoft SQL Server - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/Microsoft_SQL_Server

SQL Server 2022 Developer 或 SQL Server 2022 Express 免費版下載
https://www.microsoft.com/zh-tw/sql-server/sql-server-downloads

SQL Server Express - 維基百科,自由的百科全書
https://zh.wikipedia.org/wiki/SQL_Server_Express
這裡只談到 SQL Server 2017 Express

SQL Server Express 只支援
  • 1顆 CPU or 4 Cores  ( 到 SQL Server 2019 仍如此)
  • 單一資料庫大小在 SQL Server 2005 Express和SQL Server 2008 Express 可到 4GB,最新版本的SQL Server 2008 R2 Express ~ SQL Server 2016 Express 最大資料庫 10G  ( 到 SQL Server 2019 仍 10GB )
  • 1GB RAM ( 到 SQL Server 2019 仍如此)
基本上商業使用不建議用 Express 版,因為SQL Server Agent沒有作用,不能設定維護計畫,不能每天自動備份資料庫,DB大小受限,能使用的 CPU/core和 RAM受限,效能不佳。

********************************************************************************
SQL Server 2022 定價
閱讀 SQL Server 2022 授權資料工作表 (PDF) SQL_Server_2022_Licensing_Datasheet.pdf

閱讀 SQL Server 2022 授權指南 (PDF) SQL_Server_2022_Licensing_guide.pdf

定價 - 買斷方式 (永久授權)

版本Open No Level 價格 (美元)授權模型通路供應情況
EnterpriseUSD15,1232 核心套件大量授權、主控
Standard - 每一核心USD  3,9452 核心套件大量授權、主控
Standard - 伺服器USD     989伺服器[3]大量授權、主控
Standard - CALUSD     230CAL大量授權、主控
Developer免費每位使用者免費下載
Web請洽詢您的主控合作夥伴以取得定價資訊不適用僅主控
Express免費不適用免費下載

隨用隨附 - Azure Arc

版本每月費率 (美元)每小時費率
Standard - 每一核心USD73USD0.100
Enterprise - 每一核心USD274USD0.375

訂閱方式

訂閱及附加元件價格 (美元)授權模型通路供應情況
SQL Server Enterprise每年 USD5,4342 核心套件大量授權
SQL Server Standard每年 USD1,4182 核心套件大量授權

後面不再談每年訂閱方式,不想每年花錢麻煩;
買斷商業授權模式有 根據 CPU Cores/Pack 方式,或 Server + CAL 方式2種。

如果一般是給 Internet 公開使用的 Web Server ( Web Site) 網站使用 SQL Server,一般買 Core 授權 ( 上面 "Standard - 每一核心" 其實指 Core 授權,"2 CPU cores / pack" 方式,每個 pack 賣 USD  3,945 ( *35 = NT$138,075,將近 14 萬)

架設的 SQL Server 或網站是給內部固定人數使用,可考慮  Server + CAL,新增員工就加買 CAL 授權。

********************************************************************************

Read the SQL Server 2019 licensing data sheet
Read the SQL Server 2019 licensing guide
https://www.microsoft.com/en-us/sql-server/sql-server-2019-pricing#CP_StickyNav_1


(下圖) 授權模型 Licensing Model

(下圖) 個別虛擬機器 (Individual Virtual Machine ) or 容器 (Container)

安裝於 VM,如果 vCores 少於4,至少要買 4 Cores 授權;高於4則,則依據 vCores 數買。


(完)

相關

[研究] Microsoft SQL Server 2022 版本比較、授權、定價、訂價、價格
https://shaurong.blogspot.com/2025/04/microsoft-sql-server-2022.html

[研究] Windows Server 2019 版本比較、授權、定價
https://shaurong.blogspot.com/2018/12/windows-server-2019.html

[研究] Microsoft SQL Server 2017 版本比較、授權、定價
https://shaurong.blogspot.com/2017/09/microsoft-sql-server-2017.html

[研究] MSDN 訂閱 ( Visual Studio 2019 ) 版本比較、授權、定價
https://shaurong.blogspot.com/2019/11/msdn-visual-studio-2019.html

[研究] Visual Studio Community 社群版授權
https://shaurong.blogspot.com/2019/10/visual-studio-community.html

[研究] VMware 與 VirtualBox 授權 (Licensing)
https://shaurong.blogspot.com/2017/07/vmware-virtualbox-licensing.html

[研究] Apose.PDF 訂價與授權定價, 訂價, 授權
https://shaurong.blogspot.com/2019/11/aposepdf.html

[研究] Froala Editor 訂價與授權
https://shaurong.blogspot.com/2019/11/froala-editor.html

Windows Server 2019
https://zh.wikipedia.org/wiki/Windows_Server_2019

[研究] Windows Server 2016 版本比較、授權、定價
http://shaurong.blogspot.com/2017/02/windows-server-2016.html

[研究] SQL Server 2016 版本比較、授權、定價
http://shaurong.blogspot.com/2016/06/sql-server-2016_8.html

[研究] MSDN Subscriptions 訂閱者授權
http://shaurong.blogspot.com/2016/05/msdn-subscriptions.html

[研究] Windows Server 2012 R2 授權資訊
http://shaurong.blogspot.tw/2015/10/windows-server-2012-r2_19.html

[研究]軟體保證 (Software Assurance,SA、軟體保證方案、軟體保證更新規劃、版本升級保護、微軟軟體保證)

[研究]軟體保證 (Software Assurance,SA、軟體保證方案、軟體保證更新規劃、版本升級保護、微軟軟體保證)

2025-04-30、2025-05-02

「軟體保證」這個名稱,如果不特別括弧起來,或括弧加個英文原文,可能在採購申請過程的文件,可能就被當成一個敘述而被修改了。

軟體保證更新規劃指南 (PDF)
https://download.microsoft.com/download/E/4/6/E46C671F-A58C-45CF-9C01-87DFB8F66C6C/Renewal_Planning_Guide_1108.pdf

Software Assurance Benefits: Entitlement Summay
Commercial and Goverment Offerings
https://download.microsoft.com/download/6/C/5/6C576C0C-F740-48E2-86E1-25B15BE23879/SA_InteractiveBenefitsChart_2013_TC.pdf

簡單來說,SA 期間,該項微軟產品可以免費升級,省去再次採購麻煩;

是否合算?很難說

Click圖片可以看100%







********************************************************************************

共同供應契約採購案 - 微軟軟體

https://www.systexsoftware.com.tw/Price/Content?c=295&parentId=23940



項次品名級距決標單價
101SQL Server 標準版 2 Core 最新授權版2-281$ 142,035
102SQL Server 標準版 2 Core 最新授權版 (含三年軟體保證)2-155$ 245,390
103SQL Server 標準版 2 Core 軟體保證續約2-362$ 105,171
133Windows Server 標準版 2 Core 最新授權版(含三年軟體保證)1-4528$ 8,915
134Windows Server 標準版 2 Core 軟體保證續約1-10540$ 3,828

以100萬來說,買【SQL Server 標準版 2 Core 最新授權版 (含三年軟體保證)】

1,000,000 / 245,390 = 4 pack = 8 core

到年底 SQL Server 2025問世後,可以升級 SQL Server 2025,只是只有 8 core

買【SQL Server 標準版 2 Core 最新授權版】

----------

1,000,000 / 245,390 = 7 pack = 14 core

雖然到年底不能升級 SQL Server 2022 不能升級 SQL Server 2025,但買到的量較多

********************************************************************************

Microsoft SQL Server Versions List
https://sqlserverbuilds.blogspot.com/

版本正式版釋出日期
SQL Server 2025未定
SQL Server 20222022-11-16
SQL Server 20192019-11-04
SQL Server 20172017-10-02
SQL Server 20162016-06-01

搜尋產品和服務生命週期資訊

https://learn.microsoft.com/zh-tw/lifecycle/products/?terms=Windows%20Server

Windows Server 版本發行日期
Windows Server 20162016 年 10 月 12 日
Windows Server 20192018 年 11 月 13 日
Windows Server 20222021 年 8 月 18 日
Windows Server 20252024 年 11 月 1 日

********************************************************************************

Microsoft Volume License Agreement Summary 範例 (Microsoft 大量授權協議摘要)

* If a minus quantity is stated in the Quantity Ordered sections below, this means that we have reduced your previous order by the number of licenses reflected. Please refer to VLSC for the updated summary of all your Licensing Enrollment details.
If you have ordered Russian language products or experience any problems with your Product Keys and wish to obtain your local Microsoft Activation Center phone number, please go to https://www.microsoft.com/licensing/existing-customer/activation-centers
This is not a license confirmation. This Order confirmation, any other order confirmation you receive under your Select Plus Agreement, and any documentation evidencing transfers of licenses as described in your Select Plus Agreement, together with your proof of payment, will be your evidence of the licenses acquired under your agreement
You may also access your order confirmations online through VLSC at https://www.microsoft.com/licensing/servicecente or/r a successor site that we identify. The website records will prevail in the case of any inconsistency between this Order Confirmation and the website order records.
Again, we would like to thank you for placing your order with Microsoft. If you have any questions, please contact your Channel Partner who will work with Microsoft on your behalf.

* 如果下面的訂購數量部分中顯示為負數,則表示我們已從您先前的訂單中減少了所反映的許可證數量。請參閱 VLSC 以取得所有許可註冊詳細資訊的更新摘要。
如果您訂購了俄語產品或遇到產品金鑰問題並希望取得當地的 Microsoft 啟動中心電話號碼,請造訪 https://www.microsoft.com/licensing/existing-customer/activation-centers
這不是許可證確認。本訂單確認書、您根據 Select Plus 協議收到的任何其他訂單確認書以及 Select Plus 協議中所述的任何許可轉讓證明文件,連同您的付款證明,將作為您根據協議獲得許可的證據
您也可以透過 VLSC 在線訪問您的訂單確認,網址為 https://www.microsoft.com/licensing/servicecente 或我們指定的後續網站。若本訂單確認書與網站訂單記錄有任何不一致,以網站記錄為準。
再次感謝您向微軟下訂單。如果您有任何疑問,請聯絡您的通路合作夥伴,他們將代表您與 Microsoft 合作。


SQL Server Standard Core SLng LSA 2L 和 Win Server Standard Core SLng LSA 2L 意義 ?

ChatGPT 說:

這兩個名稱看起來是來自 Microsoft 授權型號(License Stock Keeping Unit, SKU) 的縮寫格式,常出現在採購單或微軟授權產品清單中。以下是這兩個 SKU 的說明:

🔹 SQL Server Standard Core SLng LSA 2L

  • SQL Server Standard Core:表示是 SQL Server Standard 版的核心授權(Core-based licensing),不是以 Server + CAL 模式授權。
  • SLng(Software Licensing)可能是簡寫,實際意思常為 "Software License"。
  • LSA:通常代表 License & Software Assurance(授權加上軟體保證)。
  • 2L:表示 授權兩個實體核心(2 Licenses)。在 Microsoft SQL Core 授權模式中,最小授權單位為 4 核心(即使實際只有 2 核),但有時會分別列出 2L 表示每單位數量。
🔹 Windows Server Standard Core SLng LSA 2L

  • Windows Server Standard Core:表示是 Windows Server Standard 版的核心授權模式,不是舊版以伺服器+CAL 的方式。
  • SLng:同上,可能是指 Software Licensing。
  • LSA:同樣為 License & Software Assurance。
  • 2L:授權 2 核心(2 Licenses)。
🔸 常見補充說明
Windows Server 和 SQL Server 授權的核心模型,都需要按實體或虛擬機的核心數授權,且:
  • 每台實體伺服器最少授權 8 核/伺服器 + 16 核/作業系統(SQL 可能要求最低 4 核)。
  • 授權都是 以 2 核為一單位 販售(所以你會看到 2L)。
  • LSA 指同時買下授權與 Software Assurance,會包括未來升級、再安裝等權益。
********************************************************************************


(完)

相關

微軟推軟體保證(SA)下猛藥, 2003-08-20發表
https://www.ithome.com.tw/news/21659

2025年4月29日 星期二

[研究]ASP.NET,WebForm,e.NewValues存入 DB 的 float 欄位後可能變了(二)

[研究]ASP.NET,WebForm,e.NewValues存入 DB 的 float 欄位後可能變了(二)

2025-04-29

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

[研究]ASP.NET,WebForm,e.NewValues存入 DB 的 float 欄位後可能變了(一)
https://shaurong.blogspot.com/2025/04/aspnetwebformenewvalues-db-float.html

********************************************************************************

擷取發生狀況的程式中的相關部分,寫了程式測試

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default1.aspx.cs"
    Inherits="WebApplication1.Default1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:SqlDataSource ID="SqlDataSource1" runat="server"
            ConnectionString="<%$ ConnectionStrings:MyDBConnectionString %>"
            DeleteCommand="DELETE FROM [Table58] WHERE [SN] = @SN"
            InsertCommand="INSERT INTO [Table58] ([floatField], [decimalField], [realField], [numericField]) 
                VALUES (@floatField, @decimalField, @realField, @numericField)"
            SelectCommand="SELECT * FROM [Table58]"
            UpdateCommand="UPDATE [Table58] SET [floatField] = @floatField, [decimalField] = @decimalField, 
                [realField] = @realField, [numericField] = @numericField WHERE [SN] = @SN">
            <DeleteParameters>
                <asp:Parameter Name="SN" Type="Int32" />
            </DeleteParameters>
            <InsertParameters>
                <asp:Parameter Name="floatField" Type="Double" />
                <asp:Parameter Name="decimalField" Type="Decimal" />
                <asp:Parameter Name="realField" Type="Single" />
                <asp:Parameter Name="numericField" Type="Decimal" />
            </InsertParameters>
            <UpdateParameters>
                <asp:Parameter Name="floatField" Type="Double" />
                <asp:Parameter Name="decimalField" Type="Decimal" />
                <asp:Parameter Name="realField" Type="Single" />
                <asp:Parameter Name="numericField" Type="Decimal" />
                <asp:Parameter Name="SN" Type="Int32" />
            </UpdateParameters>
        </asp:SqlDataSource>
        <asp:GridView ID="GridView1" runat="server" AllowPaging="False" AllowSorting="True" AutoGenerateColumns="False"
            EmptyDataText="無資料" DataKeyNames="SN" DataSourceID="SqlDataSource1">
            <Columns>
                <asp:BoundField DataField="SN" HeaderText="SN" InsertVisible="False" ReadOnly="True" SortExpression="SN" />
                <asp:BoundField DataField="floatField" HeaderText="floatField" SortExpression="floatField" />
                <asp:BoundField DataField="decimalField" HeaderText="decimalField" SortExpression="decimalField" />
                <asp:BoundField DataField="realField" HeaderText="realField" SortExpression="realField" />
                <asp:BoundField DataField="numericField" HeaderText="numericField" SortExpression="numericField" />
            </Columns>
        </asp:GridView>
        <br />
        <asp:DetailsView ID="DetailsView1" DefaultMode="Edit" runat="server"
            Height="50px" Width="600px" AutoGenerateRows="False" DataKeyNames="SN" DataSourceID="SqlDataSource1"
            OnItemInserted="DetailsView1_ItemInserted"
            OnItemInserting="DetailsView1_ItemInserting" AllowPaging="True" OnItemUpdating="DetailsView1_ItemUpdating">
            <Fields>
                <asp:BoundField DataField="SN" HeaderText="SN" InsertVisible="False" ReadOnly="True" SortExpression="SN" />
                <asp:TemplateField HeaderText="floatField" SortExpression="floatField">
                    <InsertItemTemplate>
                        <asp:TextBox ID="TextBox_floatField" runat="server" Text='<%# Bind("floatField") %>'></asp:TextBox>
                    </InsertItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="TextBox_floatField" runat="server" Text='<%# Bind("floatField") %>'></asp:TextBox>
                    </EditItemTemplate>
                    <ItemTemplate>
                        <asp:Label ID="Label1" runat="server" Text='<%# Bind("floatField") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="decimalField" SortExpression="decimalField">
                    <InsertItemTemplate>
                        <asp:TextBox ID="TextBox_decimalField" runat="server" Text='<%# Bind("decimalField") %>'></asp:TextBox>
                    </InsertItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="TextBox_decimalField" runat="server" Text='<%# Bind("decimalField") %>'></asp:TextBox>
                    </EditItemTemplate>
                    <ItemTemplate>
                        <asp:Label ID="Label2" runat="server" Text='<%# Bind("decimalField") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="realField" SortExpression="realField">
                    <InsertItemTemplate>
                        <asp:TextBox ID="TextBox_realField" runat="server" Text='<%# Bind("realField") %>'></asp:TextBox>
                    </InsertItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="TextBox_realField" runat="server" Text='<%# Bind("realField") %>'></asp:TextBox>
                    </EditItemTemplate>
                    <ItemTemplate>
                        <asp:Label ID="Label3" runat="server" Text='<%# Bind("realField") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderText="numericField" SortExpression="numericField">
                    <InsertItemTemplate>
                        <asp:TextBox ID="TextBox_numericField" runat="server" Text='<%# Bind("numericField") %>'></asp:TextBox>
                    </InsertItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="TextBox_numericField" runat="server" Text='<%# Bind("numericField") %>'></asp:TextBox>
                    </EditItemTemplate>
                    <ItemTemplate>
                        <asp:Label ID="Label4" runat="server" Text='<%# Bind("numericField") %>'></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:CommandField ShowInsertButton="True" ShowDeleteButton="True" ShowEditButton="True" />
            </Fields>
        </asp:DetailsView>
        <asp:Button ID="Button1" runat="server" Text="新增10筆" OnClick="Button1_Click" />
        <asp:Button ID="Button2" runat="server" Text="更新10筆" OnClick="Button2_Click" />
    </form>
</body>
</html>



Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class Default1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
           
        }

        protected void DetailsView1_ItemInserted(object sender, DetailsViewInsertedEventArgs e)
        {
            GridView1.DataBind();
        }

        protected void DetailsView1_ItemInserting(object sender, DetailsViewInsertEventArgs e)
        {

            string floatField = e.Values["floatField"].ToString().Trim();
            Int32.TryParse(floatField, out int floatFieldInt);
            e.Values["floatField"] = floatFieldInt / 100.0;

            string decimalField = e.Values["decimalField"].ToString().Trim();
            Int32.TryParse(decimalField, out int decimalFieldInt);
            e.Values["decimalField"] = decimalFieldInt / 100.0;

            string realField = e.Values["realField"].ToString().Trim();
            Int32.TryParse(realField, out int realFieldInt);
            e.Values["realField"] = realFieldInt / 100.0;

            string numericField = e.Values["numericField"].ToString().Trim();
            Int32.TryParse(numericField, out int numericFieldInt);
            e.Values["numericField"] = numericFieldInt / 100.0;
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            DetailsView1.ChangeMode(DetailsViewMode.Insert);

            TextBox TextBox_floatField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_floatField = row.FindControl("TextBox_floatField") as TextBox;
                if (TextBox_floatField != null)
                {
                    break; // 找到就跳出
                }
            }

            TextBox TextBox_decimalField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_decimalField = row.FindControl("TextBox_decimalField") as TextBox;
                if (TextBox_decimalField != null)
                {
                    break; // 找到就跳出
                }
            }

            TextBox TextBox_realField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_realField = row.FindControl("TextBox_realField") as TextBox;
                if (TextBox_realField != null)
                {
                    break; // 找到就跳出
                }
            }

            TextBox TextBox_numericField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_numericField = row.FindControl("TextBox_numericField") as TextBox;
                if (TextBox_numericField != null)
                {
                    break; // 找到就跳出
                }
            }

            for (int i = 50; i <= 60; i++)
            {
                TextBox_floatField.Text = i.ToString();
                TextBox_decimalField.Text = i.ToString();
                TextBox_realField.Text = i.ToString();
                TextBox_numericField.Text = i.ToString();
                DetailsView1.ChangeMode(DetailsViewMode.Insert);
                DetailsView1.InsertItem(true);
            }
        }
        protected void Button2_Click(object sender, EventArgs e)
        {
            DetailsView1.ChangeMode(DetailsViewMode.Edit);

            TextBox TextBox_floatField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_floatField = row.FindControl("TextBox_floatField") as TextBox;
                if (TextBox_floatField != null)
                {
                    break; // 找到就跳出
                }
            }

            TextBox TextBox_decimalField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_decimalField = row.FindControl("TextBox_decimalField") as TextBox;
                if (TextBox_decimalField != null)
                {
                    break; // 找到就跳出
                }
            }

            TextBox TextBox_realField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_realField = row.FindControl("TextBox_realField") as TextBox;
                if (TextBox_realField != null)
                {
                    break; // 找到就跳出
                }
            }

            TextBox TextBox_numericField = null;
            foreach (DetailsViewRow row in DetailsView1.Rows)
            {
                TextBox_numericField = row.FindControl("TextBox_numericField") as TextBox;
                if (TextBox_numericField != null)
                {
                    break; // 找到就跳出
                }
            }

            for (int i = 60; i <= 70; i++)
            {
                TextBox_floatField.Text = i.ToString();
                TextBox_decimalField.Text = i.ToString();
                TextBox_realField.Text = i.ToString();
                TextBox_numericField.Text = i.ToString();

                DetailsView1.UpdateItem(true);
            }
        }

        protected void DetailsView1_ItemUpdating(object sender, DetailsViewUpdateEventArgs e)
        {
            string floatField = e.NewValues["floatField"].ToString().Trim();
            Int32.TryParse(floatField, out int floatFieldInt);
            e.NewValues["floatField"] = floatFieldInt / 100.0;

            string decimalField = e.NewValues["decimalField"].ToString().Trim();
            Int32.TryParse(decimalField, out int decimalFieldInt);
            e.NewValues["decimalField"] = decimalFieldInt / 100.0;

            string realField = e.NewValues["realField"].ToString().Trim();
            Int32.TryParse(realField, out int realFieldInt);
            e.NewValues["realField"] = realFieldInt / 100.0;

            string numericField = e.NewValues["numericField"].ToString().Trim();
            Int32.TryParse(numericField, out int numericFieldInt);
            e.NewValues["numericField"] = numericFieldInt / 100.0;
        }
    }
}

SSMS 中刪除資料表內容使用

TRUNCATE TABLE [MyDB].[dbo].[Table58];
DBCC CHECKIDENT ("Table58", RESEED, 1);

下圖,

測試數次,無法重現問題,還有非預期的因素影響了,可能先不管了,要找時間改 DB Schema 和 ASP.NET 程式。

(完)

相關

[研究]ASP.NET,WebForm,e.NewValues存入 DB 的 float 欄位後可能變了(一)

[研究]ASP.NET,WebForm,e.NewValues存入 DB 的 float 欄位後可能變了(一)

2025-04-28

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************

最近碰到一個況狀,一個小數值,e.NewValues 存入DB 的 float 欄位後,幾乎都正常,但遇到一個值居然變了的情況;在 Visual Studio 2019 中 Debug,追蹤 DetailsView1_ItemUpdating() 的 e.NewValues 值到最後,都是正常的,但DB更新結果的值卻不符;研究了一下。

********************************************************************************

ChatGPT 說:

這個問題最常見的原因是:

1. SQL Server的 float 型別本身是「近似值」(approximate numeric)

float 在 SQL Server 裡 不是精確數字,它是 IEEE 754 浮點格式,會有小數誤差。例如:

0.58 在 float 中,實際 binary 儲存時可能是類似 0.5799999xxx

然後如果你查詢時 SELECT ROUND(Rate1, 2),看到的是四捨五入後的值

但是如果系統(或者某些 ORM、自訂轉換)有先把 float 小數轉成文字或其他處理,就可能出現 0.57

簡單說:float 不適合存「需要準確小數」的資料,像利率、金額,都應該用 decimal(p,s)。

2. 你在 ASP.NET、ADO.NET 的轉型過程有細節誤差

如果你用的程式碼是這樣類型的:

float value = Convert.ToSingle(e.NewValues["Rate1"]);   

command.Parameters.AddWithValue("@Rate1", e.NewValues["Rate1"]);   

因為 e.NewValues 裡面的值其實是 object,很可能已經經過一輪型別轉換(例如從 TextBox 字串變 float),過程中又有誤差。

3. SQL Server 資料型態跟 .NET 送入時的小數精度不一致

float 預設在 SQL Server 會是 float(53),但如果你明確建表時用了 float(24) 這種低精度 float,問題會更嚴重。

float(24) 大概只有 7 位有效數字

float(53) 有 15~16 位有效數字

解決建議 
把 DB 欄位改成 **decimal(10,4)**(或其他適合的 p,s),保證 0.58 進去就是 0.5800

如果不能改 DB 結構,至少在 .NET 端明確用 decimal 處理,不要用 float

例如在後端這樣轉型:

decimal value = Convert.ToDecimal(e.NewValues["Rate1"]);
command.Parameters.Add("@Rate1", SqlDbType.Decimal).Value = value;   

並且資料表欄位是 decimal(10,4)。

********************************************************************************

未何 DB 中欄位定義是 float,但是 ASP.NET WebForm 產出的 <asp:Parameter Name="Rate1" Type="Double" /> 中是 double  ?

ChatGPT 說:

你的問題非常專業,來,我直接重點回答:

1. SQL Server 的 float 對應到 .NET 是 double

在 SQL Server 裡,float 是一種「近似數字」,但它沒有直接對應到 C# 裡的 float (C# 的 float 是 32-bit 喔)。

實際上:

SQL Server 的 float(53) (預設就是 53 位元的 float)→ 對應到 .NET C# 的 double(64-bit 浮點數)

SQL Server 的 real (低精度浮點)→ 才對應到 .NET C# 的 float(32-bit)

也就是說,SQL Server 的 float 預設就是高精度版本,所以 ASP.NET WebForm 在 Parameter 自動產生時,會設定成:

<asp:Parameter Name="Rate1" Type="Double" />

而不是 Type="Single"(Single 才是 .NET 的 float)

這是正確且預期的行為!

2. 微軟官方對應表(簡單版)

SQL Server 資料型態.NET 型態asp:Parameter Type
floatSystem.DoubleDouble
realSystem.SingleSingle
decimal / numericSystem.DecimalDecimal

3. 但是!精度問題還是存在

即使 .NET 這邊是 double,但因為 SQL Server 的 float 是近似值(approximate),小數點附近會有細微誤差,這就是為什麼你會遇到像 0.58 變成 0.57 這種情形。

********************************************************************************

SQL Server 那些資料型別 是「近似值」(approximate numeric)

ChatGPT 說:只有兩種:

資料型別說明
float浮點數,近似值,精度高(通常是 53 位元,對應 .NET 的 double)
real浮點數,近似值,但精度比 float 低(對應 .NET 的 float)

這兩個型別儲存的是「浮點表示」的數字,會有細微誤差,不是精確儲存小數位。

********************************************************************************

.NET Framework 裡,「近似值」(approximate numeric)的資料型別哪幾種

ChatGPT 說:只有兩種:

.NET 型別大小精度說明
float (System.Single)32 位元(4 bytes)大約 7 位十進位有效數字單精度浮點數(single-precision floating point)
double (System.Double)64 位元(8 bytes)大約 15~16 位十進位有效數字雙精度浮點數(double-precision floating point)

這兩種型別都是基於 IEEE 754 標準儲存方式,本質上是近似值,不是完全精確。

********************************************************************************

 .NET Framework 數值型別分類圖

數值型別
├── 精確值 (Exact Numeric)
│   ├── 整數型 (Integer Types)
│   │   ├── byte    (0 ~ 255)
│   │   ├── sbyte   (-128 ~ 127)
│   │   ├── short   (-32,768 ~ 32,767)
│   │   ├── ushort  (0 ~ 65,535)
│   │   ├── int     (-2^31 ~ 2^31-1)
│   │   ├── uint    (0 ~ 2^32-1)
│   │   ├── long    (-2^63 ~ 2^63-1)
│   │   └── ulong   (0 ~ 2^64-1)
│   └── 小數型 (Decimal Type)
│       └── decimal (28~29 位十進位有效數字,適合金額、財務運算)
│
└── 近似值 (Approximate Numeric)
    ├── 浮點型 (Floating Point Types)
    │   ├── float  (System.Single, 32-bit, 約7位有效數字)
    │   └── double (System.Double, 64-bit, 約15~16位有效數字)

********************************************************************************

如果需要儲存精確小數,SQL Server 欄位建議使用哪種資料型別,對應到 .NET Framework 是哪種型別 ?

ChatGPT 說:

SQL Server 儲存「精確小數」的最佳建議:

SQL Server 型別對應 .NET Framework 型別特性
decimal(p, s) 或 numeric(p, s)System.Decimal精確小數,絕對不失真,適合金額、比例、利率等數據

✅ decimal 跟 numeric 在 SQL Server 是完全等價的,只是名字不同,通常大家習慣用 decimal

SQL Server 型別 vs .NET 型別 完整對應表:

SQL Server 型別.NET 型別說明
decimal(p,s)System.Decimal高精度小數
numeric(p,s)System.Decimal高精度小數(跟 decimal 相同)

(其他型別像 float、real 對應到 double、float,但那是近似,不建議用。)

********************************************************************************

(完)

相關

2025年4月28日 星期一

[研究]ASP.NET,HtmlSanitizer.9.0.876 升級 HtmlSanitizer.9.0.884 測試

[研究]ASP.NET,HtmlSanitizer.9.0.876 升級 HtmlSanitizer.9.0.884 測試

2025-04-28

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

因為某專案把HtmlSanitizer.9.0.876 升級 HtmlSanitizer.9.0.884 後,編譯 (重建方案) 有警告,而且發布 (Deploy) 後,居然無法運作,建立全新方案測試看看。

********************************************************************************

【遇到的問題】

已開始重建...

1>------ 已開始全部重建: 專案: WebApplication1, 組態: Debug Any CPU ------

1>  請考慮將組件 "System.ValueTuple, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" 的 app.config 從版本 "4.0.3.0" [C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\System.ValueTuple.dll] 重新對應至版本 "4.0.5.0" [],以解決衝突並避免出現警告。

1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): warning MSB3247: 在同一個相依組件的不同版本之間發現衝突。請在 Visual Studio 中按兩下這個警告 (或選取後按 Enter) 解決這些衝突,或者將下列繫結重新導向加到應用程式組態檔中的 [執行階段] 節點: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.ValueTuple" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" /></dependentAssembly></assemblyBinding>

1>  WebApplication1 -> D:\WebSolution1\WebApplication1\WebApplication1\bin\WebApplication1.dll

2>------ 已開始全部重建: 專案: WebApplication1.Tests, 組態: Debug Any CPU ------

2>  請考慮將組件 "System.ValueTuple, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" 的 app.config 從版本 "4.0.3.0" [C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\System.ValueTuple.dll] 重新對應至版本 "4.0.5.0" [],以解決衝突並避免出現警告。

2>C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2203,5): warning MSB3247: 在同一個相依組件的不同版本之間發現衝突。請在 Visual Studio 中按兩下這個警告 (或選取後按 Enter) 解決這些衝突,或者將下列繫結重新導向加到應用程式組態檔中的 [執行階段] 節點: <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><dependentAssembly><assemblyIdentity name="System.ValueTuple" culture="neutral" publicKeyToken="cc7b13ffcd2ddd51" /><bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" /></dependentAssembly></assemblyBinding>

2>  WebApplication1.Tests -> D:\WebSolution1\WebApplication1\WebApplication1.Tests\bin\Debug\WebApplication1.Tests.dll

========== 全部重建: 2 成功、0 失敗、 0 略過 ==========

********************************************************************************

【全新專案,NuGet 安裝 HtmlSanitizer.9.0.876】

WebApplication1

正在安裝:

System.Buffers.4.5.1

System.Numerics.Vectors.4.5.0

System.Runtime.CompilerServices.Unsafe.6.0.0

System.Memory.4.5.5

System.Collections.Immutable.9.0.1

System.Text.Encoding.CodePages.6.0.0

AngleSharp.0.17.1

AngleSharp.Css.0.17.0

HtmlSanitizer.9.0.876


【編譯正常】

已開始重建...

1>------ 已開始全部重建: 專案: WebApplication1, 組態: Debug Any CPU ------

1>  WebApplication1 -> C:\WebSolution1\WebApplication1\WebApplication1\bin\WebApplication1.dll

========== 全部重建: 1 成功、0 失敗、 0 略過 ==========

********************************************************************************
【升級到 HtmlSanitizer.9.0.884】

WebApplication1

更新:

HtmlSanitizer.9.0.876 -> HtmlSanitizer.9.0.884

正在安裝:

System.ValueTuple.4.6.1

【編譯正常,沒有警告】

已開始重建...

1>------ 已開始全部重建: 專案: WebApplication1, 組態: Debug Any CPU ------

1>  WebApplication1 -> C:\WebSolution1\WebApplication1\WebApplication1\bin\WebApplication1.dll

========== 全部重建: 1 成功、0 失敗、 0 略過 ==========

********************************************************************************

也就是原來方案的 Web.config 或 app.config 要添加或修改 System.ValueTuple 的一些設定。

(完)

2025年4月21日 星期一

[研究]System.Data.Entity.Core.OptimisticConcurrencyException 處理並行衝突 (EF6)

[研究]System.Data.Entity.Core.OptimisticConcurrencyException 處理並行衝突 (EF6)

2025-04-21

環境:Visual Studio 2022 + ASP.NET + WebForm + Web Application + C# + SQL Server 2019 + SQL Server Management Studio (SSMS) 19

********************************************************************************



System.Data.Entity.Core.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). 
Entities may have been modified or deleted since entities were loaded. 
See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.


System.Data.Entity.Infrastructure.DbUpdateConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). 
Entities may have been modified or deleted since entities were loaded. 
See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions. 
---> System.Data.Entity.Core.OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). 
Entities may have been modified or deleted since entities were loaded. 
See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
   於 System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.ValidateRowsAffected(Int64 rowsAffected, UpdateCommand source)
   於 System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
   於 System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<>c.<Update>b__21_0(UpdateTranslator ut)
   於 System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func`2 updateFunction)
   於 System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update()
   於 System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__153_0()
   於 System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   於 System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
   於 System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass148_0.<SaveChangesInternal>b__0()
   於 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   於 System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
   於 System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options)
   於 System.Data.Entity.Internal.InternalContext.SaveChanges()
   --- 內部例外狀況堆疊追蹤的結尾 ---
   於 System.Data.Entity.Internal.InternalContext.SaveChanges()
   於 System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   於 System.Data.Entity.DbContext.SaveChanges()
   於 System.Web.Providers.DefaultSessionStateProvider.ReleaseItemExclusive(HttpContext context, String id, Object lockId)
   於 System.Web.SessionState.SessionStateModule.OnReleaseState(Object source, EventArgs eventArgs)
   於 System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   於 System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   於 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)


********************************************************************************

處理並行衝突 (EF6)
http://go.microsoft.com/fwlink/?LinkId=472540
https://learn.microsoft.com/zh-tw/ef/ef6/saving/concurrency?redirectedfrom=MSDN
Handling Concurrency Conflicts (EF6)
https://learn.microsoft.com/en-us/ef/ef6/saving/concurrency?redirectedfrom=MSDN

OptimisticConcurrencyException 類別
https://learn.microsoft.com/zh-tw/dotnet/api/system.data.optimisticconcurrencyexception?view=netframework-4.8.1
發生開放式同步存取違規時擲回的例外狀況。

https://learn.microsoft.com/en-us/dotnet/api/system.data.optimisticconcurrencyexception?view=netframework-4.8.1
The exception that is thrown when an optimistic concurrency violation occurs.

********************************************************************************

(完)

相關





2025年4月18日 星期五

[研究] Ubuntu 25.04 (非LTS) Desktop Linux 安裝

[研究] Ubuntu 25.04 (非LTS) Desktop Linux 安裝

2025-04-18

官方網站

https://www.ubuntu-tw.org/

https://releases.ubuntu.com/25.04

24.04 是 LTS 版,但 24.10 不是。25.04 於2025-04-17釋出,也不是 LTS。

Click 圖片可以看100%原尺寸圖,安裝不難,只是留個紀錄。






















































https://help.ubuntu.com/



(完)

相關

[研究] Ubuntu 25.04 (非LTS) Desktop Linux 安裝
https://shaurong.blogspot.com/2025/04/ubuntu-2504-lts-desktop-linux.html

[研究] Ubuntu 24.10 (非LTS) Desktop Linux 安裝
https://shaurong.blogspot.com/2024/10/ubuntu-2410-lts-desktop-linux.html

[研究] Ubuntu 24.04 LTS Desktop Linux 安裝
https://shaurong.blogspot.com/2024/04/ubuntu-2404-lts-desktop-linux.html

[研究] Ubuntu 23.10 (非LTS) Desktop Linux 安裝
https://shaurong.blogspot.com/2023/11/ubuntu-2310-lts-desktop-linux.html

[研究] Ubuntu 23.04 (非LTS) Desktop Linux 安裝
http://shaurong.blogspot.com/2023/04/ubuntu-2304-lts-desktop-linux.html

[研究] Ubuntu 22.10 Desktop Linux 安裝
https://shaurong.blogspot.com/2022/10/ubuntu-2210-desktop-linux.html

[研究] Ubuntu 18.04 Desktop x64 LTS 安裝 VMware Tools-10.2.5-8068393.tar.gz
https://shaurong.blogspot.com/2018/05/ubuntu-1804-desktop-x64-lts-vmware.html

[研究] Ubuntu 22.04 LTS Desktop Linux 安裝
https://shaurong.blogspot.com/2022/05/ubuntu-2210-lts-desktop-linux.html

[研究] Ubuntu 21.10 Desktop Linux 安裝
https://shaurong.blogspot.com/2021/10/ubuntu-2110-desktop-linux.html

[研究] Ubuntu 21.04 Live Server Linux 安裝
https://shaurong.blogspot.com/2021/07/ubuntu-2104-live-server-linux.html

Index of /ubuntu-releases/
https://ftp.ubuntu-tw.org/ubuntu-releases/

Ubuntu release cycle | Ubuntu
https://ubuntu.com/about/release-cycle

BionicBeaver/ReleaseSchedule - Ubuntu Wiki
https://wiki.ubuntu.com/BionicBeaver/ReleaseSchedule

Releases - Ubuntu Wiki
https://wiki.ubuntu.com/Releases