Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Контекст временной таблицы  [new]
a_voronin
Member

Откуда: Москва
Сообщений: 4902
Столкнулся со странной ситуацией

Есть процедуры FILL_A и FILL_B

Примерно такой код

CREATE PROCEDURE FILL_A AS
....
SELECT ...
INTO #T 
FROM ....

INSERT INTO A...
SELECT ... FROM #T 

EXEC FILL_B


CREATE PROCEDURE FILL_B AS
....
SELECT ...
INTO #T 
FROM ....

INSERT INTO B...
SELECT ... FROM #T 


EXEC FILL_A падает по ошибке

Msg 213, Level 16, State 1, ..., Line 69
Column name or number of supplied values does not match table definition.

Это запрос

INSERT INTO B...
SELECT ... FROM #T 

в процедуре FILL_B

1) Поля совпадают
2) Код
SELECT ...
INTO #T 
FROM ....

INSERT INTO B...
SELECT ... FROM #T 
отдельно выполняется без ошибок
3) EXEC FILL_B выполняется без ошибок
4) EXEC FILL_A падает
5) Добавление
IF OBJECT_ID('tempdb..#T') IS NOT NULL 
DROP TABLE #T;
не помогло

Ошибку удалось устранить используя другое имя временной таблицы в FILL_B

Вопрос почему использованием временной таблицы с ОДНОЙ решеткой в вызывающей процедуре и вызываемой процедуре дало ошибку.

SQL 2014
18 сен 14, 15:42    [16591263]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
Glory
Member

Откуда:
Сообщений: 104751
BOL - CREATE TABLE - Temporary tables

...
A local temporary table created within a stored procedure or trigger can have the same name as a temporary table that was created before the stored procedure or trigger is called.....
18 сен 14, 15:54    [16591370]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
a_voronin
Member

Откуда: Москва
Сообщений: 4902
Glory
BOL - CREATE TABLE - Temporary tables

...
A local temporary table created within a stored procedure or trigger can have the same name as a temporary table that was created before the stored procedure or trigger is called.....


Вот и я думал, что так. Выполните вот это

DROP PROCEDURE dbo.Test1
DROP PROCEDURE dbo.Test2
DROP TABLE #T
GO 
CREATE PROCEDURE dbo.Test2
AS
    CREATE TABLE #t(y int NOT NULL, x CHAR(1) PRIMARY KEY);
    INSERT INTO #t VALUES (2, '2');
    SELECT Test2Col = x FROM #t;
GO

CREATE PROCEDURE dbo.Test1
AS
    CREATE TABLE #t(x INT PRIMARY KEY);
    INSERT INTO #t VALUES (1);
    SELECT Test1Col = x FROM #t;
EXEC Test2;
GO

CREATE TABLE #t(x INT PRIMARY KEY);
INSERT INTO #t VALUES (99);
GO

EXEC Test1;
GO
18 сен 14, 15:59    [16591411]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
a_voronin
Member

Откуда: Москва
Сообщений: 4902
(1 row(s) affected)

(1 row(s) affected)

(1 row(s) affected)
Msg 213, Level 16, State 1, Procedure Test2, Line 4
Column name or number of supplied values does not match table definition.
18 сен 14, 15:59    [16591413]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
daw
Member

Откуда: Муром -> Москва
Сообщений: 7381
a_voronin,

временные таблицы видимы во всех внутренних (для контекста, в котором они созданы) процедурах. это документировано.

BOL
The table can be referenced by any nested stored procedures executed by the stored procedure that created the table.


а при компиляции процедуры для тех таблиц, которые используются в процедуре и уже существуют на момент компиляции, проверяется наличие упоминаемых в процедуре столбцов. отсюда ошибка.
18 сен 14, 16:00    [16591419]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
a_voronin
Member

Откуда: Москва
Сообщений: 4902
a_voronin,
Вот в чём дело

A local temporary table created within a stored procedure or trigger can have the same name as a temporary table that was created before the stored procedure or trigger is called. However, if a query references a temporary table and two temporary tables with the same name exist at that time, it is not defined which table the query is resolved against. Nested stored procedures can also create temporary tables with the same name as a temporary table that was created by the stored procedure that called it. However, for modifications to resolve to the table that was created in the nested procedure, the table must have the same structure, with the same column names, as the table created in the calling procedure. This is shown in the following example.
18 сен 14, 16:01    [16591434]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
daw
Member

Откуда: Муром -> Москва
Сообщений: 7381
> Вот и я думал, что так. Выполните вот это

при компиляции сервер еще не знает о временной таблице с таким же именем, которая создается внутри процедуры (она же еще не создана на этот момент) и считает, что обращение идет к уже созданной вовне.
18 сен 14, 16:04    [16591451]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
a_voronin
Member

Откуда: Москва
Сообщений: 4902
daw,

Остаётся открытым вопрос, почему

IF OBJECT_ID('tempdb..#T') IS NOT NULL 
DROP TABLE #T;


не помогает?
18 сен 14, 16:11    [16591489]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
Glory
Member

Откуда:
Сообщений: 104751
a_voronin
Вот и я думал, что так

Это начало абзаца, который надо прочитать
18 сен 14, 16:12    [16591495]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
Кот Матроскин
Member

Откуда: Москва
Сообщений: 8933
a_voronin
Остаётся открытым вопрос, почему

IF OBJECT_ID('tempdb..#T') IS NOT NULL 
DROP TABLE #T;


не помогает?


Потому что этот код не выполняется.
18 сен 14, 16:19    [16591541]     Ответить | Цитировать Сообщить модератору
 Re: Контекст временной таблицы  [new]
daw
Member

Откуда: Муром -> Москва
Сообщений: 7381
a_voronin
daw,

Остаётся открытым вопрос, почему

IF OBJECT_ID('tempdb..#T') IS NOT NULL 
DROP TABLE #T;


не помогает?


ну, почему же не помогает, помогает:

DROP PROCEDURE dbo.Test1
DROP PROCEDURE dbo.Test2
--DROP TABLE #T
GO 
CREATE PROCEDURE dbo.Test2
AS
    CREATE TABLE #t(y int NOT NULL, x CHAR(1) PRIMARY KEY);
    INSERT INTO #t VALUES (2, '2');
    SELECT Test2Col = x FROM #t;
GO

CREATE PROCEDURE dbo.Test1
AS
    CREATE TABLE #t(x INT PRIMARY KEY);
    INSERT INTO #t VALUES (1);
    SELECT Test1Col = x FROM #t;
    
    IF OBJECT_ID('tempdb..#T') IS NOT NULL 
    DROP TABLE #t;

    EXEC Test2;
GO

--CREATE TABLE #t(x INT PRIMARY KEY);
--INSERT INTO #t VALUES (99);
--GO

--exec Test2;
EXEC Test1;
GO


не помогает, если внутри Test2 его поставить. потому что наличие столбцов проверяется _при компиляции_ процедуры. до ее выполнения еще дело не доходит.

кстати, если раскомментировать exec Test2 перед exec Test1, то все тоже будет работать. :) потому как, к тому времени, когда подойдет черед исполняться Test2 внутри Test1, она уже будет откомпилирована.
18 сен 14, 16:23    [16591555]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить