【问题标题】:Pulling Values From Temp Table After An Iteration迭代后从临时表中提取值
【发布时间】:2019-06-06 17:16:43
【问题描述】:

我正在查询某些数据库中最近数据的总大小。

我创建了一个包含要查询的数据库的表,然后对其进行迭代以获取数据库名称和运行迭代的总次数。

然后我创建一个临时表,将需要的数据插入其中。

我运行迭代以获取信息并将其推送到每个数据库的临时表中。

迭代完成后,我无法从这个新创建的表中提取值。

我在每个代码部分旁边写了一个小注释,解释了我正在尝试做什么以及我期望发生什么。

/*check if the #databases table is already present and then drop it*/

IF OBJECT_ID('tempdb..#databases', 'U') IS NOT NULL
begin
    drop table #databases;
end

select ArtifactID into #databases from edds.eddsdbo.[Case]
where name like '%Review%'

/*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]*/

declare @runs int = 1; /*this will track the number of times iterated 
over the result set*/

declare @max int = 0; /*this will be the limit*/

declare @databasename sysname='' /*this will allow the population of each 
database name*/

/*check if your temp table exists and drop if necessary*/
IF OBJECT_ID('tempdb..#temptable', 'U') IS NOT NULL
begin
    drop table #temptable;
end

/*create the temp table as outside the loop*/

create table #temptable(
fileSize dec,
extractedTextSize dec
)


while @runs<=@max
begin

select @max=count(*) from #databases;
/*the @max is now the number of databases inserted in to this table*/


/*This select statement pulls the information that will be placed 
into the temptable. This second statment should be inside the loop. One time 
for each DB that appeared in the first query's results.*/

/*begin the loop by assigning your database name, I don't know what the 
column is called so I have just called it databasename for now*/

select top 1 @databasename = ArtifactID from #databases;

/*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
FROM [EDDS'+cast(@databasename as nvarchar(128))+'].[EDDSDBO].[Document] ed
where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- 
(day(getdate())),getdate()),106))'


/*remove that row from the databases table so the row won't be redone
This will take the @max and lessen it by one*/
delete from #databases where ArtifactID=@databasename;

/* Once the @max is less than 1 then end the loop*/
end

/* Query the final values in the temp table after the iteration is complete*/
select filesize+extractedTextSize as Gigs from #temptable

当最后的 select 语句运行以从 #temptable 中提取值时,响应是单个 gigs 列(如预期的那样),但表本身是空白的。

发生了一些事情来清除表格中的数据,我被卡住了。

我不确定我的错误是语法错误还是一般逻辑错误,但我们将不胜感激。

【问题讨论】:

  • 除非我在运行时丢失了你所拥有的东西
  • same question单独发到多个论坛是不礼貌和浪费的。
  • @SMor3 -- 有时一个人不知道在哪里发帖
  • SQL 中的“迭代”一词通常意味着一个人正在以计算机语言程序员的身份思考{e.g. C#} 而不是 SQL 程序员;尽管有时在 SQL 中需要迭代。但是,如果可能,请避免使用它们。
  • 我接受过 JavaScript 培训,所以我的条件有点偏离。感谢您告知我有关术语和实践的信息。我可以看到它移动的速度有多慢,所以我会避免对更大的查询这样做。

标签: sql-server tsql iteration temp-tables sql-server-2017


【解决方案1】:

对格式做了一些调整,但主要问题是你的循环永远不会运行。

你有@runs

要解决这个问题,你可以做一些不同的事情,但我在循环之前设置了@max,并且在循环中只是为每个循环添加了 1 到 @runs,因为你知道在循环运行之前你需要多少 @max,并且只是将其添加到运行次数并进行比较。

但是请注意,有比您现有的方式更好的方法来做到这一点。将身份放在您的#databases 表上,并在您的循环中执行 where databaseID = loopCount (然后您不必从表中删除)

--check if the #databases table is already present and then drop it
IF OBJECT_ID('tempdb..#databases', 'U') IS NOT NULL
    drop table #databases;


--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]
select ArtifactID 
INTO #databases 
FROM edds.eddsdbo.[Case]
where name like '%Review%'


-- set to 0 to start 
DECLARE @runs int = 0; 

--this will be the limit
DECLARE @max int = 0; 

--this will allow the population of each database name
DECLARE @databasename sysname = '' 

--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
)

-- ***********************************************
--  Need to set the value your looping on before you get to your loop, also so if you dont have any you wont do your loop
-- ***********************************************      
--the @max is now the number of databases inserted in to this table
select @max = COUNT(*) 
FROM #databases;

while @runs <= @max  
    BEGIN

        /*This select statement pulls the information that will be placed 
        into the temptable. This second statment should be inside the loop. One time 
        for each DB that appeared in the first query's results.*/

        /*begin the loop by assigning your database name, I don't know what the 
        column is called so I have just called it databasename for now*/

        select top 1 @databasename = ArtifactID from #databases;

        /*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
        FROM [EDDS'+cast(@databasename as nvarchar(128))+'].[EDDSDBO].[Document] ed
        where ed.CreatedDate >= (select CONVERT(varchar,dateadd(d,- (day(getdate())),getdate()),106))


        --remove that row from the databases table so the row won't be redone This will take the @max and lessen it by one
        delete from #databases where ArtifactID=@databasename;

        --Once the @max is less than 1 then end the loop

        -- ***********************************************
        -- no need to select from the table and change your max value, just change your runs by adding one for each run
        -- ***********************************************      
        --the @max is now the number of databases inserted in to this table
        select @runs = @runs + 1  --@max=count(*) from #databases;


end

-- Query the final values in the temp table after the iteration is complete
select filesize+extractedTextSize as Gigs from #temptable

【讨论】:

  • 非常感谢!我一直在转圈,没有发现更明显的问题!现在我无法让 [EDDS'+cast(@databasename as nvarchar(128))+'] 工作。你回答了我的问题,但如果你能在这方面帮助我,你就会成为超级巨星。
  • 贴在下面,我认为这行不通,以前没看到。
  • 我找到了该问题的解决方案,但它与您的原始问题不同(并且会使发布另一个答案的问题令人困惑)因此,如果您想将其作为新问题发布,因为它不同(以我的答案为起点)我可以发布该问题的答案(只需在此处发布链接)
  • 如果您有新问题要发布答案,我为您找到了一种更简洁的方法
  • 感谢您的耐心等待,这是新问题stackoverflow.com/questions/56483520/…
【解决方案2】:

这是第二个答案,但它可以替代我在上面提到的内容,并且可以更清洁地发布以作为替代答案以保持它们分开

这是进行循环的更好方法(尚未完全测试,因此您必须进行验证)。

但不要从您的表中删除,只需向其中添加一个 ID 并使用该 ID 循环遍历它。步骤更少,更清洁。

--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

【讨论】:

  • 我也会马上研究这个解决方案!非常感谢您的建议
  • 刚刚更新了上面,有错误。也将声明移至顶部。还添加了一条评论,不确定您在循环中动态构建 FROM 的功能是否会像这样工作? 2017 年 5 月。如果没有,您必须使整个语句动态 SQL
猜你喜欢
  • 1970-01-01
  • 2020-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-17
相关资源
最近更新 更多