Jawną wartość kolumny tożsamości w tabeli można określić tylko wtedy, gdy używana jest lista kolumn, a IDENTITY_INSERT jest w programie SQL Server

187

Próbuję wykonać to zapytanie

INSERT INTO dbo.tbl_A_archive
  SELECT *
  FROM SERVER0031.DB.dbo.tbl_A

ale nawet po tym, jak pobiegłem

set identity_insert dbo.tbl_A_archive on

Otrzymuję ten komunikat o błędzie

Wyraźną wartość kolumny tożsamości w tabeli „dbo.tbl_A_archive” można określić tylko wtedy, gdy używana jest lista kolumn, a IDENTITY_INSERT jest WŁĄCZONY.

tbl_Ato ogromny stół w rzędach i szerokości, tzn. ma DUŻO kolumn. Nie chcę ręcznie wpisywać wszystkich kolumn. Jak mogę to uruchomić?

jhowe
źródło
Nawiasem mówiąc, już skonfigurowałem połączony serwer!
jhowe
4
mam również ten problem, z wyjątkiem tego, że „wstaw do X wybierz * Y” nie stanowiło problemu, dopóki nie zmieniłem schematu tabeli
FistOfFury,

Odpowiedzi:

81

Podsumowanie

SQL Server nie pozwoli ci wstawić jawnej wartości w kolumnie tożsamości, chyba że użyjesz listy kolumn. Masz zatem następujące opcje:

  1. Utwórz listę kolumn (ręcznie lub przy użyciu narzędzi, patrz poniżej)

LUB

  1. utwórz kolumnę tożsamości w tbl_A_archivezwykłej kolumnie bez tożsamości : Jeśli twoja tabela jest tabelą archiwalną i zawsze podajesz wyraźną wartość dla kolumny tożsamości, dlaczego w ogóle potrzebujesz kolumny tożsamości? Zamiast tego użyj zwykłego int.

Szczegóły dotyczące rozwiązania 1

Zamiast

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table
  SELECT *
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

musisz pisać

SET IDENTITY_INSERT archive_table ON;

INSERT INTO archive_table (field1, field2, ...)
  SELECT field1, field2, ...
  FROM source_table;

SET IDENTITY_INSERT archive_table OFF;

z field1, field2, ...zawierający nazwy wszystkich kolumn w tabelach. Jeśli chcesz automatycznie wygenerować tę listę kolumn, spójrz na odpowiedź Dave'a lub odpowiedź Andomara .


Szczegóły dotyczące rozwiązania 2

Niestety nie można po prostu „zmienić typu” kolumny int tożsamości na kolumnę int nie-tożsamości. Zasadniczo masz następujące opcje:

  • Jeśli tabela archiwum nie zawiera jeszcze danych, upuść kolumnę i dodaj nową bez tożsamości.

LUB

  • Użyj SQL Server Management Studio, aby ustawić Identity Specification/ (Is Identity)właściwość kolumny tożsamości w tabeli archiwum na No. Za kulisami stworzy to skrypt do ponownego utworzenia tabeli i skopiowania istniejących danych, więc aby to zrobić, będziesz musiał również rozbroić Tools/ Options/ Designers/ Table and Database Designers/ Prevent saving changes that require table re-creation.

LUB

Heinzi
źródło
1
Do ostatecznego rozwiązania: jeśli kolumna ma „TOŻSAMOŚĆ (1, 1)” lub coś w tym stylu, będzie musiał ją również usunąć tymczasowo.
Aleksandr Khomenko
1
@AleksandrKhomenko: Tak, właśnie to miałem na myśli przez „uczynienie [it] regularną kolumną int ( brak tożsamości )” .
Heinzi,
1
Przepraszam za zamieszanie. Miałem na myśli, że będzie musiał również usunąć właściwość automatycznego przyrostu . W przypadku SQL-Server nazywa się „TOŻSAMOŚĆ (1, 1)” - twoja odpowiedź jest absolutnie słuszna. Ale MySQL i Oracle mają inne polecenia (i staje się to nieoczywiste, spójrz na w3schools.com/sql/sql_autoincrement.asp )
Aleksandr Khomenko
2
Brakuje tego szczegółowo. Rozumiem, że dla niektórych może to być rote, ale dla innych to bzdura
DJ.
1
@DJ .: Dodałem trochę szczegółów.
Heinzi
332
SET IDENTITY_INSERT tableA ON

Musisz utworzyć listę kolumn dla instrukcji INSERT:

INSERT Into tableA ([id], [c2], [c3], [c4], [c5] ) 
SELECT [id], [c2], [c3], [c4], [c5] FROM tableB

