2012-06-24 3 views
1

Используя SQL Server 2008, я хотел бы дублировать одну строку таблицы, , не зная названия полей. Моя ключевая проблема: поскольку таблица растет и мутирует с течением времени, я бы хотел, чтобы этот скрипт-сценарий продолжал работать, без необходимости записывать 30+ постоянно изменяющихся полей, тьфу.копировать целую строку (без знания имен полей)

Также, выпущено, конечно, Невозможно скопировать поля IDENTITY.

Мой код ниже действительно работает, но мне интересно, есть ли более подходящий метод, чем мой SQL-запрос с выраженной связью?

Благодарю вас заранее. Вот мой (да, рабочий) код - приветствую предложения по его улучшению. Тодд

alter procedure spEventCopy 
    @EventID int 
as 
begin 

    -- VARS... 
    declare @SQL varchar(8000) 

    -- LIST ALL FIELDS (*EXCLUDE* IDENTITY FIELDS). 
    -- USE [BRACKETS] FOR ANY SILLY FIELD-NAMES WITH SPACES, OR RESERVED WORDS... 
    select @SQL = coalesce(@SQL + ', ', '') + '[' + column_name + ']' 
    from INFORMATION_SCHEMA.COLUMNS 
    where TABLE_NAME = 'EventsTable' 
    and COLUMNPROPERTY(OBJECT_ID('EventsTable'), COLUMN_NAME, 'IsIdentity') = 0 

    -- FINISH SQL COPY STATEMENT... 
    set @SQL = 'insert into EventsTable ' 
      + ' select ' + @SQL 
      + ' from EventsTable ' 
      + ' where EventID = ' + ltrim(str(@EventID)) 

    -- COPY ROW... 
    exec(@SQL) 

    -- REMEMBER NEW ID... 
    set @EventID = @@IDENTITY 

    -- (do other stuff here) 

    -- DONE... 
    -- JUST FOR KICKS, RETURN THE SQL STATEMENT SO I CAN REVIEW IT IF I WISH... 
    select EventID = @EventID, SQL = @SQL 

end 

ответ

2

Если вы знаете, что ваш столбец идентификаторов называется (и это не будет изменение колонки), вы можете сделать это:

SELECT * INTO #dummy FROM EventsTable where EventID = @EventID; 

ALTER TABLE #dummy 
DROP COLUMN MyIdentityColumn 

INSERT EventsTable SELECT * FROM #dummy 
DROP TABLE #dummy 

Поскольку таблица может только каждый имеет один столбец идентификатора, указав, что в запросе не должно слишком сильно ограничивать вас.

Как указывает Аарон Бертранд, существуют риски, связанные с этим подходом. Пожалуйста, прочитайте обсуждение в комментариях ниже.

+2

Это обходной путь, но я должен предположить, что это своего рода хак. –

+0

Верно, но вы должны согласиться с тем, что он намного чище и удобнее в использовании, чем код в вопросе. Возможно, это взломать, но это взлом, который покупает вам более чистый код без недостатков (что я знаю, во всяком случае). –

+2

«Легче следить» довольно субъективно, и я не согласен - я нахожу динамический SQL более интуитивным, чем создание какой-либо # компактной копии таблицы. И создание объекта в tempdb, даже если оно содержит только одну строку, может вызвать конфликт, который не возникает при чтении метаданных. Это может быть особенно актуально, если таблица широкая (например,LOB), и одна строка может не совпадать с одной страницей. –

4

Нет, нет волшебного способа сказать: «ВЫБЕРИТЕ все столбцы, кроме <foo>» - то, как вы это делаете, так вам нужно будет это сделать (взломать другой ответ в сторону).

Вот как я бы изменить свой код, с этими изменениями (некоторые из них гиперссылками, так что вы можете прочитать мое мнение о том, почему):

ALTER PROCEDURE dbo.spEventCopy 
    @EventID INT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @sql NVARCHAR(MAX) = N''; 

    SELECT @sql += ',' + QUOTENAME(name) 
     FROM sys.columns 
     WHERE [object_id] = OBJECT_ID('dbo.EventsTable') 
     AND is_identity = 0; 

    SET @sql = STUFF(@sql, 1, 1, ''); 

    SET @sql = N'INSERT dbo.EventsTable(' + @sql + ') 
     SELECT ' + @sql + ' FROM dbo.EventsTable 
     WHERE EventID = ' + CONVERT(VARCHAR(12), @EventID) + ';'; 

    EXEC sp_executesql @sql; 

    SELECT @EventID = SCOPE_IDENTITY(); 

    -- do stuff with the new row here 

    SELECT EventID = @EventID, SQL = @SQL; 
END 
+0

Аарон, это «- (сделайте что-то другое здесь)» рядом со дном. Я, очевидно, не нуждаюсь в двух копиях идентичных данных, но сократил образец кода до его ядра ради совместного использования. –

+0

+1 Вы явно не вызывали использование 'QUOTENAME' в своем списке, который я вижу. –

+0

Спасибо @MartinSmith, сделаю это. –