Come posso dinamicamente alias colonne?


10

Ho una tabella (non progettata da me) che ha 20 colonne con nomi variabili. Cioè, a seconda del tipo di record che stai guardando, il nome applicabile della colonna può cambiare.

I possibili nomi di colonna sono memorizzati in un'altra tabella, che posso interrogare molto facilmente.

Pertanto, la query che sto davvero cercando va in questo modo:

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

Ovviamente non funziona, quindi come posso ottenere un risultato simile?

' Ho provato a creare una stringa di query e ad EXECUTEinserirla, ma ciò restituisce semplicemente "Comando completato con successo" e non sembra restituire un set di righe. Si è scoperto che stavo usando una query errata per creare l'SQL dinamico e come tale ho creato una stringa vuota. SQL Server ha sicuramente eseguito correttamente la stringa vuota.

Si noti che il motivo per cui ho bisogno che ciò accada, piuttosto che semplicemente codificare i nomi delle colonne, è che i nomi delle colonne sono configurabili dall'utente.


1
Cosa succede se STAMPA la stringa di query, copia / incolla in una nuova finestra di query ed eseguila lì?
DenisT,

"Configurabile dall'utente" significa che ci sono centinaia o migliaia di tipi e / o alias che vengono cambiati frequentemente? Se gli alias sono abbastanza stabili, consiglierei di creare una serie di viste.
Jon of All Trades,

@DenisT, non genera nulla, il che forse indica che anche qualcos'altro è sbagliato. Grazie per il vantaggio.
Hotchips

@JonofAllTrades Sfortunatamente, sebbene siano abbastanza stabili, fa molto parte delle specifiche che quando l'utente cambia qualcosa nel software, anche questa cosa deve cambiare nei rapporti.
Hotchips

@DenisT Si è scoperto che le mie subquery utilizzate per creare l'SQL dinamico erano errate e restituivano set null. Quindi SQL Server ha restituito una query vuota, che è stata debitamente eseguita correttamente. Grazie per aver sottolineato il comando PRINT.
Hotchips

Risposte:


12

Prova il seguente codice:

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

Questo restituisce l'istruzione SELECT: SELECT CONVERT(INT, Col1) AS [AccountID],CONVERT(VARCHAR(50), Col2) AS [AccountName],CONVERT(DATE, Col3) AS [AccountOpenDate] FROM #Data WHERE [Type] = 'Account'


L'uso di SQL dinamico è la risposta corretta, dato che la domanda ha chiesto come farlo con SQL. Era anche qualcosa che avevo cercato di fare, ma in modo errato.
Hotchips

Tenete a mente che se si accettano input dell'utente e di utilizzarlo per costruire SQL dinamico, allora davvero, davvero bisogno di essere preoccupato per SQL injection e ingressi sanificazione. bobby-tables.com
Jonathan Van Matre,

@JonathanVanMatre Assolutamente. Fortunatamente, questo è solo per uso interno e tutti gli input sono già disinfettati dall'app.
Hotchips

7

Questo suona perfetto per una soluzione di visualizzazione front-end. La query 1 ritira i dati, la query 2 ritira i nomi delle colonne e nel codice quando costruisci la struttura che usi per visualizzare le impostazioni della seconda query.

Mentre un metodo Pure SQL può essere possibile, sarà SQL dinamico e la manutenzione del codice sarebbe un incubo.

Inoltre, probabilmente stai cercando sp_executesqle non solo EXECUTE N'Query String'perché ciò potrebbe risolvere il problema del comando completato correttamente.


Sono d'accordo e potrei sicuramente farlo in SSRS, ma non posso farlo nell'altro software di reporting che sto utilizzando al momento.
Hotchips
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.