我需要添加新位置的50个存储过程。是否有以下列方式编写存储过程的替代方法? (我为每个位置复制相同的select语句)
IF @LOCATION = 'Canada'
BEGIN
SELECT location_id, location_description
INTO #tempAssetHistoryCANADA
FROM [SERVER20].[Shop_Canada].[dbo].[report_asset_history]
END
IF @LOCATION = 'USA'
BEGIN
SELECT location_id, location_description
INTO #tempAssetHistoryUSA
FROM [SERVER20].[Shop_USA].[dbo].[report_asset_history]
END
我有一个select语句,如果@parameter
=" x"然后是完全相同的select语句,但是来自具有相同结构的不同数据源,如果@parameter
=" y"。
我想知道是否有更好的方法来编写这些存储过程,因为将来当我需要添加新位置时,我需要更新所有50个存储过程,并复制每个语句并稍微改变它对于新的位置数据?我已经研究过,并没有发现任何有用的东西。
谢谢!
答案 0 :(得分:2)
一种可能的方法是创建一个视图:
,而不是使用动态查询CREATE VIEW dbo.Locations
AS
SELECT location_id, location_description, 'Canada' AS location
FROM [SERVER20].[Shop_Canada].[dbo].[report_asset_history]
UNION ALL
SELECT location_id, location_description, 'USA' AS location
FROM [SERVER20].[Shop_USA].[dbo].[report_asset_history]
然后使用它:
SELECT location_id, location_description
INTO #tempAssetHistory
FROM [dbo].Locations
WHERE location = @LOCATION
如果您有新表[SERVER20].[Shop_XXX].[dbo].[report_asset_history]
,则必须将它们添加到您的视图中。
答案 1 :(得分:1)
首先,您不需要为每个位置使用不同的#temp表。您在每个中存储相同的数据列。其次,您可以根据位置将“From”子句存储在表中,然后使用动态sql选择临时表。我很快就会提供一些代码和示例。
DECLARE @fromClause VARCHAR(255)
DECLARE @sql VARCHAR(MAX)
--Explicitly create the temp table
CREATE TABLE #T (location_id int, location_description varchar(255) )
--Get the FROM clause
select @fromClause = fromClause from tblLocation WHERE location = @LOCATION
--Build the Dynamic SQL
SET @sql = 'SELECT location_id, location_description ' + @fromClause
--Insert into your temp table
INSERT INTO #T execute ( @sql )
--View the results
SELECT * FROM #T
答案 2 :(得分:0)
您可以使用一个表来存储所有选定的数据,使用以下内容:
DECLARE @country VARCHAR(20) = 'USA'
CREATE TABLE #tempHistory (country varchar(20), location_id int, location_description varchar(20))
DECLARE @sql VARCHAR(max)
SET @sql = 'SELECT ''' + @country + ''' as country, location_id, location_description FROM [SERVER20].[Shop_' + @country + '].[dbo].[report_asset_history]'
INSERT INTO #tempHistory EXEC (@sql)
或者您可以使用更灵活的解决方案将国家/地区列表作为参数:
CREATE PROCEDURE dbo.prepare_tempHistory(@listOfCountries VARCHAR(max))
AS
DECLARE @sql varchar(max)
SET @sql = ''
SELECT @sql = @sql + ' UNION ALL ' +
'SELECT ''' + val + ''' as country, location_id, location_description FROM [SERVER20].[Shop_' + val + '].[dbo].[report_asset_history]'
FROM dbo.fnSplit(@listOfCountries, ',')
SET @sql = RIGHT(@sql, len(@sql)-11)
INSERT INTO #tempHistory EXEC (@sql)
GO
但是你需要一个小函数来将参数分割成表格:
CREATE FUNCTION dbo.fnSplit
(
@delimited nvarchar(max),
@delimiter nvarchar(5)
)
RETURNS @ret TABLE (val nvarchar(max))
AS
BEGIN
declare @xml xml
set @xml = N'<root><r>' + replace(@delimited,@delimiter,'</r><r>') + '</r></root>'
insert into @ret(val)
select r.value('.','varchar(max)') as item
from @xml.nodes('//root/r') as records(r)
RETURN
END
GO
现在您可以通过简单的方式准备数据:
CREATE TABLE #tempHistory (country varchar(20), location_id int, location_description varchar(20))
EXEC dbo.prepare_tempHistory 'USA,Canada,Mexico'
SELECT * FROM #tempHistory
对于任何其他国家/地区仅修改参数
答案 3 :(得分:0)
您可以通过为所有助手提供#Temp表并检查数据库中的位置表,然后在执行SP时调用变量来实现此目的:
致电SP:
SP_Some_SP 'Canada'
在SP内部
Declare @Location Varchar(100)
Declare @Location_ID int = (Select Location_ID from [Location] where Location_Description = @Location)
CREATE TABLE #TempAssetHistory
(
location_ID int,
location_Description varchar(100)
)
If Exists(Select Location_Description from [Location] where Location_Description = @Location )
BEGIN
Insert INTO #TempAssetHistory
Values(@Location_ID,@Location)
END
ELSE
BEGIN
-- Do something
END
答案 4 :(得分:0)
使用回答中的建议和提到动态SQL的评论我为自己提出了这个小解决方案。它比Denis Rubashkin所说的更好,因为使用他的解决方案我每次添加新位置时仍然需要复制整个SQL查询。这样,我可以复制4行...
IF @LOCATION = 'CANADA'
...每当我想添加一个新位置而不是整个SQL语句时,从IF语句开始。它将使用参数中的正确名称替换服务器名称,并将其名称附加到临时表。
BEGIN
SET @location_server = 'SHOP_Canada'
END
@LOCATION varchar(50),
@sqlCommand nvarchar(2000),
@location_server varchar(75)
IF @LOCATION = 'CANADA'
BEGIN
SET @location_server = 'SHOP_Canada'
END
IF @LOCATION = 'USA'
BEGIN
SET @location_server = 'SHOP_USA'
END
SET @sqlCommand = 'SELECT location_id, location_description
into ##MarineShopAssetExpensesLTD_'+@location_server+'
FROM [SERVER20].'+QUOTENAME(@location_server)+'.[dbo].[report_asset_history]
INNER JOIN [SERVER20].'+QUOTENAME(@location_server)+'.[dbo].imtbl_asset ON [report_asset_history].asset_id = imtbl_asset.id
GROUP BY location_id, location_description
EXECUTE sp_executesql @sqlCommand
答案 5 :(得分:0)
由于每个SP都在寻找不同的数据,因此您可以使用另一种更为激烈的方法。
这种方法要求您将所有50个SP的所有数据SELECT语句放入一个SP,比如spDataLoad,它带有两个参数 - 数据集名称和位置。 spDataLoad根据指定的数据集和位置选择数据,并将请求的数据返回给调用者。
对于每种不同的数据集和位置组合,您仍然需要多个select语句,但至少所有内容都在一个SP中,并且对数据的更改不会影响所有50个SP。如果每个位置的表和数据相同,则可以将代码细分为多个部分,每个部分对应一个部分,使用相同的代码,但与该位置对应的数据库名称除外。
使用上面的代码作为示例,如果我们选择'AssetHistory'作为数据集名称,那么现有SP中的代码将如下所示:
:
:
CREATE TABLE #AssetHistory (
location_ID int,
location_Description varchar(100)
);
INSERT INTO #AssetHistory EXEC spDataLoad @DataSet='AssetHistory', @Location=@Location;
:
: use the data set
:
现在假设您有另一个需要数据集'AssetDetails'的SP,那么代码将是这样的:
CREATE TABLE #AssetDetails (
:
: Specification for Asset Details table
:
);
INSERT INTO #AssetDetails EXEC spDataLoad @DataSet='AssetDetails', @Location=@Location;
:
: use the data set
:
每个位置的存储过程spDataLoad(包含多个部分),基于请求的数据集进行单独选择可能如下所示:
CREATE PROCEDURE spDataLoad
@DATASET varchar(20)
, @LOCATION Varchar(50)
AS
BEGIN
-- CANADA SECTION ------------------------------------
IF @LOCATION = 'CANADA'
BEGIN
IF @DATASET = 'AssetHistory'
SELECT location_id, location_description
FROM [SERVER20].[Shop_Canada].[dbo].[report_asset_history]
ELSE IF @DATASET = 'AssetDetails'
SELECT
: Asset details data
FROM [SERVER20].[Shop_Canada].[dbo].[report_asset_details]
ELSE IF @DATASET = '....'
:
: Etc, Etc for CANADA SECTION
END;
-- USA SECTION ------------------------------------
IF @LOCATION = 'USA'
BEGIN
IF @DATASET = 'AssetHistory'
SELECT location_id, location_description
FROM [SERVER20].[Shop_USA].[dbo].[report_asset_history]
ELSE IF @DATASET = 'AssetDetails'
SELECT
: Asset details data
FROM [SERVER20].[Shop_USA].[dbo].[report_asset_details]
ELSE IF @DATASET = '....'
:
: Etc, Etc for USA SECTION
END;
-- SOME OTHER SECTION ---------------------------
IF @LOCATION = 'SOME OTHER'
BEGIN
: Same logic
END
RETURN 0;
END
要管理性能,您可能需要添加可由调用者指定的过滤默认参数,并将WHERE子句添加到数据集选择中。