nie tak jak „WSTAW do tabeli A WYBIERZ ........”

SET IDENTITY_INSERT tableA OFF
Ehsan
źródło
17
+1 ... Potrzebujesz tylko wyraźnych kolumn w klauzuli SELECT zapytania. Możesz zachować gwiazdkę w klauzuli INSERT zapytania
MacGyver,
8
... chyba że cel ma kolumnę tożsamości, a tabela źródłowa nie ma kolumny tożsamości
MacGyver
1
ta odpowiedź jest nieco bardziej przejrzysta niż Heinzi, ponieważ wspomina SET IDENTITY_INSERT
Marty
4
+1 Działa jak urok! Jednak „Możesz zachować gwiazdkę w klauzuli INSERT zapytania” tutaj nie będzie działać.
Shai Alon,
1
Wystąpił ten błąd, gdy kolumny w klauzuli select nie pasowały do ​​tabeli docelowej. Upewniając się o tym, wkładka zadziałała dla mnie
Jose
39

Jeśli korzystasz z SQL Server Management Studio, nie musisz sam wpisywać listy kolumn - wystarczy kliknąć tabelę prawym przyciskiem myszy w Eksploratorze obiektów i wybrać opcję Tabela skryptów jako -> WYBIERZ -> Okno nowego edytora zapytań .

Jeśli nie, to zapytanie podobne do tego powinno pomóc jako punkt wyjścia:

SELECT SUBSTRING(
    (SELECT ', ' + QUOTENAME(COLUMN_NAME)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'tbl_A'
        ORDER BY ORDINAL_POSITION
        FOR XML path('')),
    3,
    200000);
Dave Cluderay
źródło
2
Można to wybrać jako zmienną i użyć w dynamicznym zapytaniu SQL. Uratowałeś mi dzień. Wielkie dzięki!
Paweł Cioch
1
dzięki! Zrobiłem to dzięki gist.github.com/timabell/0ddd6a69565593f907c7
Tim Abell
łał. rozpaczliwie szukałem tego, aby dynamicznie budować moje zapytanie. Zaskoczony, widząc to tutaj. Dzięki stary.
Yasin Bilir,
24

Zgadzam się z odpowiedzią Heinzi. W przypadku pierwszej drugiej opcji oto zapytanie, które generuje listę kolumn oddzieloną przecinkami:

select name + ', ' as [text()] 
from sys.columns 
where object_id = object_id('YourTable') 
for xml path('')

W przypadku dużych tabel może to zaoszczędzić dużo pracy podczas pisania :)

Andomar
źródło
@Dziękuję, bardzo pomocne. :)
Chirag Thakar
Czasami potrzebujesz po prostu pragmatycznego rozwiązania. Dziękuję Ci!
Tobias Feil
15

Jeśli tabela „archiwum” ma być dokładną kopią głównej tabeli, proponuję po prostu usunąć fakt, że identyfikator jest kolumną identyczną. W ten sposób pozwoli Ci je wstawić.

Alternatywnie możesz zezwolić i zabronić wstawiania tożsamości dla tabeli za pomocą następującej instrukcji

SET IDENTITY_INSERT tbl_A_archive ON
--Your inserts here
SET IDENTITY_INSERT tbl_A_archive OFF

Na koniec, jeśli potrzebujesz kolumny tożsamości, aby działała, to zawsze możesz po prostu uruchomić zapisany proc.

sp_columns tbl_A_archive 

Spowoduje to zwrócenie wszystkich kolumn z tabeli, które można następnie wyciąć i wkleić do zapytania. (Jest to prawie ZAWSZE lepsze niż używanie *)

Robin Day
źródło
11

W przypadku instrukcji SQL należy również określić listę kolumn. Na przykład

INSERT INTO tbl (idcol1,col2) VALUES ( value1,value2)

zamiast

INSERT INTO tbl VALUES ( value1,value2)
Mohsin Mahmood
źródło
2
Nie dotyczy to oświadczenia PO. WARTOŚCI nie są wymagane, jeśli po opcji INSERT INTO następuje instrukcja SELECT. Popraw lub usuń swoją odpowiedź.
Gary
4

Oba będą działać, ale jeśli nadal występuje błąd przy użyciu # 1, przejdź do # 2

1)

SET IDENTITY_INSERT customers ON
GO
insert into dbo.tbl_A_archive(id, ...)
SELECT Id, ...
FROM SERVER0031.DB.dbo.tbl_A

2)

