Вот почему вы всегда должны объявлять свои столбцы как в INSERT
, так и SELECT
.
Измените их оба, чтобы объявить все столбцы, которые вы вставляете и выбираете, поэтому ваше утверждение выглядит примерно так:
INSERT INTO dbo.unactionedautotraders (code, Ref, contacted, DaySS)
SELECT C.code, P.Ref, C.contacted, P.DaySS
FROM dbo.autotr_2menl P
LEFT JOIN Customers C ON P.Ref = C.Code
WHERE C.contacted IS NULL
AND P.DaySS >= 1; --Not sure why this was a varchar?
Также настоятельно рекомендуется никогда не использовать *
впостоянный объект. Когда вы используете SELECT *
в VIEW
, SQL Server будет «преобразовывать» его в текущий список столбцов в объекте в тот момент, а не при запуске VIEW
. Поэтому, если вы добавите больше столбцов в таблицу, они будут , а не . Пример:
USE Sandbox;
GO
CREATE TABLE dbo.YourTable (ID int,
MyColumn varchar(10));
INSERT INTO dbo.YourTable (ID,
MyColumn)
VALUES(1,'Test')
GO
CREATE VIEW dbo.YourView AS
SELECT *
FROM dbo.YourTable
GO
SELECT * --Returns both columns
FROM dbo.YourView;
GO
--Add a new column
ALTER TABLE dbo.YourTable ADD MyDate date;
GO
INSERT INTO dbo.YourTable (ID,
MyColumn,
MyDate)
VALUES(2,'Test',GETDATE());
GO
SELECT * --Returns only ID and MyColumn, not MyDate
FROM dbo.YourView;
GO
--This will error
SELECT ID,
MyColumn,
MyDate
FROM dbo.YourView;
Это поведение не реплицируется с SP.
CREATE PROC dbo.YourProc @ID int
AS BEGIN
SELECT *
FROM dbo.YourTable
WHERE ID = @ID
END;
GO
EXEC dbo.YourProc @ID = 2; --Returns 3 columns
GO
ALTER TABLE dbo.YourTable ADD MyInteger int;
GO
INSERT INTO dbo.YourTable (ID,
MyColumn,
MyDate,
MyInteger)
VALUES(3,'Test',GETDATE(),12);
GO
EXEC dbo.YourProc @ID = 3; --Returns 4 columns
Это не меняет мою рекомендацию. На самом деле, я подчеркиваю это больше, так как , если вы должны были вставить данные в другую таблицу (как вы здесь), изменение исходной или целевой таблиц сломает ваш SP (возможно, это то, что здесь произошло):
CREATE TABLE dbo.MyTable (ID int,
MyColumn varchar(10),
MyDate date,
MyInteger int);
GO
CREATE PROC dbo.InsertProc @ID int
AS BEGIN
INSERT INTO dbo.MyTable
SELECT *
FROM dbo.YourTable
WHERE ID = @ID;
END;
GO
EXEC dbo.InsertProc @ID = 3; --works
GO
ALTER TABLE dbo.MyTable ADD MyTime time(0);
GO
EXEC dbo.InsertProc @ID = 1; --fails;
GO
--Undo and change your table instead
ALTER TABLE dbo.MyTable DROP COLUMN MyTime;
GO
ALTER TABLE dbo.YourTable ADD MyDecimal decimal (10,2);
GO
EXEC dbo.InsertProc @ID = 2; --fails;
GO
SELECT * --Just 1 row
FROM dbo.MyTable;
Однако, как вы можете видеть, если мы правильно объявим наши столбцы (как в INSERT
, так и в SELECT
), то эта проблема не возникнет:
--Change proc to have column names
ALTER PROC dbo.InsertProc @ID int
AS BEGIN
INSERT INTO dbo.MyTable (ID,MyColumn)
SELECT ID, MyColumn
FROM dbo.YourTable
WHERE ID = @ID;
END;
GO
EXEC dbo.InsertProc @ID = 2; --works;
GO
--Add a column to MyTable
ALTER TABLE dbo.MyTable ADD MyTime time(0);
GO
EXEC dbo.InsertProc @ID = 1; --still works;
GO
ALTER TABLE dbo.YourTable ADD MyBinary varbinary(10);
GO
EXEC dbo.InsertProc @ID = 4; --still works, inserts no data as no ID 4
GO
SELECT * --3 rows (some have NULLs)
FROM dbo.MyTable;
GO
--Clean up
DROP PROC dbo.InsertProc;
DROP TABLE dbo.MyTable;
DROP PROC dbo.YourProc;
DROP VIEW dbo.YourView;
DROP TABLE dbo.YourTable;
Нет DB Fiddle, поскольку, к сожалению, они не повторяют истинное поведение.