Czy CREATE TABLE SomeSchema. # TempTableName ma błąd?

12

Proste łóżko testowe:

USE tempdb;
GO

/*
    This DROP TABLE should not be necessary, since the DROP SCHEMA
    should drop the table if it is contained within the schema, as
    I'd expect it to be.
*/
IF COALESCE(OBJECT_ID('tempdb..#MyTempTable'), 0) <> 0 
    DROP TABLE #MyTempTable;

IF EXISTS (SELECT 1 FROM sys.schemas s WHERE s.name = 'SomeSchema') 
    DROP SCHEMA SomeSchema;
GO

CREATE SCHEMA SomeSchema AUTHORIZATION [dbo]
CREATE TABLE SomeSchema.#MyTempTable /* specifying the schema
                                        should not be necesssary since
                                        this statement is executed inside
                                        the context of the CREATE SCHEMA
                                        statement
                                     */
(
    TempTableID INT NOT NULL IDENTITY(1,1)
    , SomeData VARCHAR(50) NOT NULL
);
GO

INSERT INTO tempdb.SomeSchema.#MyTempTable (SomeData) VALUES ('This is a test');

SELECT *
FROM tempdb.SomeSchema.#MyTempTable;
GO

SELECT *
FROM sys.objects o
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE s.name = 'SomeSchema';

SELECT s.name
    , o.name
FROM sys.objects o
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE s.name = 'dbo'
    AND o.name LIKE '%MyTempTable%';

DROP SCHEMA SomeSchema;
DROP TABLE #MyTempTable;

Powyższe powinno utworzyć tymczasową tabelę o nazwie #MyTempTablew tempdb w ramach schematu o nazwie SomeSchema; jednak tak nie jest. Zamiast tego tabela jest tworzona w dboschemacie.

Czy to oczekiwane zachowanie? Zdaję sobie sprawę, że jest to z pewnością przypadek skrajny związany ze stosowaniem tabel temp specyficznych dla schematu; byłoby jednak miło, gdyby silnik podał błąd podczas próby utworzenia tabeli tymczasowej powiązanej ze schematem lub faktycznie powiązał ją ze schematem określonym w DDL.

Ponadto nie mam obecnie dostępu do SQL Server 2014 lub 2016; czy działa na tych platformach zgodnie z oczekiwaniami?

Max Vernon
źródło
Zestaw szkoleniowy dla 70-461 stwierdza, że ​​„Tabele tymczasowe są tworzone w tempdb w schemacie dbo.”, Jednak nie zawiera więcej informacji, więc nie jestem pewien, czy to oznacza tylko, gdy nie określ schemat.
Mark Sinkinson

Odpowiedzi:

11

Oba odwołania są prawidłowe i zostaną poprawnie rozwiązane, ale tabela #temp jest tworzona w ramach dboschematu.

Ta sama odpowiedź (w twoim systemie, pewnej liczby, której nie mogłem odgadnąć):

SELECT OBJECT_ID('dbo.#MyTempTable');
SELECT OBJECT_ID('SomeSchema.#MyTempTable');

Ta sama odpowiedź (obie to 1 dbo):

SELECT schema_id FROM sys.tables WHERE [object_id] = OBJECT_ID('dbo.#MyTempTable');
SELECT schema_id FROM sys.tables WHERE [object_id] = OBJECT_ID('SomeSchema.#MyTempTable');

Możliwość określenia schematu nic Ci nie kupi, ponieważ nie będziesz mieć kolizji (dwie tabele #temp o tej samej nazwie w różnych schematach) w sesji, prawda?

Jest to oczekiwane zachowanie. Tabela #temp jest powiązana z sesją, ale nie z określonym schematem. I działa tak samo aż do 2016 CTP 3.2. Analizator składni prawdopodobnie wybacza, pozwalając na bezsensowną nazwę schematu w taki sam sposób, w jaki pozwala na to błędne końcowe przecinek:

CREATE TABLE dbo.foo 
(
        bar INT
        ,
);
Aaron Bertrand
źródło
Prawdopodobnie w dużej części, ponieważ tabele tymczasowe są tworzone w TempDB, a lokalny schemat nie działałby (chyba że rzeczywiście byłeś w TempDB)
Kenneth Fisher
Tak więc wyraźnie istnieje kod, który ignoruje nazwę schematu podczas tworzenia tabeli tymczasowej; i ten kod milczy.
Max Vernon