Como posso alias dinamicamente colunas?

10

Eu tenho uma tabela (não projetada por mim) que possui 20 colunas com nomes variáveis. Ou seja, dependendo do tipo de registro que você está visualizando, o nome aplicável da coluna pode ser alterado.

Os possíveis nomes de colunas estão armazenados em outra tabela, que posso consultar com muita facilidade.

Portanto, a consulta que estou procurando é mais ou menos assim:

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

Obviamente que isso não funciona, então como posso obter um resultado semelhante?

' Eu tentei criar uma string de consulta e EXECUTEinseri-la, mas isso retorna "Command (s) Completed Successfully" e não parece retornar um conjunto de linhas. Acontece que eu estava usando uma consulta incorreta para criar o SQL dinâmico e, como tal, construiu uma string vazia. O SQL Server definitivamente executou a sequência vazia corretamente.

Observe que a razão pela qual eu preciso que isso ocorra, em vez de simplesmente codificar os nomes das colunas, é que os nomes das colunas são configuráveis ​​pelo usuário.

Hotchips
fonte
11
O que acontece se você imprimir a string de consulta, copiar / colar em uma nova janela de consulta e executá-la lá?
21414 DenisT
"Configurável pelo usuário" significa que existem centenas ou milhares de tipos e / ou aliases sendo alterados com frequência? Se os aliases forem razoavelmente estáveis, eu recomendo criar uma série de visualizações.
Jon of All Trades
@ DenisT, ele não produz nada, o que talvez indica que algo mais está errado também. Obrigado pela liderança.
Hotchips
@ JonofAllTrades Infelizmente, apesar de razoavelmente estáveis, faz parte das especificações que, quando o usuário altera algo no software, isso também deve mudar nos relatórios.
Hotchips 17/02
@DenisT Acontece que minhas subconsultas usadas para criar o SQL dinâmico estavam incorretas e retornaram conjuntos nulos. Portanto, o SQL Server retornou uma consulta em branco, que foi devidamente executada com sucesso. Obrigado por apontar o comando PRINT.
Hotchips

Respostas:

12

Tente o seguinte código:

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

Isso retorna a instrução SELECT: SELECT CONVERT(INT, Col1) AS [AccountID],CONVERT(VARCHAR(50), Col2) AS [AccountName],CONVERT(DATE, Col3) AS [AccountOpenDate] FROM #Data WHERE [Type] = 'Account'

garthmillar
fonte
Usar o SQL dinâmico é a resposta correta, já que a pergunta foi feita como fazê-lo com o SQL. Também era algo que eu tentava fazer, mas incorretamente.
Hotchips
Lembre-se de que, se você está aceitando a entrada do usuário e usando-a para criar SQL dinâmico, precisa realmente se preocupar com a injeção de SQL e com as entradas de higienização. bobby-tables.com
Jonathan Van Matre
@JonathanVanMatre Absolutely. Felizmente, isso é apenas para uso interno e todas as entradas já são higienizadas pelo aplicativo.
Hotchips
7

Isso parece excelente para uma solução de exibição de front-end. A consulta 1 recuaria seus dados, a consulta 2 recuaria os nomes das colunas e o código quando você cria a estrutura que você usa para exibir e define os cabeçalhos da segunda consulta.

Embora seja possível um método SQL puro, ele será um SQL dinâmico e a manutenção do código seria um pesadelo.

Você provavelmente está procurando sp_executesqle não apenas EXECUTE N'Query String'como isso pode resolver seu problema de comando concluído com êxito.

RubberChickenLeader
fonte
Eu concordo e definitivamente poderia fazer isso no SSRS, mas não posso fazê-lo no outro software de relatório que estou usando no momento.
Hotchips 17/02