在过程中使用动态 sql 创建模式和表
Posted
技术标签:
【中文标题】在过程中使用动态 sql 创建模式和表【英文标题】:Using dynamic sql in a procedure to create schemas and tables 【发布时间】:2019-08-05 18:56:33 【问题描述】:我的任务是创建一个示例数据库,用于存储来自我大学 15 个校区的数据。每个校园的数据必须与其他数据分开(使用模式),并且每个模式必须具有相同的表和列。这是必须使用动态 sql 的地方(如作业中所述)。
以下代码 sn-p 展示了我的努力(请记住,我还是新手):
使用大师 走 创建数据库 CTUDB 走 使用 CTUDB 走 创建过程 AddCampus_proc(@campus varchar(50)) 作为 声明 @DynamicSQL varchar(MAX) 开始 SET @DynamicSQL = '创建模式 ['+@campus+']' 执行(@DynamicSQL) SET @DynamicSQL = '创建表 ['+@campus+'].Student_tbl( 学生ID号(4,0)不为空, 名称 varchar(50) 不为空, 姓氏 varchar(50) 不为空, ID_Number number(13,0) 不为空, 地址 varchar(100) 不为空, 主键(学生 ID), CONSTRAINT CheckStudentID 检查(长度(StudentID)= 4), CONSTRAINT CheckIDNumber 检查(长度(ID_Number)= 13) );' 执行(@DynamicSQL) SET @DynamicSQL = '创建表 ['+@campus+'].Course_tbl( CourseID 整数不为空, CourseName varchar(50) 不为空, 说明 varchar(100) 不为空, 学生ID号(4,0)不为空, 主键(CourseID), 外键 (StudentID) 参考 Student_tbl(StudentID), 约束 CheckStudentID 检查(长度(StudentID)= 4) );' 执行(@DynamicSQL) SET @DynamicSQL = '创建表 ['+@campus+'].ClassMarks_tbl( ClassMarksID 整数不为空, 学生ID号(4,0)不为空, CourseID 整数不为空, Semester1_Mark1 整数非空检查(Semester1_Mark1 介于 0 和 100 之间), Semester1_Mark2 整数非空检查(Semester1_Mark2 介于 0 和 100 之间), Semester1_Mark3 整数非空检查(Semester1_Mark3 介于 0 和 100 之间), Semester1_Average 整数非空检查(Semester1_Average 介于 0 和 100 之间), Semester1_Test_Mark 整数非空检查(Semester1_Test_Mark 介于 0 和 100 之间), Semester2_Mark1 整数非空检查(Semester2_Mark1 介于 0 和 100 之间), Semester2_Mark2 整数非空检查(Semester2_Mark2 介于 0 和 100 之间), Semester2_Mark3 整数非空检查(Semester2_Mark3 介于 0 和 100 之间), Semester2_Average 整数非空检查(Semester2_Average 介于 0 和 100 之间), Semester2_Test_Mark 整数非空检查(Semester2_Test_Mark 介于 0 和 100 之间), 主键(ClassMarksID), 外键 StudentID 参考 Student_tbl(StudentID), 外键 CourseID 参考 Course_tbl(CourseID), 约束 CheckStudentID 检查(长度(StudentID)= 4) );' 执行(@DynamicSQL) SET @DynamicSQL = '创建表 ['+@campus+'].Facilitator_tbl( FacilitatorID 整数不为空, 名称 varchar(50) 不为空, 姓氏 varchar(50) 不为空, 地址 varchar(100) 不为空, Paycheck deciaml(19,4) 不为空, CourseID 整数不为空, 主键(FacilitatorID), 外键 CourseID 参考 Course_tbl(CourseID) );' 执行(@DynamicSQL) SET @DynamicSQL = '创建表 ['+@campus+'].Parents_tbl( ParentID 整数不为空, 名称 varchar(50) 不为空, 姓氏 varchar(50) 不为空, ID_Number number(13,0) 不为空, 学生ID号(4,0)不为空, 主键(父 ID), 外键 StudentID 参考 Student_tbl(StudentID), 约束 StudentID 检查(长度(StudentID)= 4) );' 执行(@DynamicSQL) 结尾 执行 AddCampus_proc '内尔斯普雷特' 执行 AddCampus_proc 'Roodepoort' 执行 AddCampus_proc '桑顿' EXEC AddCampus_proc '博克斯堡' EXEC AddCampus_proc '比勒陀利亚' 执行 AddCampus_proc 'Cape_Town' 执行 AddCampus_proc 'Vereniging' 执行 AddCampus_proc '布隆方丹' 执行 AddCampus_proc 'Polokwane' 执行 AddCampus_proc '德班' 执行 AddCampus_proc '斯泰伦博斯' 执行 AddCampus_proc 'Port_Elizabeth' 执行 AddCampus_proc 'Pochefstroom' EXEC AddCampus_proc 'Auckland_Park'
查询成功执行,但问题是架构和表实际上并未创建:
没有创建表
没有创建架构
我的问题是,为什么没有创建表和模式?我推断这是因为动态sql可能是错误的,但是我不明白为什么在这种情况下查询会成功执行。
【问题讨论】:
尝试打印出您的动态变量值以查看代码(而不是执行它们)以查看它们的样子。在创建架构之后,您可能需要一个 GO。 提示:将对象名称组装成动态 SQL 语句时的最佳做法是使用QuoteName()
以避免出现奇怪名称的问题,例如New Table
带有空格或保留字,例如 From
。
谢谢两位,对未来有用的信息。我的大学并没有确切地教给我最佳实践,因此您的意见很有价值
【参考方案1】:
将DECLARE @DynamicSQL varchar(MAX)
变量移到存储过程的begin end
块中:
CREATE PROCEDURE AddCampus_proc(@campus varchar(50))
AS
BEGIN
DECLARE @DynamicSQL varchar(MAX)
SET @DynamicSQL = 'CREATE schema ['+@campus+']'
PRINT (@DynamicSQL)
-- more T-SQL code
EXEC (@DynamicSQL)
END
EXEC AddCampus_proc 'Nelspruit'
【讨论】:
【参考方案2】:好的,已修复所有拼写错误、语法错误和非唯一名称。一切都好。 添加了一些错误处理。希望它能让你再次前进。
USE master
GO
if not exists (select 1 from master.sys.databases where name = 'CTUDB')
CREATE DATABASE CTUDB
GO
USE CTUDB
GO
if object_id('AddCampus_proc','P') is not null
begin
drop proc AddCampus_proc;
end;
GO
CREATE PROCEDURE AddCampus_proc(@campus varchar(50)
)
AS
BEGIN
DECLARE @DynamicSQL varchar(MAX)
SET @DynamicSQL = 'CREATE schema '+quotename(@campus)+''
begin try
EXEC (@DynamicSQL);
end try
begin catch
if error_number() <> 2759 --this just means the schema already exists.
begin
print(error_number())
print(error_message())
end
end catch
SET @DynamicSQL = 'CREATE table '+quotename(@campus)+'.Student_tbl(
StudentID numeric(4,0) not null PRIMARY KEY,
Name varchar(50) not null,
Surname varchar(50) not null,
ID_numeric numeric(13,0) not null,
Address varchar(100) not null,
CONSTRAINT '+@campus+'_Student_tbl_CheckStudentID check (len(StudentID) = 4),
CONSTRAINT '+@campus+'_Student_tbl_CheckIDnumeric check (len(ID_numeric) = 13)
);'
--print (@DynamicSQL);
EXEC (@DynamicSQL);
SET @DynamicSQL = 'CREATE table '+quotename(@campus)+'.Course_tbl(
CourseID integer not null PRIMARY KEY,
CourseName varchar(50) not null,
Description varchar(100) not null,
StudentID numeric(4,0) not null,
FOREIGN KEY (StudentID) REFERENCES ' + quotename(@campus) + '.Student_tbl(StudentID),
CONSTRAINT '+@campus+'_Course_tbl_CheckStudentID check (len(StudentID) = 4)
);'
--print (@DynamicSQL);
EXEC (@DynamicSQL);
SET @DynamicSQL = 'CREATE table '+quotename(@campus)+'.ClassMarks_tbl(
ClassMarksID integer not null PRIMARY KEY,
StudentID numeric(4,0) not null,
CourseID integer not null,
Semester1_Mark1 integer not null check (Semester1_Mark1 between 0 and 100),
Semester1_Mark2 integer not null check (Semester1_Mark2 between 0 and 100),
Semester1_Mark3 integer not null check (Semester1_Mark3 between 0 and 100),
Semester1_Average integer not null check (Semester1_Average between 0 and 100),
Semester1_Test_Mark integer not null check (Semester1_Test_Mark between 0 and 100),
Semester2_Mark1 integer not null check (Semester2_Mark1 between 0 and 100),
Semester2_Mark2 integer not null check (Semester2_Mark2 between 0 and 100),
Semester2_Mark3 integer not null check (Semester2_Mark3 between 0 and 100),
Semester2_Average integer not null check (Semester2_Average between 0 and 100),
Semester2_Test_Mark integer not null check (Semester2_Test_Mark between 0 and 100),
FOREIGN KEY (StudentID) REFERENCES ' + quotename(@campus) + '.Student_tbl(StudentID),
FOREIGN KEY (CourseID) REFERENCES ' + quotename(@campus) + '.Course_tbl(CourseID),
CONSTRAINT '+@campus+'_ClassMarks_tbl_CheckStudentID check (len(StudentID) = 4)
);'
--print (@DynamicSQL);
EXEC (@DynamicSQL);
SET @DynamicSQL = 'CREATE table '+quotename(@campus)+'.Facilitator_tbl(
FacilitatorID integer not null PRIMARY KEY,
Name varchar(50) not null,
Surname varchar(50) not null,
Address varchar(100) not null,
Paycheck decimal(19,4) not null,
CourseID integer not null,
FOREIGN KEY (CourseID) REFERENCES ' + quotename(@campus) + '.Course_tbl(CourseID)
);'
--print (@DynamicSQL);
EXEC (@DynamicSQL);
SET @DynamicSQL = 'CREATE table '+quotename(@campus)+'.Parents_tbl(
ParentID integer not null PRIMARY KEY,
Name varchar(50) not null,
Surname varchar(50) not null,
ID_numeric numeric(13,0) not null,
StudentID numeric(4,0) not null,
FOREIGN KEY (StudentID) REFERENCES ' + quotename(@campus) + '.Student_tbl(StudentID),
CONSTRAINT '+@campus+'_Parents_tbl_StudentID check (len(StudentID) = 4)
);'
--print (@DynamicSQL);
EXEC (@DynamicSQL);
END
GO
EXEC AddCampus_proc 'Nelspruit'
EXEC AddCampus_proc 'Roodepoort'
EXEC AddCampus_proc 'Sandton'
EXEC AddCampus_proc 'Boksburg'
EXEC AddCampus_proc 'Pretoria'
EXEC AddCampus_proc 'Cape_Town'
EXEC AddCampus_proc 'Vereniging'
EXEC AddCampus_proc 'Bloemfontein'
EXEC AddCampus_proc 'Polokwane'
EXEC AddCampus_proc 'Durban'
EXEC AddCampus_proc 'Stellenbosch'
EXEC AddCampus_proc 'Port_Elizabeth'
EXEC AddCampus_proc 'Pochefstroom'
EXEC AddCampus_proc 'Auckland_Park'
【讨论】:
非常感谢。非常有帮助的答案,现在清楚了,看看我哪里出错了。以上是关于在过程中使用动态 sql 创建模式和表的主要内容,如果未能解决你的问题,请参考以下文章
在 PostgreSQL 中为特定模式和表所有者创建表的过程是啥
如何使用 init.sql 在 Postgresql 中创建数据库、模式和表