2013-11-26 2 views
0

Как удалить столбцы из таблицы temp SQL Server, если она существует из списка?Удаление столбцов из таблицы #temp на основе входного параметра CSV

Что-то вроде:

DECLARE @cols AS NVARCHAR(MAX) 
    @cols will have value like [first_name], [last_name], ..... 
    So @cols = '[first_name], [last_name], .....' 

Теперь

ALTER TABLE #my_tables 
    DROP COLUMN @cols 

Как проверить, если #my_tables действительно содержит last_name или нет? Если не игнорировать его, а не бросать ошибку. Мне еще нужно удалить другие столбцы, которые существуют в @cols

Я думаю, что мы можем сделать, если существует условие для отдельных столбцов.

Благодаря

+1

Почему вы пытаетесь удалить столбцы из таблицы #temp? Просто игнорируйте их. –

+0

, потому что мне нужно добавить одинаковые столбцы и значения из других значений динамической оси – user1882705

+1

Так почему бы вам не подождать, чтобы построить таблицу #temp, пока не узнаете, что все столбцы будут? Или просто назовите новые столбцы first_name2, last_name2 и т. Д.? Или во избежание таблицы #temp в первую очередь? Вы знаете, что у вас будет грань временной консолидации, пытаясь построить и изменить таблицу #temp, а также использовать динамический SQL ... –

ответ

3

Я согласен с лукавыми DBA: вы должны передать эти значения в качестве параметра табличного , а не как список, разделенный запятыми. Но это не меняет проблему: вы все равно должны генерировать все команды DROP COLUMN динамически, независимо от того, анализируются ли имена столбцов из CSV с использованием табличной функции или вытаскиваются из TVP.

Я продолжу ваше текущее требование списка, разделенного запятой.

Во-первых, создайте функцию разделения строк. Это один я использую:

CREATE FUNCTION [dbo].[SplitString] 
    (
     @List NVARCHAR(MAX), 
     @Delim VARCHAR(255) 
    ) 
    RETURNS TABLE 
    AS 
     RETURN (SELECT [Value] FROM 
      ( 
      SELECT 
       [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number], 
       CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number]))) 
      FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name) 
       FROM sys.all_objects) AS x 
       WHERE Number <= LEN(@List) 
       AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim 
     ) AS y 
     ); 
GO 

Теперь создадим глупую #temp таблицу:

CREATE TABLE #foo(id INT, x INT); 

Теперь вы можете объявить список столбцов, которые вы хотите, чтобы попытаться удалить, создать динамический SQL заявление, которое проверяет, что они существуют, прежде чем сбросив их, а затем падает на них он может:

DECLARE @cols VARCHAR(MAX); 
SET @cols = '[first_name], [last_name], [id]'; 

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

SELECT @sql = @sql + N'IF EXISTS (SELECT 1 FROM tempdb.sys.columns AS c 
    WHERE [object_id] = OBJECT_ID(''tempdb..#foo'') 
    AND name = ' + REPLACE(REPLACE(QUOTENAME(s.Value, ''''),']',''),'[','') + ') 
    ALTER TABLE #foo DROP COLUMN ' + s.Value + ';' 
FROM dbo.SplitString(@cols, ',') AS s; 

EXEC sp_executesql @sql; 

SELECT * FROM #foo; -- this only returns the column x 

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

  • если вы попытаетесь удалить столбец, который участвует в любом ограничении (по умолчанию, PK, FK, проверка и т. Д.).
  • если вы попытаетесь удалить последний столбец в таблице.
  • Если у вас есть столбцы с очень плохо подобранными именами, которые каким-то образом обходят всю защиту, которую я пытался включить сюда.
+0

Спасибо за четкое решение. Я думаю, что это сработает для меня пока. Моя фактическая ситуация здесь: у меня есть таблица пользователя и соответствующая таблица транзакций, в которой хранятся все имена полей, которые были изменены за это время, а также его предварительные данные и обновленные данные (здесь я использую триггер). Так что я пытаюсь сделать здесь, это получить поля, которые изменяются из таблиц транзакций и остальных полей из таблицы пользователей, и возвращать все значения в geother как вывод – user1882705

+0

Если вы не против, я могу дать вам код, какой я я пытаюсь сделать прямо сейчас. Пожалуйста, помогите мне написать лучший эффективный магазин proc. Я знаю, что слишком много задаю, но это поможет мне в моем полном проекте. – user1882705

0

Используйте это:

SELECT * 
FROM information_schema.COLUMNS 
WHERE 
    TABLE_SCHEMA = 'db_name' 
AND TABLE_NAME = 'table_name' 
AND COLUMN_NAME = 'column_name' 

Он вернется, существует ли столбец или нет, используйте ответ от этого SQL, чтобы решить, будет ли или не делать преформы падения

1

Вы можете просто используйте динамический SQL; однако, следите за SQL Injection.

Я передал бы @cols в качестве параметра хранимой процедуры.

Тело процедуры будет ниже.

-- Declare local variables 
DECLARE @STMT NVARCHAR(MAX); 

-- Create the stmt 
SET @STMT = 'ALTER TABLE #my_tables DROP COLUMN ' + @cols; 

-- Execute the stmt 
EXEC sp_executesql @STMT; 

Я предпочел бы передать параметр значения таблицы, но это только я.

+0

Я уже использую динамический запрос, но когда @cols содержит как [Адрес] в списке, который существует в таблице temp, тогда он бросает ошибку. – user1882705

+0

Ошибка ALTER TABLE DROP COLUMN, потому что столбец «Адрес» не существует в таблице «#my_tables – user1882705

+0

@AaronBertrand, моя временная таблица #my_tables не содержит этот столбец« Адрес », но мой« @cols »содержит этот адрес как одно из полей, разделенных комой , – user1882705

1

исследовать столбцы временной таблицы вы должны помнить, что она хранится в темпе дб

select * 
from tempdb.sys.columns 
where object_id = object_id('tempdb..#my_tables') 
Смежные вопросы