¿Cómo puedo dinámicamente alias columnas?


10

Tengo una tabla (no diseñada por mí) que tiene 20 columnas con nombres variables. Es decir, dependiendo del tipo de registro que esté viendo, el nombre aplicable de la columna puede cambiar.

Los posibles nombres de columna se almacenan en otra tabla, que puedo consultar muy fácilmente.

Por lo tanto, la consulta que realmente estoy buscando es algo como esto:

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 eso no funciona, entonces, ¿cómo puedo obtener un resultado similar?

' He intentado construir una cadena de consulta e EXECUTEing, pero eso solo devuelve "Comando (s) completados con éxito" y no parece devolver un conjunto de filas. Resulta que estaba usando una consulta incorrecta para construir el SQL dinámico y, como tal, construí una cadena vacía. SQL Server definitivamente ejecutó la cadena vacía correctamente.

Tenga en cuenta que la razón por la que necesito que esto ocurra, en lugar de simplemente codificar los nombres de las columnas, es que los nombres de las columnas son configurables por el usuario.


1
¿Qué sucede si IMPRIME la cadena de consulta, copia / pega en una nueva ventana de consulta y la ejecuta allí?
DenisT

"Configurable por el usuario", lo que significa que hay cientos o miles de tipos y / o alias que se cambian con frecuencia. Si los alias son bastante estables, recomendaría crear una serie de vistas.
Jon of All Trades

@DenisT, no genera nada, lo que quizás indica que algo más está mal también. Gracias por el liderato.
Hotchips

@JonofAllTrades Desafortunadamente, aunque son bastante estables, es parte de la especificación que cuando el usuario cambia algo en el software, esa cosa también debe cambiar en los informes.
Hotchips

@DenisT Resulta que mis subconsultas utilizadas para construir el SQL dinámico eran incorrectas y devolvían conjuntos nulos. Entonces, SQL Server devolvió una consulta en blanco, que se ejecutó correctamente correctamente. Gracias por señalar el comando IMPRIMIR.
Hotchips

Respuestas:


12

Prueba el siguiente 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

Esto devuelve la instrucción SELECT: SELECT CONVERT(INT, Col1) AS [AccountID],CONVERT(VARCHAR(50), Col2) AS [AccountName],CONVERT(DATE, Col3) AS [AccountOpenDate] FROM #Data WHERE [Type] = 'Account'


El uso de SQL dinámico es la respuesta correcta, dado que la pregunta es cómo hacerlo con SQL. También fue algo que intenté hacer, pero incorrectamente.
Hotchips

Tenga en cuenta que si usted está aceptando la entrada del usuario y utilizarlo para construir el SQL dinámico, entonces realmente, realmente necesita preocuparse acerca de inyección SQL y entradas de desinfección. bobby-tables.com
Jonathan Van Matre

@ JonathanVanMatre Absolutamente. Afortunadamente, esto es solo para uso interno, y todas las entradas ya están desinfectadas por la aplicación.
Hotchips

7

Esto suena excelente para una solución de pantalla frontal. La consulta 1 retiraría sus datos, la consulta 2 retiraría los nombres de columna y el código cuando construye cualquier estructura que use para mostrar los encabezados de la segunda consulta.

Si bien es posible un método de SQL puro, será un SQL dinámico y el mantenimiento del código sería una pesadilla.

También es probable que sp_executesqlesté buscando y no solo EXECUTE N'Query String'eso puede solucionar su problema de comando completado con éxito.


Estoy de acuerdo, y definitivamente podría hacerlo en SSRS, pero no puedo hacerlo en el otro software de informes que estoy usando en este momento.
Hotchips
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.