循环 table 共 table 秒以动态创建 table 结构
Loop through table of tables to dynamically CREATE table structures
我有一个元数据 table,它有四列 Table_N、Column_N、DType 和 DLength,我正在尝试遍历元数据 table 并针对每个列distinct table dynamiaclly spit CREATE TABLE 语句及其所有列、数据类型和数据长度。基本上是典型的 table 结构或定义。
到目前为止,我已经添加了一个游标来循环遍历它们,并使用动态 SQL 语法遇到了障碍,特别是处理 DLength 字段的某些列的值的 NULL 值。例如,如果列的数据类型是 DATE,那么该列的 Dlength 值将为 NULL。如果我连接一个包含 DType 的 VARCHAR 和 DLength 的 100 的列,那么 '@DT' + '(' + @DL+ ')' 会结果为 VARCHAR(100),但对于 DATE、INT 或任何类似的数据类型,我需要一种不同的方法。另外,不是 cursor 的忠实粉丝,所以如果你对此有完全不同的方法,请随时提出建议。非常感谢任何建议。谢谢!
Table 名称:DDC_Loop(下面的示例带有 2 tables 元数据)
Table_N Column_N DType DLength
--------------------------------------------------------
AUT_C_TABLOG ORIGINAL VARCHAR 1
AUT_C_TABLOG PROTOCOL VARCHAR 1
AUT_C_TABLOG TABNAME VARCHAR 30
ANLA GEGST VARCHAR 8
ANLA GPLAB DATE NULL
ANLA GRBLT VARCHAR 5
ANLA GRBND VARCHAR 5
ANLA KTOGR VARCHAR 8
ANLA LAND1 VARCHAR 3
ANLA MENGE NUMERIC 16,3
使用常见的 table 表达式、lag、lead、几个 case 表达式和 xml 路径,您可以 return 为整个创建 table 语句table 的内容作为一个长字符串。
首先,创建并填充示例 table(请在您以后的问题中省去这一步)
CREATE TABLE Tables
(
Table_N sysname,
Column_N sysname,
DType sysname,
DLength varchar(5)
);
INSERT INTO Tables (Table_N, Column_N, DType, DLength) VALUES
('AUT_C_TABLOG', 'ORIGINAL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'PROTOCOL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'TABNAME', 'VARCHAR', '30'),
('ANLA', 'GEGST', 'VARCHAR', '8'),
('ANLA', 'GPLAB', 'DATE', NULL),
('ANLA', 'GRBLT', 'VARCHAR', '5'),
('ANLA', 'GRBND', 'VARCHAR', '5'),
('ANLA', 'KTOGR', 'VARCHAR', '8'),
('ANLA', 'LAND1', 'VARCHAR', '3'),
('ANLA', 'MENGE', 'NUMERIC', '16,3');
然后,使用 cte 获取滞后和引导 table 名称(这样您就会知道何时添加添加创建 table 以及何时不添加):
WITH CTE AS
(
SELECT Table_N,
Column_N,
DType,
DLength,
LAG(Table_N) OVER(ORDER BY Table_N) AS PrevTableName,
LEAD(Table_N) OVER(ORDER BY Table_N) AS NextTableName
FROM Tables
)
现在,在查询中使用几个 case 表达式:
SELECT CASE WHEN PrevTableName IS NULL OR Table_N <> PrevTableName
THEN 'CREATE TABLE '+ Table_N +' ('
ELSE ''
END + Column_N +' '+ DType +
CASE WHEN DLength IS NULL
THEN ''
ELSE '('+ DLength +')'
END +
CASE WHEN NextTableName IS NULL OR Table_N <> NextTableName
THEN '); '
ELSE ', '
END
FROM CTE
ORDER BY Table_N, Column_N -- Don't forget this order by, it's important!
FOR XML PATH('')
结果:
CREATE TABLE ANLA (GEGST VARCHAR(8), GPLAB DATE, GRBLT VARCHAR(5), GRBND VARCHAR(5), KTOGR VARCHAR(8), LAND1 VARCHAR(3), MENGE NUMERIC(16,3));
CREATE TABLE AUT_C_TABLOG (ORIGINAL VARCHAR(1), PROTOCOL VARCHAR(1), TABNAME VARCHAR(30));
您可以尝试生成动态语句并执行该语句。这里需要的是为每个不同的 table 名称编号行,然后,当行号为 1 时,包括 CREATE TABLE
部分 SQL 语句。
-- Table
CREATE TABLE #DDC_Loop (
Table_N nvarchar(100),
Column_N nvarchar(100),
DType nvarchar(100),
DLength nvarchar(100)
)
INSERT INTO #DDC_Loop
(Table_N, Column_N, DType, DLength)
VALUES
('AUT_C_TABLOG', 'ORIGINAL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'PROTOCOL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'TABNAME', 'VARCHAR', '30'),
('ANLA', 'GEGST', 'VARCHAR', '8'),
('ANLA', 'GPLAB', 'DATE', NULL),
('ANLA', 'GRBLT', 'VARCHAR', '5'),
('ANLA', 'GRBND', 'VARCHAR', '5'),
('ANLA', 'KTOGR', 'VARCHAR', '8'),
('ANLA', 'LAND1', 'VARCHAR', '3'),
('ANLA', 'MENGE', 'NUMERIC', '16,3')
-- Dynamci statement
DECLARE @stm nvarchar(max)
SET @stm = N''
;WITH cte AS (
SELECT
Table_N,
Column_N,
DType,
DLength,
ROW_NUMBER() OVER (PARTITION BY Table_N ORDER BY Table_N) RN,
CASE
WHEN DLength IS NULL THEN N', ' + Column_N + N' ' + DType
ELSE N', ' + Column_N + N' ' + DType + N'(' + DLength + N')'
END ColumnDefinition
FROM #DDC_Loop
)
SELECT
@stm = @stm +
CASE
WHEN RN = 1 THEN N'); CREATE TABLE ' + Table_N + N'(' + STUFF(ColumnDefinition, 1, 2, N'')
ELSE ColumnDefinition
END
FROM cte
ORDER BY Table_N, RN
SET @stm = STUFF(@stm, 1, 3, N'') + SUBSTRING(@stm, 1, 3)
-- Print and execute statement
PRINT @stm
EXEC (@stm)
生成的语句:
CREATE TABLE ANLA(GEGST VARCHAR(8), GPLAB DATE, GRBLT VARCHAR(5), GRBND VARCHAR(5), KTOGR VARCHAR(8), LAND1 VARCHAR(3), MENGE NUMERIC(16,3));
CREATE TABLE AUT_C_TABLOG(ORIGINAL VARCHAR(1), PROTOCOL VARCHAR(1), TABNAME VARCHAR(30));
我有一个元数据 table,它有四列 Table_N、Column_N、DType 和 DLength,我正在尝试遍历元数据 table 并针对每个列distinct table dynamiaclly spit CREATE TABLE 语句及其所有列、数据类型和数据长度。基本上是典型的 table 结构或定义。
到目前为止,我已经添加了一个游标来循环遍历它们,并使用动态 SQL 语法遇到了障碍,特别是处理 DLength 字段的某些列的值的 NULL 值。例如,如果列的数据类型是 DATE,那么该列的 Dlength 值将为 NULL。如果我连接一个包含 DType 的 VARCHAR 和 DLength 的 100 的列,那么 '@DT' + '(' + @DL+ ')' 会结果为 VARCHAR(100),但对于 DATE、INT 或任何类似的数据类型,我需要一种不同的方法。另外,不是 cursor 的忠实粉丝,所以如果你对此有完全不同的方法,请随时提出建议。非常感谢任何建议。谢谢!
Table 名称:DDC_Loop(下面的示例带有 2 tables 元数据)
Table_N Column_N DType DLength
--------------------------------------------------------
AUT_C_TABLOG ORIGINAL VARCHAR 1
AUT_C_TABLOG PROTOCOL VARCHAR 1
AUT_C_TABLOG TABNAME VARCHAR 30
ANLA GEGST VARCHAR 8
ANLA GPLAB DATE NULL
ANLA GRBLT VARCHAR 5
ANLA GRBND VARCHAR 5
ANLA KTOGR VARCHAR 8
ANLA LAND1 VARCHAR 3
ANLA MENGE NUMERIC 16,3
使用常见的 table 表达式、lag、lead、几个 case 表达式和 xml 路径,您可以 return 为整个创建 table 语句table 的内容作为一个长字符串。
首先,创建并填充示例 table(请在您以后的问题中省去这一步)
CREATE TABLE Tables
(
Table_N sysname,
Column_N sysname,
DType sysname,
DLength varchar(5)
);
INSERT INTO Tables (Table_N, Column_N, DType, DLength) VALUES
('AUT_C_TABLOG', 'ORIGINAL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'PROTOCOL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'TABNAME', 'VARCHAR', '30'),
('ANLA', 'GEGST', 'VARCHAR', '8'),
('ANLA', 'GPLAB', 'DATE', NULL),
('ANLA', 'GRBLT', 'VARCHAR', '5'),
('ANLA', 'GRBND', 'VARCHAR', '5'),
('ANLA', 'KTOGR', 'VARCHAR', '8'),
('ANLA', 'LAND1', 'VARCHAR', '3'),
('ANLA', 'MENGE', 'NUMERIC', '16,3');
然后,使用 cte 获取滞后和引导 table 名称(这样您就会知道何时添加添加创建 table 以及何时不添加):
WITH CTE AS
(
SELECT Table_N,
Column_N,
DType,
DLength,
LAG(Table_N) OVER(ORDER BY Table_N) AS PrevTableName,
LEAD(Table_N) OVER(ORDER BY Table_N) AS NextTableName
FROM Tables
)
现在,在查询中使用几个 case 表达式:
SELECT CASE WHEN PrevTableName IS NULL OR Table_N <> PrevTableName
THEN 'CREATE TABLE '+ Table_N +' ('
ELSE ''
END + Column_N +' '+ DType +
CASE WHEN DLength IS NULL
THEN ''
ELSE '('+ DLength +')'
END +
CASE WHEN NextTableName IS NULL OR Table_N <> NextTableName
THEN '); '
ELSE ', '
END
FROM CTE
ORDER BY Table_N, Column_N -- Don't forget this order by, it's important!
FOR XML PATH('')
结果:
CREATE TABLE ANLA (GEGST VARCHAR(8), GPLAB DATE, GRBLT VARCHAR(5), GRBND VARCHAR(5), KTOGR VARCHAR(8), LAND1 VARCHAR(3), MENGE NUMERIC(16,3));
CREATE TABLE AUT_C_TABLOG (ORIGINAL VARCHAR(1), PROTOCOL VARCHAR(1), TABNAME VARCHAR(30));
您可以尝试生成动态语句并执行该语句。这里需要的是为每个不同的 table 名称编号行,然后,当行号为 1 时,包括 CREATE TABLE
部分 SQL 语句。
-- Table
CREATE TABLE #DDC_Loop (
Table_N nvarchar(100),
Column_N nvarchar(100),
DType nvarchar(100),
DLength nvarchar(100)
)
INSERT INTO #DDC_Loop
(Table_N, Column_N, DType, DLength)
VALUES
('AUT_C_TABLOG', 'ORIGINAL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'PROTOCOL', 'VARCHAR', '1'),
('AUT_C_TABLOG', 'TABNAME', 'VARCHAR', '30'),
('ANLA', 'GEGST', 'VARCHAR', '8'),
('ANLA', 'GPLAB', 'DATE', NULL),
('ANLA', 'GRBLT', 'VARCHAR', '5'),
('ANLA', 'GRBND', 'VARCHAR', '5'),
('ANLA', 'KTOGR', 'VARCHAR', '8'),
('ANLA', 'LAND1', 'VARCHAR', '3'),
('ANLA', 'MENGE', 'NUMERIC', '16,3')
-- Dynamci statement
DECLARE @stm nvarchar(max)
SET @stm = N''
;WITH cte AS (
SELECT
Table_N,
Column_N,
DType,
DLength,
ROW_NUMBER() OVER (PARTITION BY Table_N ORDER BY Table_N) RN,
CASE
WHEN DLength IS NULL THEN N', ' + Column_N + N' ' + DType
ELSE N', ' + Column_N + N' ' + DType + N'(' + DLength + N')'
END ColumnDefinition
FROM #DDC_Loop
)
SELECT
@stm = @stm +
CASE
WHEN RN = 1 THEN N'); CREATE TABLE ' + Table_N + N'(' + STUFF(ColumnDefinition, 1, 2, N'')
ELSE ColumnDefinition
END
FROM cte
ORDER BY Table_N, RN
SET @stm = STUFF(@stm, 1, 3, N'') + SUBSTRING(@stm, 1, 3)
-- Print and execute statement
PRINT @stm
EXEC (@stm)
生成的语句:
CREATE TABLE ANLA(GEGST VARCHAR(8), GPLAB DATE, GRBLT VARCHAR(5), GRBND VARCHAR(5), KTOGR VARCHAR(8), LAND1 VARCHAR(3), MENGE NUMERIC(16,3));
CREATE TABLE AUT_C_TABLOG(ORIGINAL VARCHAR(1), PROTOCOL VARCHAR(1), TABNAME VARCHAR(30));