Программно создать оператор DDL для пользовательского типа данных (UDDT) - PullRequest
2 голосов
/ 22 октября 2019

Я пытаюсь добавить поддельные синонимы, указывающие на поддержку удаленных объектов ( PR ) для tSQLt .

Чтобы сделать возможным макетирование / подделку таблиц, которые имеют определенные пользователем типы систем в определениях таблиц, мне нужно сгенерировать оператор DDL пользовательского типа данных (UDDT).

Я неУ меня слишком большой опыт работы с UDDT, и что я могу придумать об очень простом сценарии, если UDDT просто так прост, если это будет что-то вроде CREATE TYPE dbo.SomeType FROM INT, но я знаю, что он может быть гораздо более сложным.

Итак, вопрос в том, есть ли у кого-нибудь уже работающее решение, в идеале реализованное с использованием T-SQL через системные объекты. В худшем случае SQLCLR будет единственным другим вариантом.

Ответы [ 2 ]

3 голосов
/ 22 октября 2019

Существуют различные типы пользовательских типов: пользовательские таблицы (UDTT), пользовательские типы (UDT; сложные типы, реализованные с помощью SQLCLR) и пользовательские типы данных (UDDT; главным образом, синонимы существующей системы). типов, но с учетом размера / точности и NULL / NOT NULL).

Вам не нужно беспокоиться о UDTT, поскольку они не могут быть столбцами в таблицах.

Возможно, вы можетеНе работайте с UDT, по крайней мере, сейчас, так как это добавляет много сложности, так как вам также необходимо скопировать сборку.

Существует один основной вид системного каталога: sys.types. Следующее должно дать вам большинство, если не все, что вам нужно. collation_name, по-видимому, не годится для использования ни при тестировании простого CREATE TYPE в качестве теста, ни в документации.

SELECT N'CREATE TYPE ' + QUOTENAME(sch.[name])
         + N'.' + QUOTENAME(typ.[name])
         + N' FROM ' + styp.[name]
         + CASE
             WHEN typ.[system_type_id] IN
                       (41, 42, 43, 106, 108, 165, 167, 173, 175, 231, 239)
               THEN N'('
                    + CASE
                        WHEN typ.[max_length] = -1 -- for: VARCHAR, NVARCHAR, VARBINARY
                          THEN N'MAX'
                        WHEN typ.[system_type_id] IN (165, 167, 173, 175)
                          -- VARBINARY, VARCHAR, BINARY, CHAR
                          THEN CONVERT(NVARCHAR(5), typ.[max_length])
                        WHEN typ.[system_type_id] IN (231, 239) -- NVARCHAR, NCHAR
                          THEN CONVERT(NVARCHAR(5), (typ.[max_length] / 2))
                        WHEN typ.[system_type_id] IN (41, 42, 43)
                          -- TIME, DATETIME2, DATETIMEOFFSET
                          THEN CONVERT(NVARCHAR(5), typ.[scale])
                        WHEN typ.[system_type_id] IN (106, 108) -- DECIMAL, NUMERIC
                          THEN CONVERT(NVARCHAR(5), typ.[precision]) 
                               + N', ' + CONVERT(NVARCHAR(5), typ.[scale])
                        END            
                    + N')'
             ELSE N''
           END
         + CASE typ.[is_nullable] WHEN 1 THEN N' NULL' ELSE ' NOT NULL' END
         + N';'
FROM   sys.types typ
INNER JOIN sys.schemas sch
        ON sch.[schema_id] = typ.[schema_id]
INNER JOIN sys.types styp
        ON styp.[user_type_id] = typ.[system_type_id]
WHERE  typ.[is_user_defined] = 1
AND    typ.[is_assembly_type] = 0
AND    typ.[is_table_type] = 0;

Правила

!! Они давно устарели и не должны использоваться !!

Документация для CREATE RULE

Правила можно найти в: sys.sql_modules(который включает в себя оператор CREATE в поле [definition])

