根据其他 table 的内容创建 table

Create tables based on contents of other table

我有一个 table,其中包含要创建的 table 的名称以及 table 应该具有的列:

CREATE TABLE Tables2Create (
table_name nvarchar(256)
,colum_names nvarchar(max)
)
INSERT INTO Tables2Create VALUES ('People','Name|Occupation|Hobby')
INSERT INTO Tables2Create VALUES ('Schools','Name|Place|Type ')

现在我需要一些 TSQL 可以为字段 table_names 中的每个 table 动态创建 tables 并且拆分字段 column_names 来决定哪些列每个 table 应该有。所有字段都可以是nvarchar的。

CREATE TABLE People (
Name nvarchar(256)
,Occupation nvarchar(256)
,Hobby nvarchar(256)
)

知道怎么做吗?

下面是使用 STRING_SPLIT 提取列名并使用 STRING_AGG 连接列名和 CREATE TABLE 语句的示例。

DECLARE @SQL nvarchar(MAX);
SELECT @SQL = STRING_AGG(CreateTableStatement, '')
FROM (
    SELECT 
        'CREATE TABLE ' + QUOTENAME(table_name) + N' (' + 
        (
            SELECT STRING_AGG(QUOTENAME(value) + ' nvarchar(256)',',')
            FROM STRING_SPLIT(column_names,'|')
        )
        + N');'
    FROM dbo.Tables2Create
) AS CreateTableStatements(CreateTableStatement)

EXEC(@SQL);

你能做到吗?是的你可以。你应该?老实说,可能不会。正如我在评论中提到的那样,存储分隔数据始终是一个设计缺陷;至少规范你的设计。

话虽这么说,我在这里使用的方法是“一体化”解决方案;没有游标,没有迭代。正如您已标记 SQL Server 2019,这意味着我们可以使用 STRING_AGG。这给出了这样的东西:

USE master;
GO

CREATE DATABASE TestDB;
GO

USE TestDB;
GO

CREATE TABLE Tables2Create (table_name sysname, --correct data type for object names
                            column_names nvarchar(max)
)
INSERT INTO Tables2Create VALUES (N'People',N'Name|Occupation|Hobby')
INSERT INTO Tables2Create VALUES (N'Schools',N'Name|Place|Type ');
GO

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

DECLARE @Delim nvarchar(10) = N',' + @CRLF + N'    '

SET @SQL = (SELECT STRING_AGG(S.SQL,'')
            FROM(SELECT @CRLF + @CRLF +
                        N'CREATE TABLE dbo.' + QUOTENAME(T2C.table_name) + N' (' + @CRLF + N'    ' +
                        STRING_AGG(QUOTENAME(SS.value) +  N' nvarchar(256)',@Delim) WITHIN GROUP (ORDER BY SS.[Value]) + @CRLF + N');' AS SQL
                 FROM dbo.Tables2Create T2C
                      CROSS APPLY STRING_SPLIT(T2C.column_names,N'|') SS
                 GROUP BY T2C.table_name) S);

PRINT @SQL; --Your best friend

EXEC sys.sp_executesql @SQL;
GO

USE master;
GO

DROP DATABASE TestDB;

db<>fiddle