SET IDENTITY_INSERT customers ON
GO
insert into dbo.tbl_A_archive(id, ...)
VALUES(@Id,....)
Chirag Thakar
źródło
4
To naprawdę nie jest dobry sposób, jeśli OP wstawia wiele rekordów. Ignorujesz „tbl_A to ogromna tabela w wierszach i szerokości, tzn. Ma DUŻO kolumn. Nie chcę wpisywać wszystkich kolumn ręcznie”.
Gary,
4

Aby wprowadzić wszystkie nazwy kolumn do listy rozdzielanej przecinkami dla instrukcji Select dla rozwiązań wymienionych w tym pytaniu, korzystam z następujących opcji, ponieważ są one nieco mniej szczegółowe niż większość odpowiedzi tutaj. Chociaż większość odpowiedzi tutaj jest jednak całkowicie do zaakceptowania.

1)

SELECT column_name + ',' 
FROM   information_schema.columns 
WHERE  table_name = 'YourTable'

2) Jest to prawdopodobnie najprostsze podejście do tworzenia kolumn, jeśli masz SQL Server SSMS.

1) Przejdź do tabeli w Eksploratorze obiektów i kliknij + po lewej stronie nazwy tabeli lub kliknij dwukrotnie nazwę tabeli, aby otworzyć listę podrzędną.

2) Przeciągnij podfolder kolumn do głównego obszaru zapytań, aby automatycznie wkleić dla ciebie całą listę kolumn.

Ryan
źródło
3

Musisz podać nazwę kolumny, którą chcesz wstawić, jeśli istnieje kolumna Tożsamość. Polecenie będzie więc wyglądać tak:

SET IDENTITY_INSERT DuplicateTable ON

INSERT Into DuplicateTable ([IdentityColumn], [Column2], [Column3], [Column4] ) 
SELECT [IdentityColumn], [Column2], [Column3], [Column4] FROM MainTable

SET IDENTITY_INSERT DuplicateTable OFF

Jeśli tabela ma wiele kolumn, uzyskaj nazwę tych kolumn za pomocą tego polecenia.

SELECT column_name + ','
FROM   information_schema.columns 
WHERE  table_name = 'TableName'
for xml path('')

(po usunięciu ostatniego przecinka (',')) Wystarczy skopiować nazwę poprzednich kolumn.

Rousonur Jaman
źródło
3

To powinno działać. Właśnie natrafiłem na twój problem:

SET IDENTITY_INSERT dbo.tbl_A_archive ON;
INSERT INTO     dbo.tbl_A_archive (IdColumn,OtherColumn1,OtherColumn2,...)
SELECT  *
FROM        SERVER0031.DB.dbo.tbl_A;
SET IDENTITY_INSERT dbo.tbl_A_archive OFF;

Niestety wydaje się, że potrzebujesz listy kolumn, w tym kolumny tożsamości, aby wstawić rekordy określające tożsamość. Nie musisz jednak wymieniać kolumn w SELECT. Jak sugerował @Dave Cluderay , spowoduje to sformatowanie listy do skopiowania i wklejenia (jeśli mniej niż 200 000 znaków).

Dodałem USE, ponieważ przełączam się między instancjami.

USE PES
SELECT SUBSTRING(
    (SELECT ', ' + QUOTENAME(COLUMN_NAME)
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'Provider'
        ORDER BY ORDINAL_POSITION
        FOR XML path('')),
    3,
    200000);
Gary
źródło
3
SET IDENTITY_INSERT tableA ON

INSERT Into tableA ([id], [c2], [c3], [c4], [c5] ) 
SELECT [id], [c2], [c3], [c4], [c5] FROM tableB

Nie tak jak to

INSERT INTO tableA
SELECT * FROM tableB

SET IDENTITY_INSERT tableA OFF
Królik
źródło
2

Ten fragment kodu pokazuje, jak wstawić do tabeli, gdy kolumna Klucz podstawowy tożsamości jest WŁĄCZONA.

SET IDENTITY_INSERT [dbo].[Roles] ON
GO
insert into Roles (Id,Name) values(1,'Admin')
GO
insert into Roles (Id,Name) values(2,'User')
GO
SET IDENTITY_INSERT [dbo].[Roles] OFF
GO
AminGolmahalle
źródło
1

Na przykład, jeśli chcesz wstawić wartości z jednej tabeli do drugiej za pomocą procedury składowanej. Użyłem tego i tego , tego drugiego, co jest prawie jak odpowiedź Andomara.

CREATE procedure [dbo].[RealTableMergeFromTemp]
    with execute as owner