Вам необходимо будет отдельно циклически проходить по sys.types и, для любых пользовательских типов, где rule_object_id <> 0, выполнить EXEC sp_bindrule N'@rulename', N'@objectname';.

По умолчанию

!! Они давно устарели и не должны использоваться !!

Документация для CREATE DEFAULT

Значения по умолчанию можно найти в: sys.sql_modules(который включает в себя оператор CREATE в поле [definition])

Вам необходимо будет отдельно циклически проходить по sys.types и, для любых пользовательских типов, где default_object_id <> 0, выполнить EXEC sp_bindefault N'@defaultname', N'@objectname';.

2 голосов
/ 22 октября 2019

Трудно что-то написать после Соломона , потому что он обычно отвечал на все лучше, но давайте попробуем другой подход, используя SMO .

Чтобы создать сценарий T-SQL для всех пользовательских типов в базе данных AdventureWorks2016, мы можем использовать следующий фрагмент.

    // get all user defined data types 
    var userDt = db.UserDefinedDataTypes;

    var result = new StringBuilder();
    foreach (UserDefinedDataType t in userDt)
    {
        ConsoleEx.WriteLine($"{t.Schema}{'.'}{t.Name}", ConsoleColor.Red);
        var helper = t.Script(MakeOptions());
        foreach (var h in helper)
        {
            result.AppendLine(h);    
        }
        result.AppendLine();
    }

    var fileName = $"{db.Name}_UDDT_{DateTime.Now:yyyy_mm_dd_HH_mm_ss}.txt";
    if (File.Exists(fileName))
        File.Delete(fileName);
    File.WriteAllText(fileName, result.ToString());
    // start notepad and disply the configuration
    Process.Start(fileName);

.. и мы получим результат, как показано во фрагменте ниже.

/****** Object:  UserDefinedDataType [dbo].[AccountNumber]    Script Date: 22.10.2019. 9:47:03 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'AccountNumber' AND ss.name = N'dbo')
CREATE TYPE [dbo].[AccountNumber] FROM [nvarchar](15) NULL

/****** Object:  UserDefinedDataType [dbo].[AccountNumber2]    Script Date: 22.10.2019. 9:47:03 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'AccountNumber2' AND ss.name = N'dbo')
CREATE TYPE [dbo].[AccountNumber2] FROM [nvarchar](15) NOT NULL

/****** Object:  UserDefinedDataType [dbo].[Flag]    Script Date: 22.10.2019. 9:47:03 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'Flag' AND ss.name = N'dbo')
CREATE TYPE [dbo].[Flag] FROM [bit] NOT NULL

/****** Object:  UserDefinedDataType [dbo].[Name]    Script Date: 22.10.2019. 9:47:03 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'Name' AND ss.name = N'dbo')
CREATE TYPE [dbo].[Name] FROM [nvarchar](50) NULL

/****** Object:  UserDefinedDataType [dbo].[NameStyle]    Script Date: 22.10.2019. 9:47:04 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'NameStyle' AND ss.name = N'dbo')
CREATE TYPE [dbo].[NameStyle] FROM [bit] NOT NULL

/****** Object:  UserDefinedDataType [dbo].[OrderNumber]    Script Date: 22.10.2019. 9:47:04 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'OrderNumber' AND ss.name = N'dbo')
CREATE TYPE [dbo].[OrderNumber] FROM [nvarchar](25) NULL

/****** Object:  UserDefinedDataType [dbo].[Phone]    Script Date: 22.10.2019. 9:47:04 ******/
IF NOT EXISTS (SELECT * FROM sys.types st JOIN sys.schemas ss ON st.schema_id = ss.schema_id WHERE st.name = N'Phone' AND ss.name = N'dbo')
CREATE TYPE [dbo].[Phone] FROM [nvarchar](25) NULL

Узнайте больше о SMO - ознакомьтесь Программирование SQL Server с помощью инфраструктуры объектов управления SQL Server

Пример этого ответа можно найти на GitHub ListAllUserDefinedDataTypes

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...