it-swarm.asia

كيف أنسخ جدولًا باستخدام SELECT INTO لكني أتجاهل خاصية IDENTITY؟

لدي جدول به عمود هوية يقول:

create table with_id (
 id int identity(1,1),
 val varchar(30)
);

من المعروف أن هذا

select * into copy_from_with_id_1 from with_id;

ينتج عن copy_from_with_id_1 بهوية في المعرف أيضًا.

ما يلي سؤال تجاوز سعة المكدس إشارات تسرد جميع الأعمدة بشكل صريح.

لنحاول

select id, val into copy_from_with_id_2 from with_id;

عفوًا ، حتى في هذه الحالة معرف الهوية هو عمود هوية.

ما أريده هو طاولة مثل

create table without_id (
 id int,
 val varchar(30)
);
43
bernd_k

من كتب اون لاين

يتم تحديد تنسيق new_table من خلال تقييم التعبيرات في قائمة التحديد. يتم إنشاء الأعمدة في new_table بالترتيب المحدد بواسطة قائمة التحديد. كل عمود في new_table له نفس الاسم ونوع البيانات والقيمة الباطلة والقيمة كتعبير مطابق في قائمة التحديد. يتم نقل خاصية IDENTITY للعمود باستثناء الشروط المحددة في "العمل مع أعمدة الهوية" في قسم الملاحظات.

اسفل الصفحة:

عند تحديد عمود هوية موجود في جدول جديد ، يرث العمود الجديد خاصية IDENTITY ، ما لم يكن أحد الشروط التالية صحيحًا:

  • تحتوي عبارة SELECT على دالة الصلة أو جملة GROUP BY أو دالة التجميع.
  • يتم ضم عبارات SELECT متعددة باستخدام UNION.
  • يتم سرد عمود الهوية أكثر من مرة في قائمة التحديد.
  • عمود الهوية جزء من تعبير.
  • عمود الهوية من مصدر بيانات بعيد.

إذا كان أي من هذه الشروط صحيحًا ، يتم إنشاء العمود NOT NULL بدلاً من وراثة خاصية IDENTITY. إذا كان عمود الهوية مطلوبًا في الجدول الجديد ولكن مثل هذا العمود غير متوفر ، أو كنت تريد قيمة أساسية أو زيادة مختلفة عن عمود هوية المصدر ، حدد العمود في قائمة التحديد باستخدام وظيفة IDENTITY. راجع "إنشاء عمود هوية باستخدام وظيفة IDENTITY" في قسم الأمثلة أدناه.

لذلك ... يمكنك من الناحية النظرية الإفلات من:

select id, val 
into copy_from_with_id_2 
from with_id

union all

select 0, 'test_row' 
where 1 = 0;

سيكون من المهم التعليق على هذا الرمز لشرحه ، خشية إزالته في المرة التالية التي ينظر فيه شخص ما إليه.

56
Eric Humphrey - lotsahelp

مستوحاة من إجابة Erics ، وجدت الحل التالي الذي يعتمد فقط على أسماء الجداول ولا يستخدم أي اسم عمود محدد:

select * into without_id from with_id where 1 = 0
union all
select * from with_id where 1 = 0
;
insert into without_id select * from with_id;

تحرير

حتى أنه من الممكن تحسين هذا ل

select * into without_id from with_id
union all
select * from with_id where 1 = 0
;
31
bernd_k

يمكنك استخدام صلة لإنشاء الجدول الجديد وتعبئته دفعة واحدة:

SELECT
  t.*
INTO
  dbo.NewTable
FROM
  dbo.TableWithIdentity AS t
  LEFT JOIN dbo.TableWithIdentity ON 1 = 0
;

بسبب 1 = 0 الشرط ، لن يكون للجانب الأيمن أي تطابقات وبالتالي يمنع ازدواج صفوف الجانب الأيسر ، ولأن هذه صلة خارجية ، فلن يتم التخلص من صفوف الجانب الأيسر أيضًا. أخيرًا ، نظرًا لأن هذا صلة ، يتم التخلص من خاصية IDENTITY.

تحديد الأعمدة الموجودة على الجانب الأيسر فقط ، وبالتالي ، ستنتج نسخة طبق الأصل من dbo.TableWithIdentity من ناحية البيانات فقط ، أي مع إزالة الخاصية IDENTITY.

كل ما قيل ، ماكس فيرنون أثار نقطة صحيحة في تعليق يستحق أن يوضع في الاعتبار. إذا نظرت إلى خطة تنفيذ الاستعلام أعلاه:

Execution plan

ستلاحظ أن الجدول المصدر مذكور في خطة التنفيذ مرة واحدة فقط. تم استبعاد المثيل الآخر بواسطة المُحسّن.

لذلك ، إذا كان بإمكان المُحسّن أن يثبت بشكل صحيح أن الجانب الأيمن من الصلة غير مطلوب في الخطة ، فيجب أن يكون من المعقول توقع أنه في إصدار مستقبلي من SQL Server قد يكون قادرًا على معرفة أن الخاصية IDENTITY لا تحتاج إلى تمت إزالته أيضًا ، نظرًا لعدم وجود عمود IDENTITY آخر في صف المصدر الذي تم تعيينه وفقًا لخطة الاستعلام. هذا يعني أن الاستعلام أعلاه قد يتوقف عن العمل كما هو متوقع في وقت ما.

