SQL 在视图中声明变量
SQL Declaring Variables in a View
我创建了一个在下面的 where 语句中使用动态变量的视图。
DECLARE
@wkFileYear SMALLINT = (select fs.FileYear from dbo.FileSemesters fs
where fs.systemcurrentflag = 1),
@wkFileSemester SMALLINT = (select fs.FileSemester from dbo.FileSemesters fs where fs.systemcurrentflag = 1)
Select R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
from
(
SELECT SC.FileType, SC.FileYear, SC.FileSemester, SC.ID, SC.ClassCode
FROM StudentClasses AS SC
) as R
LEFT JOIN
(
SELECT SAR.Filetype,SAR.FileYear, SAR.FileSemester, SAR.ID, SAR.ClassCode, SAR.Result as Raw
FROM
StudentAssessmentResults AS SAR
) as R1
on r.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
where
R.FileType = 'A'
AND (R.FileYear = @wkFileYear)
AND (R.FileSemester =
case
when (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and @wkFileSemester = 4
then 3
else @wkFileSemester
end
)
我想将其保存为数据库中的视图,但您不能在视图内声明变量。我查看了有关使用 CTE 或 Table Valued Functions 的所有信息,但我不确定所有语法。我尝试使用各种来源的示例创建 CTE 和 Table Value Functions,但没有成功。
希望有人能解释我如何仍然可以使用变量,但允许我将其保存为数据库中的视图。
视图的结构依赖于变量是没有意义的。
相反,您需要在您的视图中创建可以查询的@wkFileYear 和@wkFileSemester 列。
或者,如果您想使用变量,您可以创建一个数据库函数/存储过程,其中 returns 您需要的数据。
这是存储过程的示例。
CREATE PROCEDURE [dbo].[sp_GetTestData]
--Param
@wkFileYear SMALLINT,
@wkFileSemester SMALLINT
AS
BEGIN
@wkFileYear = select fs.FileYear from dbo.FileSemesters fs where fs.systemcurrentflag = 1
@wkFileSemester = select fs.FileSemester from dbo.FileSemesters fs where fs.systemcurrentflag = 1
Select R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
from
(
SELECT SC.FileType, SC.FileYear, SC.FileSemester, SC.ID, SC.ClassCode
FROM StudentClasses AS SC
) as R
LEFT JOIN
(
SELECT SAR.Filetype,SAR.FileYear, SAR.FileSemester, SAR.ID, SAR.ClassCode, SAR.Result as Raw
FROM
StudentAssessmentResults AS SAR
) as R1
on r.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID where
R.FileType = 'A'
AND (R.FileYear = @wkFileYear)
AND (R.FileSemester =
case
when (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and @wkFileSemester = 4
then 3
else @wkFileSemester
end
)
end
您可以作弊一点,方法是使用 CTE 解析任何想要声明的变量。如果这些 settings 的 CTE 只有一行,那么我们可以使用交叉连接合并 settings 以便它们对每个视图中的行。
CREATE VIEW CurrentSemesterClasses
AS
WITH SystemSettings as (
-- Query to resolve the Variables, MUST only return a single row
SELECT TOP 1 FileYear, FileSemester
FROM dbo.FileSemesters
WHERE SystemCurrentFlag = 1
)
SELECT R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
FROM StudentClasses R, SystemSettings
LEFT JOIN StudentAssessmentResults R1
ON R.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
WHERE R.FileType = 'A'
AND R.FileYear = SystemSettings.FileSemester
AND R.FileSemester = CASE
WHEN (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and SystemSettings.FileSemester = 4 then 3
ELSE SystemSettings.FileSemester
END
NOTE: I have simplified your original query by referencing the required tables directly rather than using the strange sub-query that was used. This syntax should behave the same or have better performance than the original, but it ultimately much easier to maintain.
There is no performance benefit to sub-querying just the columns that you think you need via sub-queries instead of joining directly onto tables. This syntax looks like you are expecting the sub-query to cache a subset of the data table but this is not how it works. Do not make the mistake of assuming the sub-query is resolved entirely first before the main query
在这种特殊情况下,如果按照约定 或应用程序逻辑,dbo.FileSemesters
table 中将只有一行 SystemCurrentFlag = 1
那么我们可以进一步将这个查询简化为一个简单的连接:
CREATE VIEW CurrentSemesterClassesSimple
AS
SELECT R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
FROM StudentClasses R
INNER JOIN dbo.FileSemesters S ON R.FileYear = s.FileYear AND S.SystemCurrentFlag = 1
LEFT JOIN StudentAssessmentResults R1
ON R.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
WHERE R.FileType = 'A'
AND R.FileSemester = CASE
WHEN (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and S.FileSemester = 4 then 3
ELSE S.FileSemester
END
为了完成这个集合,下面是如何将清理后的原始查询打包成 TVF - Table Valued Function
CREATE FUNCTION CurrentSemesterClassesFn
(
-- This function has no parameters
)
RETURNS
@Table_Var TABLE
(
-- Please update the types of these columns to match your schema!
FileType CHAR(1)
, FileYear INT
, FileSemester INT
, ID INT
, ClassCode VARCHAR(100)
, [Raw] VARCHAR(max)
)
CREATE VIEW CurrentSemesterClassesSimple
AS
BEGIN
DECLARE @wkFileYear SMALLINT, @wkFileSemester SMALLINT;
SELECT @wkFileYear = fs.FileYear
, @wkFileSemester = fs.FileSemester
FROM dbo.FileSemesters fs
WHERE fs.systemcurrentflag = 1;
INSERT INTO @Table_Var (FileType, FileYear, FileSemester, ID, ClassCode, Raw)
SELECT R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
FROM StudentClasses R
LEFT JOIN StudentAssessmentResults R1
ON R.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
WHERE R.FileType = 'A'
AND R.FileYear = @wkFileYear
AND R.FileSemester = CASE
WHEN (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and @wkFileSemester = 4 then 3
ELSE S.FileSemester
END
RETURN
END
我创建了一个在下面的 where 语句中使用动态变量的视图。
DECLARE
@wkFileYear SMALLINT = (select fs.FileYear from dbo.FileSemesters fs
where fs.systemcurrentflag = 1),
@wkFileSemester SMALLINT = (select fs.FileSemester from dbo.FileSemesters fs where fs.systemcurrentflag = 1)
Select R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
from
(
SELECT SC.FileType, SC.FileYear, SC.FileSemester, SC.ID, SC.ClassCode
FROM StudentClasses AS SC
) as R
LEFT JOIN
(
SELECT SAR.Filetype,SAR.FileYear, SAR.FileSemester, SAR.ID, SAR.ClassCode, SAR.Result as Raw
FROM
StudentAssessmentResults AS SAR
) as R1
on r.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
where
R.FileType = 'A'
AND (R.FileYear = @wkFileYear)
AND (R.FileSemester =
case
when (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and @wkFileSemester = 4
then 3
else @wkFileSemester
end
)
我想将其保存为数据库中的视图,但您不能在视图内声明变量。我查看了有关使用 CTE 或 Table Valued Functions 的所有信息,但我不确定所有语法。我尝试使用各种来源的示例创建 CTE 和 Table Value Functions,但没有成功。
希望有人能解释我如何仍然可以使用变量,但允许我将其保存为数据库中的视图。
视图的结构依赖于变量是没有意义的。
相反,您需要在您的视图中创建可以查询的@wkFileYear 和@wkFileSemester 列。
或者,如果您想使用变量,您可以创建一个数据库函数/存储过程,其中 returns 您需要的数据。
这是存储过程的示例。
CREATE PROCEDURE [dbo].[sp_GetTestData]
--Param
@wkFileYear SMALLINT,
@wkFileSemester SMALLINT
AS
BEGIN
@wkFileYear = select fs.FileYear from dbo.FileSemesters fs where fs.systemcurrentflag = 1
@wkFileSemester = select fs.FileSemester from dbo.FileSemesters fs where fs.systemcurrentflag = 1
Select R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
from
(
SELECT SC.FileType, SC.FileYear, SC.FileSemester, SC.ID, SC.ClassCode
FROM StudentClasses AS SC
) as R
LEFT JOIN
(
SELECT SAR.Filetype,SAR.FileYear, SAR.FileSemester, SAR.ID, SAR.ClassCode, SAR.Result as Raw
FROM
StudentAssessmentResults AS SAR
) as R1
on r.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID where
R.FileType = 'A'
AND (R.FileYear = @wkFileYear)
AND (R.FileSemester =
case
when (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and @wkFileSemester = 4
then 3
else @wkFileSemester
end
)
end
您可以作弊一点,方法是使用 CTE 解析任何想要声明的变量。如果这些 settings 的 CTE 只有一行,那么我们可以使用交叉连接合并 settings 以便它们对每个视图中的行。
CREATE VIEW CurrentSemesterClasses
AS
WITH SystemSettings as (
-- Query to resolve the Variables, MUST only return a single row
SELECT TOP 1 FileYear, FileSemester
FROM dbo.FileSemesters
WHERE SystemCurrentFlag = 1
)
SELECT R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
FROM StudentClasses R, SystemSettings
LEFT JOIN StudentAssessmentResults R1
ON R.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
WHERE R.FileType = 'A'
AND R.FileYear = SystemSettings.FileSemester
AND R.FileSemester = CASE
WHEN (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and SystemSettings.FileSemester = 4 then 3
ELSE SystemSettings.FileSemester
END
NOTE: I have simplified your original query by referencing the required tables directly rather than using the strange sub-query that was used. This syntax should behave the same or have better performance than the original, but it ultimately much easier to maintain.
There is no performance benefit to sub-querying just the columns that you think you need via sub-queries instead of joining directly onto tables. This syntax looks like you are expecting the sub-query to cache a subset of the data table but this is not how it works. Do not make the mistake of assuming the sub-query is resolved entirely first before the main query
在这种特殊情况下,如果按照约定 或应用程序逻辑,dbo.FileSemesters
table 中将只有一行 SystemCurrentFlag = 1
那么我们可以进一步将这个查询简化为一个简单的连接:
CREATE VIEW CurrentSemesterClassesSimple
AS
SELECT R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
FROM StudentClasses R
INNER JOIN dbo.FileSemesters S ON R.FileYear = s.FileYear AND S.SystemCurrentFlag = 1
LEFT JOIN StudentAssessmentResults R1
ON R.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
WHERE R.FileType = 'A'
AND R.FileSemester = CASE
WHEN (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and S.FileSemester = 4 then 3
ELSE S.FileSemester
END
为了完成这个集合,下面是如何将清理后的原始查询打包成 TVF - Table Valued Function
CREATE FUNCTION CurrentSemesterClassesFn
(
-- This function has no parameters
)
RETURNS
@Table_Var TABLE
(
-- Please update the types of these columns to match your schema!
FileType CHAR(1)
, FileYear INT
, FileSemester INT
, ID INT
, ClassCode VARCHAR(100)
, [Raw] VARCHAR(max)
)
CREATE VIEW CurrentSemesterClassesSimple
AS
BEGIN
DECLARE @wkFileYear SMALLINT, @wkFileSemester SMALLINT;
SELECT @wkFileYear = fs.FileYear
, @wkFileSemester = fs.FileSemester
FROM dbo.FileSemesters fs
WHERE fs.systemcurrentflag = 1;
INSERT INTO @Table_Var (FileType, FileYear, FileSemester, ID, ClassCode, Raw)
SELECT R.FileType, R.FileYear, R.FileSemester, R.ID, R.ClassCode, R1.Raw
FROM StudentClasses R
LEFT JOIN StudentAssessmentResults R1
ON R.FileYear = R1.Fileyear
and R.FileSemester = R1.FileSemester
and R.FileType = R1.FileType
and R.ClassCode = R1. ClassCode
and R.ID = R1.ID
WHERE R.FileType = 'A'
AND R.FileYear = @wkFileYear
AND R.FileSemester = CASE
WHEN (left(R.classcode,2) = '12' or left(R.classcode,2) = '11') and @wkFileSemester = 4 then 3
ELSE S.FileSemester
END
RETURN
END