"Invalid column name x" 和 "There is already an object named 'x' in the database"

"Invalid column name x" and "There is already an object named 'x' in the database"

我正在使用 Swagger API v1 OAS3 使用 T-SQL 在 SSMS v15.0.18386 中执行存储过程。然而,奇怪的是,即使我在我的服务器响应中收到一条错误消息,直接通过我的 Swagger UI 执行它仍然有效并给我预期的结果。我认为这与我创建和删除临时 table 的方式以及在删除它之前为每个临时 table 创建一个新列的方式有关。我只想忽略错误消息,但我认为它导致我的前端拒绝使其工作。

我通过 Swagger 从服务器收到的错误消息:

Microsoft.Data.SqlClient.SqlException (0x80131904):
Invalid column name 'Category'.
Invalid column name 'Category'.
Invalid column name 'Category'.
Invalid column name 'Category'.
There is already an object named 'rscopy' in the database.

at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction) at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method) at Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName)
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, IEnumerable1 parameters) at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlRaw(DatabaseFacade databaseFacade, String sql, Object[] parameters) at API.Controllers.CruiseLineController.CopyShip(Int32 shipId, String newShipName, String newShipCode) in CLController.cs:line 87 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context) Error Number:207,State:1,Class:16

我的T-SQL代码:

ALTER PROCEDURE [dbo].[CopyShip]
    (@ShipId int,
     @ShipName nvarchar(150),
     @ShipCode nvarchar(8))
AS
BEGIN
    SET NOCOUNT ON

    DECLARE @CruiselineId int, @NewShipId int;

    SET @CruiselineId = (SELECT [CruiselineId] FROM [dbo].Ships 
                         WHERE ShipId = @ShipId);

    ---- CREATING COPY OF Ships
    SELECT * 
    INTO shicopy
    FROM [dbo].Ships 
    WHERE ShipId = @ShipId

    UPDATE shicopy SET [Name] = @ShipName
    UPDATE shicopy SET [ShipCode] = @ShipCode

    INSERT INTO Ships 
        SELECT
            [CruiselineId], [Name], [ShipCode], [ClassId],
            [guestNumber], [staffNumber], [creationYear],
            [weight], [length], [passagerDeck], [handicapCabins],
            [nationality]
        FROM shicopy

    DROP TABLE shicopy;

    -- Declaring a new int variable and setting its value to be 
    -- the highest number in the ShipId column of the Ships 
    -- table (a.k.a. the new ShipId of the newly created Ship).
    
    --DECLARE @NewShipId int;
    SET @NewShipId = (SELECT MAX(ShipId) FROM [dbo].[Ships]);

    -- CREATING COPY OF Cabins
    SELECT * 
    INTO cccopy
    FROM [dbo].CabinCategory 
    WHERE ShipId = @ShipId

    UPDATE cccopy SET ShipId = @NewShipId

    INSERT INTO CabinCategory 
        SELECT
            [ShipId], [CabinType], [BalconySize], [MinSize], [MaxSize],
            [NoOfBeds], [Category], [HexCodes], [Description],
            [LongDescription], [LongDescriptonSE], [LongDescriptionNO],
            [HeaderDescriptionSE], [HeaderDescriptionNO],
            [FreeTextField], [FreeTextFieldSE], [FreeTextFieldNO],
            [CabinCategoryIdOld]
        FROM cccopy

    DROP TABLE cccopy;

    -- CREATING COPY OF BENEFITS
    SELECT * 
    INTO cbcopy
    FROM [dbo].[CabinToBenefits] 
    WHERE ShipId = @ShipId

    UPDATE cbcopy SET ShipId = @NewShipId

    ALTER TABLE cbcopy
        ADD Category nvarchar(255);

    EXEC (
    'Update B 
    set
    B.[Category] = bse.[Category]
    from dbo.[cbcopy] B 
    Inner join 
    dbo.CabinCategory bse on B.CabinCategoryId = BSE.CabinCategoryId

    Update B 
    set
    B.CabinCategoryId = bse.CabinCategoryId 
    from dbo.cbcopy B 
    Inner join 
    dbo.CabinCategory bse on B.Category = BSE.Category and B.ShipId = BSE.ShipId'
    )

    INSERT INTO CabinToBenefits
    SELECT [BenefitsId]
      ,[CabinCategoryId]
      ,[ShipId] FROM cbcopy

    DROP TABLE cbcopy;

...
...

---- CREATING COPY OF RestaurantToSeating

    Select * into rscopy
    FROM [dbo].[RestaurantToSeating] where ShipId = @ShipId

    update rscopy set ShipId = @NewShipId

    ALTER TABLE rscopy
    ADD Category nvarchar(255);

    EXEC (
    'Update B 
    set
    B.[Category] = bse.[Category]
    from dbo.rscopy B 
    Inner join 
    dbo.Restaurant bse on B.RestaurantId = BSE.RestaurantId

    Update B 
    set
    B.RestaurantId = bse.RestaurantId
    from dbo.rscopy B 
    Inner join 
    dbo.Restaurant bse on B.Category = BSE.Category and B.ShipId = BSE.ShipId'
    )


    INSERT INTO RestaurantToSeating
    SELECT [RestaurantId]
      ,[SeatingId]
      ,[ShipID] FROM rscopy

    DROP TABLE rscopy;
