SQL Server 是否支持自定義域?
PostgreSQL 支持
DOMAIN
規範,來自 SQL 2011 工作草案規範,域是一個命名的使用者定義對象,在可以指定數據類型的某些地方,可以將其指定為數據類型的替代。域由數據類型、可能的預設選項和零個或多個(域)約束組成。
這使我們能夠做一些非常酷的事情,例如通過不區分大小寫的文本類型為電子郵件實現 HTML5 規範的域。它確保所有訪問數據庫的客戶端都對插入的數據進行完整性檢查。
CREATE DOMAIN email AS citext CHECK ( value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$' );
SQL Server 是否支持觸發器系統之外的任何此類功能?
SQLCLR 為創建完全自定義的數據類型提供了一個表面區域。事實上,這就是 SQL Server 支持幾何和層次數據類型的方式。
由於 SQLCLR 基於 Microsoft.Net 通用中間語言,因此 SQLCLR 數據類型可能有多種約束。例如,您可以通過在 DNS 中查詢 MX 記錄作為數據驗證程式碼的一部分,輕鬆確保電子郵件地址來自有效域。
只要
IsByteOrdered:=True
設置了,SQL Server 就可以索引 CLR UDT。有很多這樣的屬性,您可以更改它們以影響 SQL Server 如何使用 UDT。對於索引所需的相等匹配,SQL Server 只查看儲存在頁面中的二進制值,即它根本不需要查看 UDT 程式碼。作為檢查域空間有效性的 SQLCLR 使用者定義類型的範例,我編寫了以下可怕的概念驗證 VB.Net 程式碼:
Imports System Imports System.Data Imports System.Data.SqlClient Imports System.Data.SqlTypes Imports Microsoft.SqlServer.Server <Serializable()> _ <Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, IsByteOrdered:=True, MaxByteSize:=320, ValidationMethodName:="ValidateEmailAddress")> _ Public Structure EmailType Implements INullable Implements IBinarySerialize Private m_Null As Boolean Private m_EmailAddress As String Public Function ValidateEmailAddress() As Boolean 'is the email address valid? If Me.IsValidDomain Then Return True Else Return False End If End Function Public Overrides Function ToString() As String Return Me.m_EmailAddress End Function Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull Get ' Put your code here If Me.m_EmailAddress Is Nothing Then Me.m_Null = True Else Me.m_Null = False End If Return m_Null End Get End Property Public Shared ReadOnly Property Null As EmailType Get Dim h As New EmailType h.m_Null = True Return h End Get End Property 'called when SQL Server passes in a SqlString value to the UDT Public Shared Function Parse(ByVal s As SqlString) As EmailType If s.IsNull Then Return Null End If Dim u As New EmailType u.m_EmailAddress = CType(s, String) If u.ValidateEmailAddress = False Then Throw New Exception("Invalid Email Address") End If Return u End Function Public Function IsValidDomain() As Boolean Dim iAtSign As Int32 = Microsoft.VisualBasic.Strings.InStr(Me.m_EmailAddress, "@") Dim iDomainLength As Int32 = Microsoft.VisualBasic.Strings.Len(Me.m_EmailAddress) - iAtSign Dim sDomain As String = Microsoft.VisualBasic.Strings.Right(Me.m_EmailAddress, iDomainLength) Dim bResolvable As Boolean = False Try Dim ip As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(sDomain) bResolvable = True Catch ex As Exception Throw New Exception(Me.m_EmailAddress & " is not from a resolvable domain.") End Try Return bResolvable End Function ' save the value to the database Public Sub Write(w As System.IO.BinaryWriter) Implements IBinarySerialize.Write w.Write(Me.m_EmailAddress) End Sub ' retrieve the value from the database Public Sub Read(r As System.IO.BinaryReader) Implements IBinarySerialize.Read Dim sTemp As String = r.ReadString Dim sTemp1 As String = "" For Each n As Char In sTemp.ToCharArray sTemp1 = sTemp1 & n.ToString Next Me.m_EmailAddress = sTemp End Sub End Structure
由於上面的程式碼沒有簽名,你應該只在可以啟用
TRUSTWORTHY
數據庫設置的開發機器上測試它。編譯程式碼後,您可以通過以下方式將其導入 SQL Server:CREATE ASSEMBLY SQLCLREmailType AUTHORIZATION dbo FROM 'C:\Path\Goes\Here\SQLCLREmailType.dll' WITH PERMISSION_SET = UNSAFE; CREATE TYPE EmailType EXTERNAL NAME SQLCLREmailType.[SQLCLREmailType.EmailType]
然後可以像這樣使用 UDT:
DECLARE @t TABLE ( col EmailType NOT NULL ); INSERT INTO @t (col) VALUES ('mvernon@mvct.com') , ('us@them.com'); SELECT CONVERT(varchar(50), t.col) FROM @t t GO
上面的程式碼返回:
+------------------+ | (無列名) | +------------------+ | mvernon@mvct.com | | us@them.com | +------------------+
但是,當嘗試插入屬於不存在的電子郵件域的地址時,如下所示:
DECLARE @t TABLE ( col EmailType NOT NULL ); INSERT INTO @t (col) VALUES , ('us@asdfasdfasdfasdfasdfasdfasdfasdf90097809878907098908908908908.com'); SELECT CONVERT(varchar(50), t.col) FROM @t t GO
您會看到一個錯誤:
消息 6522,級別 16,狀態 2,第 27
行在執行使用者定義的常式或聚合“EmailType”期間發生 .NET Framework 錯誤:
System.Exception:us@asdfasdfasdfasdfasdfasdfasdfasdf90097809878907098908908908908.com 不是來自可解析的域。
System.Exception:
在 SQLCLREmailType.EmailType.IsValidDomain()
在 SQLCLREmailType.EmailType.ValidateEmailAddress()
在 SQLCLREmailType.EmailType.Parse(SqlString s)