在过程中使用动态 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 中创建数据库、模式和表

如何通过 SQL Developer 执行带有游标和表 OUT 参数的存储过程?

python中使用sql select的过程的奇怪结果

使用 PL/SQL 过程在 oracle 10g 中转储表

在创建数据库和表之前创建一个过程