END

如您所见,除了错误消息 ('rscopy') 中提到的代码之外,我使用相同的代码创建其他临时 table,但它是唯一带下划线的代码作为一个错误。也许是因为它是我在存储过程中创建的最后一个临时 table(具有多对多变量)?

无论哪种方式,鉴于我所拥有的,我不太明白为什么我的代码会导致我出现这个错误 - 特别是当我通过我的 API UI 执行它时它实际上起作用了.

有什么想法吗?

如评论中所述,rscopy 和添加列不是必需的。您的“创建副本”代码块,可以替换为以下

---- CREATING COPY OF RestaurantToSeating

insert into RestaurantToSeating (ShipId, RestaurantId, SeatingId )
select ShipId       = @NewShipId,
       RestaurantId = bse.RestaurantId,
       SeatingId    = rs.SeatingId 
from   RestaurantToSeating rs
       inner join dbo.Restaurant r   on rs.RestaurantId = r.RestaurantId 
       inner join dbo.Restaurant bse on r.Category      = bse.Category 
                                    and rs.ShipId       = bse.ShipId
where  rs.ShipId = @ShipId

不要复制到临时文件中 table 之后才删除它。直接从原文插入即可。

还有:

  • 不要使用 SELECT MAX 滚动您自己的 IDENTITY 专栏。使用适当的 IDENTITY 列并使用 OUTPUTSCOPE_IDENTITY().
  • 获取先前的值
  • 不要在不需要时用 [] 引用每个列名。我没有费心删除它们,因为我一整天都没有。
  • 我必须说,我不清楚为什么你有这些连接,它们似乎不是必需的,但我已经把它们留在里面了。
CREATE OR ALTER PROCEDURE [dbo].[CopyShip]
     @ShipId int,
     @ShipName nvarchar(150),
     @ShipCode nvarchar(8)
AS

SET NOCOUNT ON;

INSERT INTO Ships (
  [CruiselineId], [Name], [ShipCode], [ClassId],
  [guestNumber], [staffNumber], [creationYear],
  [weight], [length], [passagerDeck], [handicapCabins], [nationality]
)
SELECT
  [CruiselineId], @ShipName, @ShipCode, [ClassId],
  [guestNumber], [staffNumber], [creationYear],
  [weight], [length], [passagerDeck], [handicapCabins], [nationality]
FROM [dbo].Ships 
WHERE ShipId = @ShipId;

DECLARE @NewShipId int = SCOPE_IDENTITY();

-- CREATING COPY OF Cabins
INSERT INTO CabinCategory (
  [ShipId], [CabinType], [BalconySize], [MinSize], [MaxSize],
  [NoOfBeds], [Category], [HexCodes], [Description],
  [LongDescription], [LongDescriptonSE], [LongDescriptionNO],
  [HeaderDescriptionSE], [HeaderDescriptionNO],
  [FreeTextField], [FreeTextFieldSE], [FreeTextFieldNO], [CabinCategoryIdOld]
)
SELECT
  @NewShipId, [CabinType], [BalconySize], [MinSize], [MaxSize],
  [NoOfBeds], [Category], [HexCodes], [Description],
  [LongDescription], [LongDescriptonSE], [LongDescriptionNO],
  [HeaderDescriptionSE], [HeaderDescriptionNO],
  [FreeTextField], [FreeTextFieldSE], [FreeTextFieldNO],
  [CabinCategoryIdOld]
FROM [dbo].CabinCategory cc
WHERE ShipId = @ShipId;


INSERT INTO CabinToBenefits (
  [BenefitsId]
 ,[CabinCategoryId]
 ,[ShipId]
)
SELECT B.[BenefitsId]
      ,bse2.CabinCategoryId
      ,@NewShipId
FROM [dbo].[CabinToBenefits] B
JOIN dbo.CabinCategory bse on B.CabinCategoryId = bse.CabinCategoryId
JOIN dbo.CabinCategory bse2 on bse2.[Category] = bse.Category and B.ShipId = bse2.ShipId
WHERE ShipId = @ShipId;

---- CREATING COPY OF RestaurantToSeating
INSERT INTO RestaurantToSeating (
  ShipId,
  RestaurantId,
  SeatingId
)
SELECT @NewShipId,
       bse.RestaurantId,
       rs.SeatingId 
FROM RestaurantToSeating rs
JOIN dbo.Restaurant r on rs.RestaurantId = r.RestaurantId 
JOIN dbo.Restaurant bse on r.Category = bse.Category and rs.ShipId = bse.ShipId
where rs.ShipId = @ShipId;