
ご存知のように、MSSQL
は列挙を作成/使用する機能を
提供していません 。これは、暗黙的で信頼性が低く、く、複雑にサポートされるコードを必要とすることがよくあります。 リレーショナルデータベースの転送自体には場所を持たないことができると主張することができますが、私の練習では(そして私の練習だけでなく)多くの場合、これらの行が生まれました:
select * from Process where ProcessType = 1
または
declare @processSuspended int = 1; select * from Process where ProcessType = @processSuspended;
難易度の異なる同様の松葉杖。
そして、私はしたい-
SELECT * FROM Process WHERE ProcessType = EnumProcess.Suspended;
一般に、解決策は知られています-CLR型を作成します。 しかし、アセンブリを作成し、公開し、その関連性を常に管理したい人はいますか?
この記事の目的- この人目を引く構文にできるだけ近くなる
- 自動的に転送を作成します
免責事項 :さらにすべては、Visual Studio 2012、MS SQL Server 2012 SP1、.Net Framework 3.5を使用して短時間で作成されたものであり、その方法の一例にすぎません。
言葉なしでやってみよう
(UPD:
1つのスクリプトですべて一緒に)
1.アセンブリをインポートします(記事の最後-ソースコードへのリンク)、(ALTER DATABASE SET TRUSTWORTHY ONを忘れないでください)
CREATE ASSEMBLY SQLAutoEnums ... CREATE ASSEMBLY [SQLAutoEnums] FROM WITH PERMISSION_SET = UNSAFE GO CREATE FUNCTION [dbo].[SqlAutoEnums.EnumMembers_Current](@enumName [nvarchar](4000)) RETURNS TABLE ( [ID] [int] NULL, [Name] [nvarchar](4000) NULL ) WITH EXECUTE AS N'dbo' AS EXTERNAL NAME [SQLAutoEnums].[UserDefinedFunctions].[EnumMembersCurrent] GO CREATE FUNCTION [dbo].[SqlAutoEnumsCompile](@code [nvarchar](max)) RETURNS [varbinary](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLAutoEnums].[UserDefinedFunctions].[SqlAutoEnumsCompile] GO CREATE FUNCTION [dbo].[SqlAutoEnumsGenerate](@tableName [nvarchar](4000), @columnPrefix [nvarchar](4000), @columnName [nvarchar](4000), @columnMember [nvarchar](4000), @columnValue [nvarchar](4000)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLAutoEnums].[UserDefinedFunctions].[SqlAutoEnumsGenerate] GO CREATE FUNCTION [dbo].[SqlAutoEnumsTryCompile](@code [nvarchar](max)) RETURNS [nvarchar](max) WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLAutoEnums].[UserDefinedFunctions].[SqlAutoEnumsTryCompile] GO
2.テストテーブルSqlAutoEnums.Dataを作成します。このテーブルには、列挙の説明とそれを表示するビューがあります(後で、構造を維持しながら、列挙が格納されている別のテーブルにリダイレクトできます。その後、SqlAutoEnums.Dataテーブルは不要です)。
CREATE TABLE dbo。[SqlAutoEnums.Data] ... CREATE TABLE [dbo].[SqlAutoEnums.Data]( [ID] [int] IDENTITY(1,1) NOT NULL, [Prefix] [nvarchar](50) NOT NULL, [Name] [nvarchar](50) NOT NULL, [MemberName] [nvarchar](50) NOT NULL, [MemberValue] [int] NOT NULL, CONSTRAINT [PK_SqlAutoEnums.Data] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO CREATE UNIQUE NONCLUSTERED INDEX [IX_SqlAutoEnums.Data] ON [dbo].[SqlAutoEnums.Data] ( [Prefix] ASC, [Name] ASC, [MemberName] ASC, [MemberValue] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO CREATE UNIQUE NONCLUSTERED INDEX [IX_SqlAutoEnums.Data.A] ON [dbo].[SqlAutoEnums.Data] ( [Name] ASC, [MemberValue] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO CREATE VIEW [dbo].[SqlAutoEnums.Data.View] AS SELECT ID , Prefix , Name , MemberName , MemberValue FROM dbo.[SqlAutoEnums.Data]
3.多数の実用的および補助的な機能:
関数の作成... CREATE FUNCTION [dbo].[SqlAutoEnums.Enum_Equals] ( @enumName NVARCHAR(100) ) RETURNS bit AS BEGIN DECLARE @res BIT = 0; SET @res = CASE WHEN EXISTS ( SELECT Name AS MemberName, ID AS MemberValue FROM dbo.[SqlAutoEnums.EnumMembers_Current](@enumName) except select MemberName, MemberValue FROM dbo.[SqlAutoEnums.EnumMembers_New](@enumName) ) OR EXISTS ( SELECT MemberName, MemberValue FROM dbo.[SqlAutoEnums.EnumMembers_New](@enumName) EXCEPT SELECT Name AS MemberName, ID AS MemberValue FROM dbo.[SqlAutoEnums.EnumMembers_Current](@enumName) ) THEN 0 ELSE 1 END; RETURN @res; END GO
4.転送を作成/更新する手順を作成します
CREATE PROCEDURE dbo。[SqlAutoEnums.Renew] ... CREATE PROCEDURE [dbo].[SqlAutoEnums.Renew] WITH EXECUTE AS SELF AS BEGIN DECLARE @msg NVARCHAR(MAX); BEGIN TRY BEGIN TRAN
4.転送を自動的に更新するためにテーブルにトリガーを掛けます
CREATE TRIGGER dbo。[SqlAutoEnums.Renew.Trigger] ... CREATE TRIGGER dbo.[SqlAutoEnums.Renew.Trigger] ON [dbo].[SqlAutoEnums.Data] AFTER INSERT, DELETE, UPDATE AS BEGIN EXEC dbo.[SqlAutoEnums.Renew]; END
今それをどうしますか?
テストリストを生成します
INSERT INTO dbo。[SqlAutoEnums.Data] ... INSERT INTO dbo.[SqlAutoEnums.Data] (Prefix, Name, MemberName, MemberValue) VALUES ('Enum', 'Lolly', 'C', 14 ), ('Enum', 'Lolly', 'A', 1 ), ('Enum', 'Lolly', 'B', 2 ), ('Enum', 'Process', 'Running', 1 ), ('Enum', 'Process', 'Suspended', 2 ), ('Enum', 'Process', 'Terminated', 3 )
私たちが今持っているものを見てみましょう:
内部について少し
SqlAutoEnumsアセンブリは、実際には、SqlAutoEnums.Generatedを生成および登録しています*列挙が配置されているテーブル内のデータからのアセンブリ。 CLR Hosted
Enviroment (
tynt 、
tynt )の制限により、不器用なstring.Formatを生成し、
パスEnvironment.GetEnvironmentVariable( "windir")+ "\\ Microsoft.NET \\ Framework \\ v3.5に沿ってcsc.exeを呼び出してコンパイルします。
\\ csc.exe "(使用している.NETのバージョンの
.NET 3.5インストールパス
がサーバーにインストールされていることを確認してください
。Environment.GetEnvironmentVariable (" TEMP ")へのアクセスがあることを確認してください)。 いつの日か、私たちは不器用なものを交換します。
SQLServerはenumを認識せず、認識もしないため、列挙メンバーの名前によるフィールドを持つ構造が形成されます。
public enum FooEnum{A = 1, B = 2} public struct MyFooEnum { public MyFooEnum(FooEnum value) { _value = value; } public static MyFooEnum A { get { return new MyFooEnum(FooEnum.A);} } public static MyFooEnum B { get { return new MyFooEnum(FooEnum.B);} } private FooEnum _value; }
まだ多くの技術的なラッピングがあります(たとえば、
ここ 、MSDN、Googleなど、CLR型の作成に関する詳細を読むことができます...
作業で列挙型(テーブルのフィールドと計算フィールド、プロシージャ/関数のパラメーターなど)を使用するとすぐに、他のユーザーデータタイプと同様に変更されることを覚えておく必要があります(ALTER TYPEがないため-DROPが行われます) 、CREATE)または削除できない場合、最初にすべてのリンクを削除する必要があります。 ただし、型がプロシージャ/関数のコード内でのみ使用されている場合は可能ですが、列挙またはその一部がない場合、プロシージャ/関数は例外で失敗する可能性があります。
したがって、新しいアセンブリを生成すると、依存関係のないすべての列挙がそのアセンブリに転送されます。「古い」アセンブリには、変更する必要がなく、依存関係がある列挙が残ります。
SqlAutoEnums.dllの約束された
アセンブリソースご清聴ありがとうございました。誰かが上記の恩恵を受けるか、より高度なオプションを思い付くと思います。