在编写TSQL存储过程时,我发现自己想要集中/规范化代码的某些部分。例如,如果我有这样的查询:
SELECT * FROM SomeTable WHERE SomeColumn IN (2, 4, 8)
对于这样的情况,我想将(2,4,8)放在我可以在以后的其他查询中重用的过程之外的某些地方 - 以避免重复。有没有内置的方法来做到这一点?如果我可以分解整个SQL代码片段(如WHERE子句的一部分),并在其他查询中重用它们,那么真正干净的是,但我怀疑这是可能的。
感谢。
答案 0 :(得分:2)
我经常想要类似的东西但是特别不存在。以下是您可以做的一些事情。
选项1
我们所做的是使用用户定义函数(UDF)来收集您可能称之为全局变量的内容。
您可以在查询中内联调用UDF,这使其非常有用。
假设您要指定在多个存储过程中使用的服务器名称。复制该值不是最佳可维护的。相反,你可能会做类似的事情:
select * from clientNodes where serverName = dbo.SOME_SERVER_NAME()
选项2
这个更明显但值得指出。将您的值保存在查找表中,并通过ID引用它。 ID不会改变,但它引用的值可能会改变。使用上面的示例示例,但是对于此选项:
Table: Servers
Columns: ServerID, ServerName
declare @serverName varchar(50)
select @serverName = ServerName from Servers where ServerID = 1
这是数据库规范化的典型方法,但人们不一定会考虑这一点,以保持数据库逻辑数据的集中化。
我希望有所帮助! 伊恩
答案 1 :(得分:0)
使用SQL Server 2005,您可以考虑使用表值函数。
E.g:
SELECT ... FROM SomeTable INNER JOIN SomeFunction() F ON SomeTable.SomeColumn = F.Id
...
CREATE FUNCTION SomeFunction()
RETURNS @IdTable TABLE (Id INT)
AS
RETURN
(
SELECT 2 Id
UNION ALL
SELECT 4
UNION ALL
SELECT 8
)
更常见的情况是,您可能希望将值作为参数传递给存储过程。您可以将其作为逗号分隔的字符串执行此操作。例如。
EXEC MyProcedure('2,4,8')
...
CREATE PROCEDURE MyProcedure
(
@IdString AS VARCHAR(MAX)
)
AS
BEGIN
SELECT ... FROM SomeTable INNER JOIN SomeFunction(@IdString) F ON SomeTable.SomeColumn = F.Id
END
...
CREATE FUNCTION dbo.SomeFunction
(
@IdString VARCHAR(MAX)
)
RETURNS @IdTable TABLE (Id INT)
AS
BEGIN
DECLARE @CommaIndex INT, @TotalLength INT, @StartIndex INT, @Id VARCHAR(10)
SET @TotalLength=LEN(@IdString)
SET @StartIndex = 1
WHILE @StartIndex <= @TotalLength
BEGIN
SET @CommaIndex = CHARINDEX(',', @IdString, @StartIndex)
IF @CommaIndex > 0
BEGIN
SET @Id = SUBSTRING(@IdString, @StartIndex, @CommaIndex-@StartIndex)
SET @StartIndex = @CommaIndex + 1
END
ELSE
BEGIN
Set @Id = SUBSTRING(@IdString, @StartIndex, @TotalLength-@StartIndex+1)
SET @StartIndex = @TotalLength+1
END
INSERT INTO @IdTable
(Id)
VALUES
(CAST(@Id AS INT))
END
RETURN
END
答案 2 :(得分:0)
您通常会为要完成的工作创建 VIEW 。
首先创建一个返回SomeColumn值2,4,8的函数
create function fnSomeTableFilters()
returns @Result table ( ID int not null )
as
begin
insert @Result(ID)
select 2
union select 4
union select 8
return
end
GO
现在创建一个过滤2,4,8
的视图create view vwFilteredSomeTable
as
select * from SomeTable where SomeColumn in (select ID from dbo.fnSomeTableFilters())
最后,您的查询变为
SELECT * FROM vwFilteredSomeTable
确保为您的视图提供有意义的名称
例如)我有一个名为vwActiveSites的视图,用于根据名称建议查询活动网站
create view vwActiveSites
as
select ...
from Sites S
where S.Active = 1
这里的美妙之处在于,您使用 vwFilteredSomeTable 的所有查询都不需要更改。如果您需要使用不同的值进行过滤,则只需更改 fnSomeTableFilters
答案 3 :(得分:0)
是的 - 使用表格或视图。 SomeColumn为IN(2,4,8)必须以某种方式对您的数据有意义,因此以这种方式对其进行建模。给它一个有意义的名称,你可以自己重用它或者加入其他查询。为什么要把它埋在UDF或其他类似的东西中?
例如,如果SomeColumn是State并且值('FL','GA','SC')是您的东南地区,那么而不是传播:
SELECT * FROM SomeTable WHERE State IN ('FL', 'GA', 'SC')
到处都是,只需创建一个Territory列并完成它。
重复使用静态WHERE子句是另一个表或属性(也就是一个概念),只是乞求出来。