在迭代中正确使用@declare 时遇到问题
Having trouble correctly using @declare in an iteration
我post又问了一个问题
但事实证明,我的问题的第一个修复更简单,我将设置我的计数放在错误的位置进行迭代。
真正的问题是,当我尝试迭代时,我构造数据库名称的值是错误的。
这是 Stack Overflow 上一位友好人士更正的代码,他们通知我 post 第二个问题,以澄清声明格式不正确的问题。
主要问题涉及这一行
[EDDS'+cast(@databasename as nvarchar(128))+'].[EDDSDBO].[文档]
--check if the #databases table is already present and then drop it
IF OBJECT_ID('tempdb..#databases', 'U') IS NOT NULL
drop table #databases;
--create the temp table as outside the loop
create table #databases(
ID INT IDENTITY,
ArtifactID VARCHAR(20) -- not sure of this ID's data type
)
--check if your temp table exists and drop if necessary
IF OBJECT_ID('tempdb..#temptable', 'U') IS NOT NULL
drop table #temptable;
--create the temp table as outside the loop
create table #temptable(
fileSize dec,
extractedTextSize dec
)
--this will allow the population of each database name
DECLARE @databasename sysname = ''
-- initialze to 1 so it matches first record in temp table
DECLARE @LoopOn int = 1;
--this will be the max count from table
DECLARE @MaxCount int = 0;
--Once this first statement has been run there will now be a number column
that is associated with the artificatID. Each database has an area that is
-- titled [EDDS'artifactID']. So if the artifactID = 1111111 then the
DB would be accessed at [EDDS1111111]
-- do insert here so it adds the ID column
INSERT INTO #databases(
ArtifactID
)
SELECT ArtifactID
FROM edds.eddsdbo.[Case]
where name like '%Review%'
-- sets the max number of loops we are going to do
select @MaxCount = COUNT(*)
FROM #databases;
while @LoopOn <= @MaxCount
BEGIN
-- your table has IDENTITY so select the one for the loop your on
(initalize to 1)
select @databasename = ArtifactID
FROM #databases
WHERE ID = @LoopOn;
--generate your sql using the @databasename variable, if you want
to make
--the database and table names dynamic too then you can use the
same formula
insert into #temptable
select SUM(fileSize)/1024/1024/1024,
SUM(extractedTextSize)/1024/1024
-- dont know/think this will work like this? If not you have to
use dynamic SQL
FROM [EDDS'+cast(@databasename as nvarchar(128))+'].[EDDSDBO].
[Document] ed
where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106))
-- remove all deletes/etc and just add one to the @LoopOn and it will be selected above based off the ID
select @LoopOn += 1
end
-- Query the final values in the temp table after the iteration is complete
select filesize+extractedTextSize as Gigs
FROM #temptable
我收到一个错误
Invalid object name 'EDDS'+cast(@databasename as nvarchar(128))+'.EDDSDBO.Document'
如果我手动输入 EDDS1111111.EDDSDBO.Document
它工作正常。
如果我设置 declare @databasename nvarchar(128) = 1111111
它也会破坏代码。
我认为该错误与我如何转换它或将其添加到语句中有关。
感谢您提供的任何帮助
您不能构建 SQL 并像上面那样执行,否则会出现您看到的错误,您需要使整个语句动态化。下面是 2 种不同的解决方案,具体取决于 size/complexity(如果您没有 post 完整代码)。
这将解决您的问题并为 table 中的每一行创建动态 SQL。
我将其更新为有 2 个解决方案,一个是如果您没有很多行来执行动态 SQL,另一个是如果您有复杂或很多 运行在。
第二个解决方案可以针对您的特定场景使用更少的代码进行精简,但是按照我下面的方式进行操作,只需更改 SQL 和 temp table你的插入是为了你的结果。
我自己用一些基本的 sql table 测试了这个,两个版本都运行良好。
尽管我没有像您那样进行计算,但根据您 table 中的数据,您的计算 and/or 您的实际选择可能需要更新,因为我无法访问您的实际 data/tables测试。
我还有几行用于测试,你显然可以把它们去掉。
-- this is used to add line breaks to make code easier to read
DECLARE @NewLine AS NVARCHAR(MAX) = CHAR(10)
-- to hold your dynamic SQL for all rows/inserts at once
DECLARE @sql NVARCHAR(MAX) = N'';
-- create temp table to insert your dynamic SQL results into
IF OBJECT_ID('tempdb..#DatabaseSizes', 'U') IS NOT NULL
DROP TABLE #DatabaseSizes;
create table #DatabaseSizes(
fileSize DECIMAL,
extractedTextSize DECIMAL
)
SELECT @sql = @sql + N'' +
'select SUM(fileSize)/1024/1024/1024 as fileSize, SUM(extractedTextSize)/1024/1024 as extractedTextSize ' + @NewLine +
'FROM [EDDS' + CAST(ArtifactID as nvarchar(128)) + '].[EDDSDBO].[Document] ed ' + @NewLine +
'where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106)) ; ' + @NewLine + @NewLine
FROM edds.eddsdbo.[Case]
WHERE name like '%Review%'
-- for testing/validating
PRINT @sql
INSERT INTO #DatabaseSizes (
fileSize,
extractedTextSize
)
-- executes all the dynamic SQL we just generated
EXEC sys.sp_executesql @SQL;
SELECT *
FROM #DatabaseSizes
-- &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
-- for solution with a LOT of records from your table that is too large or complex to execute all at once using the above
-- this will generate seperate dynamic SQL for each row in your table
-- &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
DECLARE @NewLine AS NVARCHAR(MAX) = CHAR(10)
DECLARE @IdOnFromLoop INT
DECLARE @DynamicSQLFromLoop NVARCHAR(MAX)
-- table to insert data into that our dynamic SQL creates
IF OBJECT_ID('tempdb..#DatabaseSizes', 'U') IS NOT NULL
DROP TABLE #DatabaseSizes;
create table #DatabaseSizes(
fileSize DECIMAL,
extractedTextSize DECIMAL
)
-- this is to hold each rows dynamic SQL so we can loop through them and execute each statement one at a time
IF OBJECT_ID('tempdb..#DynamicSQLPerLoop', 'U') IS NOT NULL
DROP TABLE #DynamicSQLPerLoop;
create table #DynamicSQLPerLoop(
ID INT IDENTITY,
DynamicSQL NVARCHAR(MAX)
)
-- here we build our our dynamic SQL we want for each row in the table to be executed
INSERT INTO #DynamicSQLPerLoop (
DynamicSQL
)
SELECT 'select SUM(fileSize)/1024/1024/1024 as fileSize, SUM(extractedTextSize)/1024/1024 as extractedTextSize ' + @NewLine +
'FROM [EDDS' + CAST(ArtifactID as nvarchar(128)) + '].[EDDSDBO].[Document] ed ' + @NewLine +
'where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106)) ; ' + @NewLine + @NewLine
FROM edds.eddsdbo.[Case]
WHERE name like '%Review%'
-- for testing/validating all the rows
SELECT * FROM #DynamicSQLPerLoop
-- need to initalize ID to start on, could default to 1, but if no recordsd found would try to do loop and error out
SELECT @IdOnFromLoop = MIN(ID)
FROM #DynamicSQLPerLoop
-- now we just loop through all the records, until no more are found
WHILE @IdOnFromLoop IS NOT NULL
BEGIN
-- need to get dynamic SQL statement to execute for the loop we are on now
SELECT @DynamicSQLFromLoop = DynamicSQL
FROM #DynamicSQLPerLoop
WHERE ID = @IdOnFromLoop
-- now we insert the data into our table by executing the dynamic SQL
INSERT INTO #DatabaseSizes (
fileSize,
extractedTextSize
)
EXEC sys.sp_executesql @DynamicSQLFromLoop
-- now we get the ID that is one higher than the one we just did, and if none found will exit loop
SELECT @IdOnFromLoop = MIN(ID)
FROM #DynamicSQLPerLoop
WHERE ID > @IdOnFromLoop
END -- end looping
SELECT *
FROM #DatabaseSizes
我post又问了一个问题
但事实证明,我的问题的第一个修复更简单,我将设置我的计数放在错误的位置进行迭代。 真正的问题是,当我尝试迭代时,我构造数据库名称的值是错误的。
这是 Stack Overflow 上一位友好人士更正的代码,他们通知我 post 第二个问题,以澄清声明格式不正确的问题。
主要问题涉及这一行 [EDDS'+cast(@databasename as nvarchar(128))+'].[EDDSDBO].[文档]
--check if the #databases table is already present and then drop it
IF OBJECT_ID('tempdb..#databases', 'U') IS NOT NULL
drop table #databases;
--create the temp table as outside the loop
create table #databases(
ID INT IDENTITY,
ArtifactID VARCHAR(20) -- not sure of this ID's data type
)
--check if your temp table exists and drop if necessary
IF OBJECT_ID('tempdb..#temptable', 'U') IS NOT NULL
drop table #temptable;
--create the temp table as outside the loop
create table #temptable(
fileSize dec,
extractedTextSize dec
)
--this will allow the population of each database name
DECLARE @databasename sysname = ''
-- initialze to 1 so it matches first record in temp table
DECLARE @LoopOn int = 1;
--this will be the max count from table
DECLARE @MaxCount int = 0;
--Once this first statement has been run there will now be a number column
that is associated with the artificatID. Each database has an area that is
-- titled [EDDS'artifactID']. So if the artifactID = 1111111 then the
DB would be accessed at [EDDS1111111]
-- do insert here so it adds the ID column
INSERT INTO #databases(
ArtifactID
)
SELECT ArtifactID
FROM edds.eddsdbo.[Case]
where name like '%Review%'
-- sets the max number of loops we are going to do
select @MaxCount = COUNT(*)
FROM #databases;
while @LoopOn <= @MaxCount
BEGIN
-- your table has IDENTITY so select the one for the loop your on
(initalize to 1)
select @databasename = ArtifactID
FROM #databases
WHERE ID = @LoopOn;
--generate your sql using the @databasename variable, if you want
to make
--the database and table names dynamic too then you can use the
same formula
insert into #temptable
select SUM(fileSize)/1024/1024/1024,
SUM(extractedTextSize)/1024/1024
-- dont know/think this will work like this? If not you have to
use dynamic SQL
FROM [EDDS'+cast(@databasename as nvarchar(128))+'].[EDDSDBO].
[Document] ed
where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106))
-- remove all deletes/etc and just add one to the @LoopOn and it will be selected above based off the ID
select @LoopOn += 1
end
-- Query the final values in the temp table after the iteration is complete
select filesize+extractedTextSize as Gigs
FROM #temptable
我收到一个错误
Invalid object name 'EDDS'+cast(@databasename as nvarchar(128))+'.EDDSDBO.Document'
如果我手动输入 EDDS1111111.EDDSDBO.Document
它工作正常。
如果我设置 declare @databasename nvarchar(128) = 1111111
它也会破坏代码。
我认为该错误与我如何转换它或将其添加到语句中有关。
感谢您提供的任何帮助
您不能构建 SQL 并像上面那样执行,否则会出现您看到的错误,您需要使整个语句动态化。下面是 2 种不同的解决方案,具体取决于 size/complexity(如果您没有 post 完整代码)。
这将解决您的问题并为 table 中的每一行创建动态 SQL。
我将其更新为有 2 个解决方案,一个是如果您没有很多行来执行动态 SQL,另一个是如果您有复杂或很多 运行在。
第二个解决方案可以针对您的特定场景使用更少的代码进行精简,但是按照我下面的方式进行操作,只需更改 SQL 和 temp table你的插入是为了你的结果。
我自己用一些基本的 sql table 测试了这个,两个版本都运行良好。 尽管我没有像您那样进行计算,但根据您 table 中的数据,您的计算 and/or 您的实际选择可能需要更新,因为我无法访问您的实际 data/tables测试。
我还有几行用于测试,你显然可以把它们去掉。
-- this is used to add line breaks to make code easier to read
DECLARE @NewLine AS NVARCHAR(MAX) = CHAR(10)
-- to hold your dynamic SQL for all rows/inserts at once
DECLARE @sql NVARCHAR(MAX) = N'';
-- create temp table to insert your dynamic SQL results into
IF OBJECT_ID('tempdb..#DatabaseSizes', 'U') IS NOT NULL
DROP TABLE #DatabaseSizes;
create table #DatabaseSizes(
fileSize DECIMAL,
extractedTextSize DECIMAL
)
SELECT @sql = @sql + N'' +
'select SUM(fileSize)/1024/1024/1024 as fileSize, SUM(extractedTextSize)/1024/1024 as extractedTextSize ' + @NewLine +
'FROM [EDDS' + CAST(ArtifactID as nvarchar(128)) + '].[EDDSDBO].[Document] ed ' + @NewLine +
'where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106)) ; ' + @NewLine + @NewLine
FROM edds.eddsdbo.[Case]
WHERE name like '%Review%'
-- for testing/validating
PRINT @sql
INSERT INTO #DatabaseSizes (
fileSize,
extractedTextSize
)
-- executes all the dynamic SQL we just generated
EXEC sys.sp_executesql @SQL;
SELECT *
FROM #DatabaseSizes
-- &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
-- for solution with a LOT of records from your table that is too large or complex to execute all at once using the above
-- this will generate seperate dynamic SQL for each row in your table
-- &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
DECLARE @NewLine AS NVARCHAR(MAX) = CHAR(10)
DECLARE @IdOnFromLoop INT
DECLARE @DynamicSQLFromLoop NVARCHAR(MAX)
-- table to insert data into that our dynamic SQL creates
IF OBJECT_ID('tempdb..#DatabaseSizes', 'U') IS NOT NULL
DROP TABLE #DatabaseSizes;
create table #DatabaseSizes(
fileSize DECIMAL,
extractedTextSize DECIMAL
)
-- this is to hold each rows dynamic SQL so we can loop through them and execute each statement one at a time
IF OBJECT_ID('tempdb..#DynamicSQLPerLoop', 'U') IS NOT NULL
DROP TABLE #DynamicSQLPerLoop;
create table #DynamicSQLPerLoop(
ID INT IDENTITY,
DynamicSQL NVARCHAR(MAX)
)
-- here we build our our dynamic SQL we want for each row in the table to be executed
INSERT INTO #DynamicSQLPerLoop (
DynamicSQL
)
SELECT 'select SUM(fileSize)/1024/1024/1024 as fileSize, SUM(extractedTextSize)/1024/1024 as extractedTextSize ' + @NewLine +
'FROM [EDDS' + CAST(ArtifactID as nvarchar(128)) + '].[EDDSDBO].[Document] ed ' + @NewLine +
'where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106)) ; ' + @NewLine + @NewLine
FROM edds.eddsdbo.[Case]
WHERE name like '%Review%'
-- for testing/validating all the rows
SELECT * FROM #DynamicSQLPerLoop
-- need to initalize ID to start on, could default to 1, but if no recordsd found would try to do loop and error out
SELECT @IdOnFromLoop = MIN(ID)
FROM #DynamicSQLPerLoop
-- now we just loop through all the records, until no more are found
WHILE @IdOnFromLoop IS NOT NULL
BEGIN
-- need to get dynamic SQL statement to execute for the loop we are on now
SELECT @DynamicSQLFromLoop = DynamicSQL
FROM #DynamicSQLPerLoop
WHERE ID = @IdOnFromLoop
-- now we insert the data into our table by executing the dynamic SQL
INSERT INTO #DatabaseSizes (
fileSize,
extractedTextSize
)
EXEC sys.sp_executesql @DynamicSQLFromLoop
-- now we get the ID that is one higher than the one we just did, and if none found will exit loop
SELECT @IdOnFromLoop = MIN(ID)
FROM #DynamicSQLPerLoop
WHERE ID > @IdOnFromLoop
END -- end looping
SELECT *
FROM #DatabaseSizes