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ć?


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


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

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);

2
Można to wybrać jako zmienną i użyć w dynamicznym zapytaniu SQL. Uratowałeś mi dzień. Wielkie dzięki!
— Paweł Cioch


ł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 :)


@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 *)


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)

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,....)

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.


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.


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);

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

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

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

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 .


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.


-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


Pracowałem dla mnie: zapomniałem dodać kolumnę do tabeli z projektu, dobrze jest to sprawdzić przed wypróbowaniem innych odpowiedzi.
— Exel Gamboa,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.