Имена столбцов SQL из листа Excel

Я использую SSMS 2014 и SQL Server 2014. Мне нужно изменить имена столбцов в конце результата запроса, используя файл excel или таблицу с данными.

После некоторых операторов SELECT и прочего я получаю таблицу с данными, например

+---------+---------+------+
|  Col1   |  Col2   | Col3 |
+---------+---------+------+
| Value 1 | Value 2 |  123 |
| Value 2 | Value 2 |  456 |
| Value 3 | Value 3 |  789 |
+---------+---------+------+

И таблица или excelfile

+----+---------+-----------+-----------+
| ID | ColName |  Language |  Addition |
+----+---------+-----------+-----------+
|  1 | Col1    |  D        |       123 |
|  2 | Col2    |  D        |       456 |
|  3 | Col3    |  D        |       789 |
|  4 | Col1    |  E        |       123 |
|  5 | Col2    |  E        |       456 |
|  6 | Col3    |  E        |       789 |
+----+---------+-----------+-----------+

Что я пытаюсь сделать, так это получить дополнительное значение каждого столбца и добавить его к имени столбца. Он должен добавлять только значения с определенным language. @setLang = 'D'

Col1 + Addition
Col2 + Addition
Col3 + Addition

+-------------+-------------+---------+
|  Col1 123   |  Col2 456   | Col3789 |
+-------------+-------------+---------+
| Value 1     | Value 2     |  123    |
| Value 2     | Value 2     |  456    |
| Value 3     | Value 3     |  789    |
+-------------+-------------+---------+

Я попробовал это через Information_Schema.Columns и отфильтровал, где таблица = 'resultTable' и Column_name = @cName. Может быть, мне нужен цикл для получения каждого имени столбца.

Спасибо, что читаете и пытаетесь мне помочь.


person JollyPopper    schedule 24.10.2014    source источник


Ответы (2)


Попробуйте - он использует таблицу, а не файл excel (но, похоже, это вариант в вашем вопросе). Я сделал несколько временных таблиц и заполнил их вашими значениями, но вам это явно не понадобится. Вам нужно будет заменить ссылки на tempdb именем базы данных, в которой хранятся ваши таблицы, а временные таблицы #Original и #ExcelInfo — именами ваших таблиц.

Я также использовал временную таблицу, чтобы добавить столбец «ID IDENTITY (1,1)» в таблицу, содержащую ваши исходные данные. Это необходимо, чтобы держать под контролем unpivot; если вы можете изменить свою таблицу, чтобы включить идентификатор, это облегчит задачу, но если нет, вы можете вставить ее во временную таблицу, как это сделал я.

Сценарий короче, чем кажется — вся первая часть — это настройка примера; настоящий ответ начинается со строки, в которой объявляется ваша языковая переменная.

/*
The script between the first two dividing lines of dashes is just used to set up the example. The bit you want is from
the "-- Test Variables --" line.
*/
-----------------------------------------------------------------------------------------------------------------------
IF OBJECT_ID('tempdb..#Original') IS NOT NULL DROP TABLE #Original
IF OBJECT_ID('tempdb..#ExcelInfo') IS NOT NULL DROP TABLE #ExcelInfo

CREATE TABLE #Original
( Col1  VARCHAR(50)
 ,Col2  VARCHAR(50)
 ,Col3  VARCHAR(50))
CREATE TABLE #ExcelInfo
( Id            INT IDENTITY(1,1)   NOT NULL
 ,ColName       VARCHAR(50)         NOT NULL
 ,[Language]    CHAR(1)             NOT NULL
 ,Addition      INT                 NOT NULL)

INSERT #Original
SELECT *
FROM
        (   SELECT 'Value 1' AS Col1,'Value 2' AS Col2  ,123 AS Col3
    UNION   SELECT 'Value 2'        ,'Value 2'          ,456
    UNION   SELECT 'Value 3'        ,'Value 3'          ,789)           AS This
ORDER BY Col1


INSERT #ExcelInfo (ColName,[Language],Addition)
SELECT *
FROM
        (   SELECT 'Col1' AS ColName, 'D' AS [Language], 123 AS Addition
    UNION   SELECT 'Col2','D',456
    UNION   SELECT 'Col3','D',789
    UNION   SELECT 'Col1','E',123
    UNION   SELECT 'Col2','E',456
    UNION   SELECT 'Col3','E',789)                                  AS This
ORDER BY [Language], Addition

-----------------------------------------------------------------------------------------------------------------------
-- Test Variables --
DECLARE @SetLang CHAR(1) = 'D'
-----------------------------------------------------------------------------------------------------------------------
-- make the default empty, not null on our dynamic string, so it can be added to
DECLARE @Columns VARCHAR(MAX) = ''
DECLARE @SQL VARCHAR(MAX)

CREATE TABLE #OriginalColumns
( Id INT IDENTITY(1,1)
 ,Name VARCHAR(50))
CREATE TABLE #BasicResult
(Id INT NOT NULL, Name VARCHAR(50), Value VARCHAR(50))
-- If you can add an id column to your original table, this bit is unecessary - you can use yours in place of this table
CREATE TABLE #Original_WITH_Id
( Id INT IDENTITY(1,1)
 ,Col1  VARCHAR(50)
 ,Col2  VARCHAR(50)
 ,Col3  VARCHAR(50))

