首页 > 解决方案 > 临时表的列名无效

问题描述

我想创建一个将数据插入多个表的过程。我需要获取插入的 ID,因此我创建了捕获它们的临时表。问题是我收到错误“无效的列名'app_guid'”和“无效的列名'app_nazwa_pliku'”,但我用这些列创建了临时表。你碰巧知道我的代码有什么问题吗?

create procedure p_paseczek_przenies
as

declare @new_nr_sprawy varchar(50)

if object_id('tempdb..##paseczki') is not null drop table ##paseczki

select 
top 1 with ties
s.sp_numer as SprawaGlowna_sp_numer,
s.sp_id as SprawaGlowna_sp_id
,Paseczek.max_ak_id as Paseczek_max_ak_id
,apisp_data_przyjscia
,app_guid
,app_nazwa_pliku

into ##paseczki

from sprawa as s
join akcja as a on a.ak_sp_id=s.sp_id and ak_akt_id=111
join sprawa_powiazania as sp on s.sp_id=sp.sp_id and rodzaj_powiazania='SPRAWY POLUBOWNE'
join (select max(ak_id) max_ak_id,ak_sp_id from akcja 
where ak_akt_id=1089 
group by ak_sp_id) as Paseczek on Paseczek.ak_sp_id=sp.sp_id_powiazana
join akcja_pismo on apis_ak_id=max_ak_id
join akcja_pismo_przychodzace on apis_apisp_id=apisp_id
join akcja_pismo_plik on app_apis_id=apis_id
where s.sp_numer=@new_nr_sprawy
order by ROW_NUMBER() over (partition by s.sp_id order by paseczek.max_ak_id desc)

if exists (select * from ##paseczki) 

begin

    if object_id('tempdb..##akcja') is not null drop table ##akcja

    create table ##akcja (
    ak_id int
    ,apisp_data_przyjscia datetime
    ,app_guid varchar(max)
    ,app_nazwa_pliku varchar(max)
    )

    merge akcja as target using (
    select * from ##paseczki) as source on 1=0
    when not matched then insert
    (ak_akt_id, ak_sp_id, ak_kolejnosc, ak_interwal, ak_zakonczono, ak_pr_id, ak_publiczna) 
    values (1089,SprawaGlowna_sp_id,1,1,getdate(),5,1)
    output inserted.ak_id,source.apisp_data_przyjscia,source.app_guid,source.app_nazwa_pliku
    into ##akcja;

    insert into rezultat
    (re_ak_id, re_ret_id, re_data_planowana, re_us_id_planujacy, re_data_wykonania, re_us_id_wykonujacy, re_konczy)
    select ak_id,309,getdate(),5,getdate(),5,1 from ##akcja

    if object_id('tempdb..##akcja_pismo_przychodzace') is not null drop table ##akcja_pismo_przychodzace

    create table ##akcja_pismo_przychodzace (
    apisp_id int
    ,ak_id int
    ,app_guid varchar(max)
    ,app_nazwa_pliku varchar(max)
    )

    merge akcja_pismo_przychodzace as target using (
    select * from ##akcja) as source on 1=0
    when not matched then insert
    (apisp_data_przyjscia)
    values (apisp_data_przyjscia)
    output inserted.apisp_id,source.ak_id,source.app_guid,source.app_nazwa_pliku
    into ##akcja_pismo_przychodzace;

    if object_id('tempdb..##akcja_pismo') is not null drop table ##akcja_pismo

    create table ##akcja_pismo (
    apis_id int
    ,app_guid varchar(max)
    ,app_nazwa_pliku varchar(max)
    )

    merge akcja_pismo as target using (
    select * from ##akcja_pismo_przychodzace) as source on 1=0
    when not matched then insert
    (apis_ak_id, apis_apisp_id, apis_data_stworzenia,[apis_us_id_tworzacy])
    values (ak_id,apisp_id,getdate(),5)
    output inserted.apis_id,source.app_guid,source.app_nazwa_pliku
    into ##akcja_pismo;

    alter table [dm_data_bps].[dbo].[akcja_pismo_plik] disable trigger [tr_akcja_pismo_plik_ins]

    insert into akcja_pismo_plik
    ([app_guid],[app_apis_id],[app_nazwa_pliku])
    select [app_guid],[apis_id],[app_nazwa_pliku] from ##akcja_pismo

    alter table [dm_data_bps].[dbo].[akcja_pismo_plik] enable trigger [tr_akcja_pismo_plik_ins]
end

标签: tsql

解决方案


SQL Server 在创建过程和首次执行时编译过程,并根据当时的上下文验证整个过程。

例如,尝试以下查询:

CREATE PROCEDURE P
AS
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T
SELECT 1 Y INTO #T
SELECT Y FROM #T

GO
CREATE TABLE #T (X INT)

GO
EXEC P

你会得到一个错误(“无效的列名'Y'。”),因为当编译过程时,表#T只有列X。

为避免此问题,您应该在执行过程之前确保表#T 不存在或具有正确的列。

一种方法是使用另一个存储过程(包装器):

CREATE PROCEDURE P1
AS
SELECT 1 Y INTO #T
SELECT Y FROM #T

GO
CREATE PROCEDURE P2
AS
IF OBJECT_ID('tempdb..#T') IS NOT NULL DROP TABLE #T
EXEC P1

GO
CREATE TABLE #T (X INT)

GO
EXEC P2

GO
DROP PROCEDURE P1, P2
--DROP TABLE #T

另一种方法是使用动态 SQL,因为该代码是单独编译的,就好像它是另一个存储过程一样。

更好的方法是确保临时表在每个存储过程中都是唯一命名的,除非需要在它们之间共享数据。对于后一种情况,您可以阅读http://www.sommarskog.se/share_data.html#temptables以获得更多见解。


推荐阅读