There is already an object named '#result'

2019-04-12 11:02发布

问题:

Alter Procedure sp_Member(
  @comcode int = 0,
  @SubComCode int = 0
)
as begin
  set nocount on
  If @comcode='0'
  begin
    select (
      select sum(amount)
        from tbcoudet
        where memcode=tbm.memcode and
              expyear=(select max(expyear) from tbexpyear)
              and exists (
                select itemcode
                from tbitem
                where comcode=@comcode and
                  SubComCode=@SubComCode and
                  itemcode=tbcoudet.itemcode
              )
        group by memcode,expyear
      )'TurnOver', *
    into #result from tbmember tbm where can_flag='N'
  end
  If @subcomcode='0'
  begin
    select (
      select sum(amount)
      from tbcoudet
      where memcode=tbm.memcode and expyear=(select max(expyear) from tbexpyear)
        and exists (
          select itemcode
          from tbitem
          where comcode=@comcode and
            itemcode=tbcoudet.itemcode
        )
      group by memcode,expyear
    )'TurnOver', *
    into #result from tbmember tbm where can_flag='N'
  end

  select top 10 * from #result where TurnOver is not null order by TurnOver desc
end

That is my sql code and when i am going to execute store procedure then I get the error

There is already an object named '#result' in the database.

Can anyone tell me what the problem is?

回答1:

The error is: there is already a temporary table by that name - don't re-create it if it already exists....

The problem lies in the way you do your select's - you have two places where you have

select (columns)
into #result 
from tbmember tbm 
...

The first time around, this will create the temporary table #result. And the second time around, you'll get the error - since it cannot create a table that already exists.

So you need to change your code to:

  • explicitly create the table #result in the beginning

    CREATE TABLE #result ( ...give list of columns and their datatypes here .....)
    
  • use code like this to insert values:

    INSERT INTO #result(colum list)
       SELECT (column list) 
       FROM  .......
       WHERE .......
    

That code will work and you will be able to insert two sets of data into your temporary table.



回答2:

If you are not sure whether temp table exists or not but you are sure that before next statement you won't need it use object_id function this way:

if object_id('tempdb..#result', 'u') is not null
    drop table #result

It will not cause an error if table doesn't exist and drop it if it does. In my opinion it's a good practice to use just before each:

select ... into #temp from ...


回答3:

SELECT ... INTO ... always wants to create a new temp table.

Instead, create the temp table at the top of the procedure (using create table #result (columns)), and then re-write your selects using INSERT INTO (columns) SELECT ... instead.

I'm unable to write out a full example, since I don't know your column definitions.

Even if, as a matter of course, only one of your if statements is true, the T-SQL parser is rather simple, and still "sees" both attempted declarations of #result.


As an aside, I'm not sure why you're writing your if statements like this:

if @subcomcode='0'

Since @subcomcode is an int, you'd be better off not quoting the 0 literal.



回答4:

Agreed it's good to drop before creating new temp tables. But a simple workaround is just to close your DB connection when debugging this type of stuff. As the disconnection - wipes all those for you.



回答5:

I have similar problem, but neither proposed solution here helps me. I have 6 ifs similar to this two in a stored procedure and it won't let me alter the procedure, which makes no sense, it clearly could work. Throws same error on alter procedure. I must have into #tbl in every if because every if has select with different columns and I don't want to make table for every select. Other option is dynamic selects...

I had to make it dynamic (not all), like this:

IF @Type = '1'
    SELECT
        col1
    INTO #tbl1
    FROM Table1
ELSE IF @Type = '2'
    SELECT
        col1
        ,col2
    INTO #tbl2
    FROM Table2
--IF...

DECLARE @sql VARCHAR(MAX) = '
    select 
        *
    from #tbl' + @Type

EXEC (@sql)

But in your case, you should create temp table manually because you are using same structure and just adding value.

If you are lazy to create temp table with all the columns, another solution would be this:

ALTER PROCEDURE sp_Member (
    @comcode INT = 0
  , @SubComCode INT = 0
  )
AS
BEGIN
  SET NOCOUNT ON

  SELECT  CONVERT(DECIMAL(18, 2), 0) TurnOver
        , *
  INTO    #result
  FROM    tbmember
  WHERE   can_flag = 'N'

  IF @comcode = '0'
  BEGIN
    UPDATE  r
    SET     TurnOver = (SELECT  SUM(amount)
                        FROM    tbcoudet
                        WHERE   memcode = r.memcode
                                AND expyear = (SELECT MAX(expyear)
                                               FROM   tbexpyear
                                              )
                                AND EXISTS ( SELECT itemcode
                                             FROM   tbitem
                                             WHERE  comcode = @comcode
                                                    AND SubComCode = @SubComCode
                                                    AND itemcode = tbcoudet.itemcode )
                        GROUP BY memcode
                              , expyear
                       )
    FROM    #result r
  END
  IF @SubComCode = '0'
  BEGIN
    UPDATE  r
    SET     TurnOver = (SELECT  SUM(amount)
                        FROM    tbcoudet
                        WHERE   memcode = r.memcode
                                AND expyear = (SELECT MAX(expyear)
                                               FROM   tbexpyear
                                              )
                                AND EXISTS ( SELECT itemcode
                                             FROM   tbitem
                                             WHERE  comcode = @comcode
                                                    AND itemcode = tbcoudet.itemcode )
                        GROUP BY memcode
                              , expyear
                       )
    FROM    #result r
  END

  SELECT TOP 10
          *
  FROM    #result
  WHERE   TurnOver IS NOT NULL
  ORDER BY TurnOver DESC
END


回答6:

You are trying to create the temporary table twice in the procedure.

In the second query don't use select ... into #result ... but rather insert into #result select ... so that it doesn't try to create it again.


Note that the prefix sp_ means System Procedure, and should not be used for regular procedures.