Как я могу динамически псевдоним столбцов?

10

У меня есть таблица (не разработанная мной), которая имеет 20 переменных столбцов. То есть, в зависимости от того, какой тип записи вы просматриваете, применимое имя столбца может измениться.

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

Поэтому запрос, который я действительно ищу, выглядит примерно так:

SELECT Col1 AS (SELECT ColName FROM Names WHERE ColNum = 1 and Type = @Type),
       Col2 AS (SELECT ColName FROM Names WHERE ColNum = 2 and Type = @Type)
FROM   Tbl1 
WHERE  Type = @Type

Очевидно, что это не работает, так как я могу получить аналогичный результат?

« Я пытался создать строку запроса и использовать EXECUTEее, но она просто возвращает« Команда (и) успешно выполнена ») и, похоже, не возвращает набор строк. Оказывается, я использовал неправильный запрос для построения динамического SQL и поэтому создал пустую строку. SQL Server определенно выполнил пустую строку правильно.

Обратите внимание, что причина, по которой мне это нужно, а не просто жесткое кодирование имен столбцов, заключается в том, что имена столбцов настраиваются пользователем.

Hotchips
источник
1
Что произойдет, если вы напечатаете строку запроса, скопируете / вставите в новое окно запроса и выполните его там?
DenisT
«Настраиваемый пользователем» означает, что существуют сотни или тысячи типов и / или часто меняются псевдонимы? Если псевдонимы достаточно стабильны, я бы рекомендовал создать серию представлений.
Джон на все руки
@DenisT, он ничего не выводит, что, возможно, указывает на то, что что-то еще не так. Спасибо за лидерство.
Hotchips
@JonofAllTrades К сожалению, несмотря на то, что они довольно стабильны, это очень большая часть спецификации, что, когда пользователь изменяет что-то в программном обеспечении, эта вещь также должна меняться в отчетах.
Hotchips
@DenisT Оказывается, мои подзапросы, использованные для построения динамического SQL, были неверными и возвращали нулевые наборы. Таким образом, SQL Server вернул пустой запрос, который он успешно выполнил. Спасибо за указание на команду PRINT.
Hotchips

Ответы:

12

Попробуйте следующий код:

CREATE TABLE #Names
(
    [Type] VARCHAR(50),
    ColNum SMALLINT,
    ColName VARCHAR(50),
    ColDataType VARCHAR(20)
)

INSERT  INTO #Names VALUES
('Customer', 1, 'CustomerID', 'INT'),
('Customer', 2, 'CustomerName', 'VARCHAR(50)'),
('Customer', 3, 'CustomerJoinDate', 'DATE'),
('Customer', 4, 'CustomerBirthDate', 'DATE'),
('Account', 1, 'AccountID', 'INT'),
('Account', 2, 'AccountName', 'VARCHAR(50)'),
('Account', 3, 'AccountOpenDate', 'DATE'),
('CustomerAccount', 1, 'CustomerID', 'INT'),
('CustomerAccount', 2, 'AccountID', 'INT'),
('CustomerAccount', 3, 'RelationshipSequence', 'TINYINT')


CREATE TABLE #Data
(
    [Type] VARCHAR(50),
    Col1 VARCHAR(50),
    Col2 VARCHAR(50),
    Col3 VARCHAR(50),
    Col4 VARCHAR(50),
    Col5 VARCHAR(50),
    Col6 VARCHAR(50),
    Col7 VARCHAR(50)
)

INSERT  INTO #Data VALUES
('Customer', '1', 'Mr John Smith', '2005-05-20', '1980-11-15', NULL, NULL, NULL),
('Customer', '2', 'Mrs Hayley Jones', '2009-10-10', '1973-04-03', NULL, NULL, NULL),
('Customer', '3', 'ACME Manufacturing Ltd', '2012-12-01', NULL, NULL, NULL, NULL),
('Customer', '4', 'Mr Michael Crocker', '2014-01-13', '1957-01-23', NULL, NULL, NULL),
('Account', '1', 'Smith-Jones Cheque Acct', '2005-05-25', NULL, NULL, NULL, NULL),
('Account', '2', 'ACME Business Acct', '2012-12-01', NULL, NULL, NULL, NULL),
('Account', '3', 'ACME Social Club', '2013-02-10', NULL, NULL, NULL, NULL),
('Account', '4', 'Crocker Tipping Fund', '2014-01-14', NULL, NULL, NULL, NULL),
('CustomerAccount', '1', '1', '1', NULL, NULL, NULL, NULL),
('CustomerAccount', '2', '1', '2', NULL, NULL, NULL, NULL),
('CustomerAccount', '2', '3', '2', NULL, NULL, NULL, NULL),
('CustomerAccount', '3', '2', '1', NULL, NULL, NULL, NULL),
('CustomerAccount', '3', '3', '1', NULL, NULL, NULL, NULL),
('CustomerAccount', '4', '2', '2', NULL, NULL, NULL, NULL),
('CustomerAccount', '4', '4', '1', NULL, NULL, NULL, NULL)


DECLARE @Type VARCHAR(50) = 'Account' -- Or Customer, or CustomerAccount

DECLARE @SQLText NVARCHAR(MAX) = ''

SELECT  @SQLText += 'SELECT '

SELECT  @SQLText += ( -- Add in column list, with dynamic column names.
                SELECT  'CONVERT(' + ColDataType + ', Col' + CONVERT(VARCHAR, ColNum) + ') AS [' + ColName + '],'
                FROM    #Names
                WHERE   [Type] = @Type FOR XML PATH('')
            )

SELECT  @SQLText = LEFT(@SQLText, LEN(@SQLText) - 1) + ' ' -- Remove trailing comma

SELECT  @SQLText += 'FROM #Data WHERE [Type] = ''' + @Type + ''''

PRINT   @SQLText
EXEC    sp_executesql @SQLText

Это возвращает инструкцию SELECT: SELECT CONVERT(INT, Col1) AS [AccountID],CONVERT(VARCHAR(50), Col2) AS [AccountName],CONVERT(DATE, Col3) AS [AccountOpenDate] FROM #Data WHERE [Type] = 'Account'

garthmillar
источник
Использование динамического SQL является правильным ответом, учитывая, что вопрос задан, как это сделать с SQL. Это было то, что я пытался сделать, но неправильно.
Hotchips
Имейте в виду, что если вы принимаете пользовательский ввод и используете его для построения динамического SQL, то вам действительно нужно заботиться о внедрении SQL-кода и его очистке. bobby-tables.com
Джонатан Ван Матр
@JonathanVanMatre Абсолютно. К счастью, это только для внутреннего использования, и все входы уже очищены приложением.
Hotchips
7

Это звучит замечательно для внешнего интерфейса дисплея. Запрос 1 будет возвращать ваши данные, запрос 2 будет извлекать имена столбцов и в коде, когда вы создаете какую-либо структуру, которую вы используете для отображения, вы устанавливаете заголовки из второго запроса.

Хотя метод Pure SQL может быть возможен, это будет динамический SQL, а обслуживание кода станет кошмаром.

Кроме того, вы, вероятно, ищете, sp_executesqlи не только EXECUTE N'Query String'это может исправить вашу проблему команды завершена успешно.

RubberChickenLeader
источник
Я согласен, и я определенно мог бы сделать это в SSRS, но я не могу сделать это в другом программном обеспечении для составления отчетов, которое я использую в настоящее время.
Hotchips