AS
BEGIN
BEGIN TRANSACTION RealTableDataMerge
SET XACT_ABORT ON

    DECLARE @columnNameList nvarchar(MAX) =
     STUFF((select ',' + a.name
      from sys.all_columns a
      join sys.tables t on a.object_id = t.object_id 
       where t.object_id = object_id('[dbo].[RealTable]') 
    order by a.column_id
    for xml path ('')
    ),1,1,'')

    DECLARE @SQLCMD nvarchar(MAX) =N'INSERT INTO [dbo].[RealTable] (' + @columnNameList + N') SELECT * FROM [#Temp]'

    SET IDENTITY_INSERT [dbo].[RealTable] ON;
    exec(@sqlcmd)
    SET IDENTITY_INSERT [dbo].[RealTable] OFF

COMMIT TRANSACTION RealTableDataMerge
END

GO
Rubenisme
źródło
0

Istnieje co najmniej jedna kolumna, która ma właściwość automatycznego przyrostu lub wartość tego atrybutu zostanie obliczona jako ograniczenie. Próbujesz zmodyfikować tę kolumnę.

Istnieją dwa sposoby rozwiązania tego problemu: 1) Wymień wyraźnie inne kolumny i ustaw tylko ich wartości, a PrimaryKey lub wartość kolumny automatycznego przyrostu ustawią się automatycznie.

2) Możesz włączyć INDENTITY_INSERT, a następnie wykonać zapytanie wstawiania, a następnie wyłączyć IDENTITY_INSERT.

Sugestia: Wykonaj pierwszy krok, ponieważ jest to bardziej odpowiednie i wydajne podejście.

Aby uzyskać więcej informacji, przeczytaj ten artykuł na temat programu pomocniczego SQL .

Shanu Dey
źródło
0

Upewnij się, że nazwy kolumn, typy danych i kolejność w tabeli, z której wybierasz rekordy, są dokładnie takie same jak w tabeli docelowej. Jedyną różnicą powinno być to, że tabela docelowa ma kolumnę tożsamości jako pierwszą kolumnę, której nie ma w tabeli źródłowej.

Miałem podobny problem podczas wykonywania polecenia „INSERT INTO table_Dest SELECT * FROM table_source_linked_server_excel”. Tabele miały 115 kolumn.

Miałem dwie takie tabele, w których ładowałem dane z Excela (jako serwer połączony) do tabel w bazie danych. W tabelach bazy danych dodałem kolumnę tożsamości o nazwie „id”, której nie było w źródłowym programie Excel. W przypadku jednej tabeli zapytanie zakończyło się powodzeniem, aw innej wystąpił błąd „Wyraźną wartość kolumny tożsamości w tabeli można określić tylko wtedy, gdy używana jest lista kolumn, a IDENTITY_INSERT znajduje się na serwerze SQL”. To było zagadkowe, ponieważ scenariusz był dokładnie taki sam dla obu zapytań. Sprawdziłem to i znalazłem to w zapytaniu, w którym pojawiał się błąd z INSERT INTO .. ​​WYBIERZ *:

  1. Niektóre nazwy kolumn w tabeli źródłowej zostały zmodyfikowane, chociaż wartości były prawidłowe
  2. Było kilka dodatkowych kolumn poza rzeczywistymi kolumnami danych, które były wybierane przez SELECT *. Odkryłem to, używając opcji „Tabela skryptów jako> Wybierz do> nowe okno zapytania” w źródłowej tabeli programu Excel (pod połączonymi serwerami). Była jedna ukryta kolumna tuż za ostatnią kolumną w Excelu, chociaż nie miała żadnych danych. Usunąłem tę kolumnę w źródłowej tabeli programu Excel i zapisałem ją.

Po wprowadzeniu powyższych dwóch zmian zapytanie INSERT INTO ... SELECT * zostało uruchomione pomyślnie. Kolumna tożsamości w tabeli docelowej wygenerowała wartości tożsamości dla każdego wstawionego wiersza zgodnie z oczekiwaniami.

Tak więc, mimo że tabela docelowa może mieć kolumnę tożsamości, której nie ma w tabeli źródłowej, INSERT INTO .. ​​SELECT * uruchomi się pomyślnie, jeśli nazwy, typy danych i kolejność kolumn w źródle i miejscu docelowym są dokładnie takie same.

Mam nadzieję, że to komuś pomoże.

Uttam
źródło
-1

Myślę, że ten błąd występuje z powodu niedopasowania liczby kolumn w definicji tabeli i liczby kolumn w zapytaniu wstawiania. Długość kolumny jest również pomijana z wprowadzoną wartością. Wystarczy przejrzeć definicję tabeli, aby rozwiązać ten problem

Codemaker
źródło
Pracowałem dla mnie: zapomniałem dodać kolumnę do tabeli z projektu, dobrze jest to sprawdzić przed wypróbowaniem innych odpowiedzi.
Exel Gamboa,