INSERT #Original_WITH_Id
SELECT * FROM #Original
-----------------------------------------------------------------------------------------------------------------------
-- List out the columns and put the list in a variable.
INSERT #OriginalColumns
SELECT QUOTENAME(Col.name)
FROM tempdb.sys.columns AS Col
WHERE Col.object_id = OBJECT_ID('tempdb.dbo.#Original_WITH_Id')
-- we're not interested in the identity column at the moment
AND Col.name <> 'Id'
-- keep everything in the same order as they are listed on the table
ORDER BY Col.column_id

SELECT @Columns = @Columns + ',' + Name
FROM #OriginalColumns
-- clip off the leading comma
SELECT @Columns = SUBSTRING(@Columns,2,LEN(@Columns))

-- get a full list of everything, creating our new list of columns as we go, using the Id column to keep a mark on which
-- row each record originally came from
SET @SQL =
'INSERT #BasicResult
SELECT Id, New.Name, Value FROM
     (SELECT Id, Name, Value
      FROM #Original_WITH_Id
      UNPIVOT (Value FOR Name IN (' + @Columns + ')) Unpvt) AS Old
JOIN (SELECT ColName, CONVERT(VARCHAR(50),ColName) + '' '' + CONVERT(VARCHAR(50),Addition)  AS Name
      FROM #ExcelInfo
      WHERE [Language] = ''' + @SetLang + ''') AS New ON Old.Name = New.ColName'
PRINT @SQL
EXEC (@SQL)

-- now update our list of columns to be the new column headings
SET @Columns = ''
SELECT @Columns = @Columns + ',' + QUOTENAME(Name) FROM (SELECT DISTINCT Name FROM #BasicResult) AS Names
SELECT @Columns = SUBSTRING(@Columns,2,LEN(@Columns))

-- pivout our results back out to their original format, but with the new column headings (include the Id if you want)
SET @SQL =
'SELECT /*Id,*/ ' + @Columns + '
 FROM
    (SELECT Id, Name,Value
     FROM #BasicResult) AS Up
     PIVOT (MAX(Value) FOR Name IN  (' + @Columns + ')) AS Pvt'

PRINT @SQL
EXEC (@SQL)

-- clean up --
DROP TABLE #OriginalColumns
DROP TABLE #BasicResult

Надеюсь, это поможет! Может быть, есть более эффективный способ сделать это... Я не уверен.

person High Plains Grifter    schedule 24.10.2014
comment
Эй, спасибо за вашу помощь. Честно говоря, я не пробовал ваш код, поэтому не уверен, работает он или нет. Мое решение работает с курсором и работает с меньшим количеством кода. Что вы думаете? - person JollyPopper; 27.10.2014
comment
Справедливости ради - если это работает, то это работает! Также хорошо избегать динамического SQL. Недостатком курсора является то, что производительность не будет хорошей для больших наборов данных. Если вы используете только небольшой набор данных и производительность хорошая, то отлично! - person High Plains Grifter; 27.10.2014
comment
Ну да, вы правы с производительностью. Но в таблице CSV всего ~ 3000 строк, и она переименовывает мои столбцы примерно за 3 секунды, что, на мой взгляд, хорошо. Все равно спасибо! - person JollyPopper; 27.10.2014

Хорошо, я попробовал еще раз, но теперь без Excelfile. Я сделал CSV из файла Excel и вставил его с помощью Bulk в мою созданную таблицу:

IF NOT EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'CSVTest')
BEGIN
CREATE TABLE _DICTIONARY
( _TableName VARCHAR (20),
_ColumnName  VARCHAR  (20),
_Language    VARCHAR  (20),
_FieldShort  VARCHAR (50),
_FieldMid    VARCHAR (50),
_FieldLong   VARCHAR (50)
)
BULK
INSERT _DICTIONARY
FROM 'C:\_DICTIONARY.csv'
WITH
(
FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n'
)
END

После этого я переименовываю все столбцы с помощью курсора.

DECLARE @dic_tableName            as nvarchar(50),
        @dic_columnName           as nvarchar(50),
        @db_tableName              as nvarchar(50),
        @db_columnName            as nvarchar(50);


DECLARE C CURSOR FAST_FORWARD FOR
    SELECT _TableName, _ColumnName FROM _DICTIONARY
OPEN C;

FETCH NEXT FROM C INTO @dic_tableName, @dic_columnName;

WHILE @@FETCH_STATUS = 0
BEGIN
  IF EXISTS(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @dic_tableName AND COLUMN_NAME = @dic_columnName)
BEGIN
  SET @db_tableName = @dic_tableName + '.' + @dic_columnName
  SET @db_columnName = @dic_tableName + '_' + @dic_columnName
  EXEC sp_rename @db_tableName, @db_columnName ,'COLUMN'
  FETCH NEXT FROM C INTO @dic_tableName, @dic_columnName;
END
  ELSE
BEGIN
  FETCH NEXT FROM C INTO @dic_tableName, @dic_columnName;
END
END

CLOSE C;
DEALLOCATE C;

Он делает свою работу.

person JollyPopper    schedule 27.10.2014