ولكن ، كما لوحظ بشكل صحيح من قبل ypercubeᵀᴹ ، حتى الآن (الدليل تم ذكره صراحة أنه إذا كان هناك صلة ، فلن يتم حفظ خاصية الهوية:

عندما يتم تحديد عمود هوية موجود في جدول جديد ، يرث العمود الجديد خاصية IDENTITY ، ما لم تحتوي عبارة ... SELECT على صلة.

لذا ، طالما استمر الدليل في ذكره ، ربما يمكننا أن نطمئن إلى أن السلوك سيظل كما هو.

مجد إلى Shaneis و ypercubeᵀᴹ لإثارة موضوع ذي صلة في الدردشة.

13
Andriy M

جرب هذا الرمز ..

SELECT isnull(Tablename_old.IDENTITYCOL + 0, -1) AS 'New Identity Column'
INTO   dbo.TableName_new
FROM   dbo.TableName_old 

تضمن المكالمة ISNULL إنشاء العمود الجديد باستخدام NOT NULL البطلان.

6
Saurav Ghosh

فقط لإظهار طريقة مختلفة:

يمكنك استخدام خادم مرتبط.

SELECT * 
INTO without_id 
FROM [linked_server].[source_db].dbo.[with_id];

يمكنك إنشاء خادم مرتبط مؤقتًا بالخادم المحلي باستخدام ما يلي:

DECLARE @LocalServer SYSNAME 
SET @LocalServer = @@SERVERNAME;
EXEC master.dbo.sp_addlinkedserver @server = N'localserver'
    , @srvproduct = ''
    , @provider = 'SQLNCLI'
    , @datasrc = @LocalServer;
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'localserver'
    , @useself = N'True'
    , @locallogin = NULL
    , @rmtuser = NULL
    , @rmtpassword = NULL;

عند هذه النقطة ، ستقوم بتشغيل select * into الرمز ، يشير إلى localserver اسم الخادم المرتبط المكون من أربعة أجزاء:

SELECT * 
INTO without_id 
FROM [localserver].[source_db].dbo.[with_id];

بعد اكتمال ذلك ، نظف الخادم المرتبط localserver بهذا:

EXEC sp_dropserver @server = 'localserver'
    , @droplogins = 'droplogins';

أو يمكنك استخدام بناء الجملة OPENQUERY

SELECT * 
INTO without_id 
FROM OPENQUERY([linked_server], 'SELECT * FROM [source_db].dbo.[with_id]');
3
bernd_k

لا يتم نقل خاصية الهوية إذا كانت عبارة التحديد تحتوي على صلة وهكذا

select a.* into without_id from with_id a inner join with_id b on 1 = 0;

سيعطي أيضًا السلوك المطلوب (للعمود id المنسوخ لعدم الاحتفاظ بخاصية IDENTITY. ومع ذلك ، سيكون له تأثير جانبي لعدم نسخ أي صف على الإطلاق! (كما هو الحال مع البعض الآخر الأساليب) لذا ستحتاج بعد ذلك إلى:

insert into without_id select * from with_id;

(شكرا AakashM!)

1
anon-99

الطريقة السهلة هي جعل العمود جزءًا من تعبير.

مثال:
إذا كان الجدول dbo. الموظف لديه هوية في عمود المعرّف ، في المثال أدناه ، الجدول المؤقت #t سيكون له هوية في عمود المعرّف أيضًا.

--temp table has IDENTITY
select ID, Name 
into #t
from dbo.Employee

قم بتغيير هذا لتطبيق تعبير على ID ولن يكون لديك #t هوية ID في عمود ID. في هذه الحالة نقوم بتطبيق إضافة بسيطة على عمود المعرف.

--no IDENTITY
select ID = ID + 0, Name 
into #t
from dbo.Employee

من الأمثلة الأخرى على التعبيرات لأنواع البيانات الأخرى ما يلي: convert () أو سلسلة متسلسلة أو Isnull ()

1
FistOfFury

في بعض الأحيان ، تريد الإدراج من جدول حيث لا تعرف (أو تهتم) إذا تم إنشاء العمود باستخدام IDENTITY أم لا. قد لا يكون عمودًا صحيحًا تعمل معه. في هذه الحالة ، يعمل ما يلي:

SELECT TOP(0) ISNULL([col],NULL) AS [col], ... INTO [table2] FROM [table1]
ALTER TABLE [table2] REBUILD WITH (DATA_COMPRESSION=page)
INSERT INTO [table2] ...

ستقوم ISNULL بإسقاط سمة IDENTITY من العمود ولكنها ستدرجها بنفس الاسم والنوع كالعمود الأصلي وستجعلها غير قابلة للإلغاء. سيعمل TOP (0) على إنشاء جدول فارغ يمكنك استخدامه لإدراج الصفوف المحددة فيه. يمكنك أيضًا جعل الجدول مضغوطًا قبل إدراج البيانات إذا لزم الأمر.

1
Tony
select convert(int, id) as id, val 
into copy_from_with_id_without_id 
from with_id;

ستزيل الهوية.

الجانب السلبي هو أن id يصبح لاغياً ولكن يمكنك إضافة هذا القيد.

0
john hunter