Jak mogę dynamicznie aliasować kolumny?

10

Mam tabelę (nie zaprojektowaną przeze mnie), która ma 20 kolumn o różnych nazwach. Oznacza to, że w zależności od rodzaju rekordu, którego szukasz, odpowiednia nazwa kolumny może ulec zmianie.

Możliwe nazwy kolumn są przechowywane w innej tabeli, którą mogę bardzo łatwo wyszukać.

Dlatego zapytanie, którego tak naprawdę szukam, wygląda mniej więcej tak:

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

Oczywiście to nie działa, więc jak mogę uzyskać podobny wynik?

Próbowałem zbudować ciąg zapytania i EXECUTEgo ing, ale to po prostu zwraca„ Polecenia zakończone pomyślnie ”i nie wydaje się, aby zwrócił zestaw wierszy. Okazuje się, że użyłem niepoprawnego zapytania do zbudowania dynamicznego SQL i jako taki zbudowałem pusty ciąg. SQL Server zdecydowanie poprawnie wykonał pusty ciąg.

Zauważ, że powód, dla którego muszę to mieć miejsce, zamiast prostego kodowania nazw kolumn, polega na tym, że nazwy kolumn można konfigurować przez użytkownika.

Hotchips
źródło
1
Co się stanie, jeśli WYDRUKujesz ciąg zapytania, skopiujesz / wkleisz do nowego okna zapytania i tam go wykonasz?
DenisT,
„Konfigurowalny przez użytkownika” oznacza, że ​​istnieją setki lub tysiące typów i / lub aliasów, które są często zmieniane? Jeśli aliasy są dość stabilne, polecam utworzenie serii widoków.
Jon of All Trades
@DenisT, nic nie wyświetla, co może oznaczać, że coś jeszcze jest nie tak. Dzięki za prowadzenie.
Hotchips
@JonofAllTrades Niestety, mimo że są one dość stabilne, jest to w dużej mierze specyfikacja, że ​​kiedy użytkownik zmienia coś w oprogramowaniu, to również musi się zmienić w raportach.
Hotchips
@DenisT Okazuje się, że moje podzapytania użyte do zbudowania dynamicznego SQL były niepoprawne i zwróciły zestawy zerowe. Tak więc SQL Server zwrócił puste zapytanie, które poprawnie wykonał. Dziękujemy za wskazanie polecenia PRINT.
Hotchips

Odpowiedzi:

12

Wypróbuj następujący kod:

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

Zwraca instrukcję SELECT: SELECT CONVERT(INT, Col1) AS [AccountID],CONVERT(VARCHAR(50), Col2) AS [AccountName],CONVERT(DATE, Col3) AS [AccountOpenDate] FROM #Data WHERE [Type] = 'Account'

garthmillar
źródło
Używanie dynamicznego SQL jest poprawną odpowiedzią, biorąc pod uwagę, że pytanie dotyczy tego, jak to zrobić z SQL. Próbowałem to zrobić, ale niepoprawnie.
Hotchips
Pamiętaj, że jeśli akceptujesz dane wprowadzane przez użytkownika i używasz ich do budowania dynamicznego SQL, naprawdę musisz naprawdę martwić się wprowadzaniem SQL i odkażaniem danych wejściowych. bobby-tables.com
Jonathan Van Matre
@JonathanVanMatre Absolutnie. Na szczęście jest to tylko do użytku wewnętrznego, a wszystkie dane wejściowe są już zdezynfekowane przez aplikację.
Hotchips
7

Brzmi to najlepiej w przypadku wyświetlacza front-end. Zapytanie 1 odciągnęłoby twoje dane, Zapytanie 2 odciągnęłoby nazwy kolumn i kodu, kiedy budujesz jakąkolwiek strukturę, której używasz do wyświetlania, ustawiasz nagłówki z drugiego zapytania.

Chociaż czysta metoda SQL może być możliwa, będzie to dynamiczny SQL, a utrzymanie kodu byłoby koszmarem.

Również prawdopodobnie szukasz, sp_executesqla nie tylko to, EXECUTE N'Query String'że może to rozwiązać problem polecenia zakończony powodzeniem.

RubberChickenLeader
źródło
Zgadzam się i zdecydowanie mogę to zrobić w SSRS, ale nie mogę tego zrobić w innym oprogramowaniu do raportowania, którego obecnie używam.
Hotchips