Bagaimana saya bisa secara dinamis alias kolom?

10

Saya punya tabel (tidak dirancang oleh saya) yang memiliki 20 kolom bernama variabel. Artinya, tergantung pada jenis catatan apa yang Anda lihat, nama kolom yang berlaku dapat berubah.

Kemungkinan nama kolom disimpan di tabel lain, yang dapat saya query dengan sangat mudah.

Karenanya, kueri yang benar-benar saya cari berjalan seperti ini:

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

Jelas itu tidak berhasil, jadi bagaimana saya bisa mendapatkan hasil yang serupa?

' Saya sudah mencoba membangun string kueri dan EXECUTEmemasukkannya, tetapi itu hanya mengembalikan "Perintah yang Berhasil Diselesaikan" dan sepertinya tidak mengembalikan rowset. Ternyata saya menggunakan kueri yang salah untuk membangun SQL dinamis dan karenanya membangun string kosong. SQL Server pasti mengeksekusi string kosong dengan benar.

Perhatikan bahwa alasan saya ingin ini terjadi, bukan hanya pengodean nama kolom yang sulit, adalah bahwa nama kolom dapat dikonfigurasi pengguna.

Hotchip
sumber
1
Apa yang terjadi jika Anda PRINT string kueri, salin / tempel ke jendela permintaan baru dan jalankan di sana?
DenisT
"Dapat dikonfigurasi pengguna" yang berarti ada ratusan atau ribuan jenis, dan / atau alias sering diubah? Jika aliasnya cukup stabil, saya sarankan membuat serangkaian tampilan.
Jon of All Trades
@Denis, Itu tidak menghasilkan apa-apa, yang mungkin menunjukkan ada sesuatu yang salah juga. Terima kasih atas petunjuknya.
Hotchips
@JonofAllTrades Sayangnya, sementara mereka cukup stabil, itu sangat banyak bagian dari spesifikasi bahwa ketika pengguna mengubah sesuatu dalam perangkat lunak, hal itu juga harus berubah dalam laporan.
Hotchips
@DenisT Ternyata subqueries saya yang digunakan untuk membangun SQL dinamis salah dan mengembalikan set nol. Jadi SQL Server mengembalikan kueri kosong, yang telah dieksekusi dengan sukses. Terima kasih telah menunjukkan perintah PRINT.
Hotchips

Jawaban:

12

Coba kode berikut:

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

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

Garthmillar
sumber
Menggunakan SQL dinamis adalah jawaban yang benar, mengingat pertanyaan itu bertanya bagaimana melakukannya dengan SQL. Itu juga sesuatu yang saya coba lakukan, tetapi salah.
Hotchips
Ingatlah bahwa jika Anda menerima input pengguna dan menggunakannya untuk membangun SQL dinamis, maka Anda benar- benar perlu khawatir tentang input injeksi SQL dan sanitasi. bobby-tables.com
Jonathan Van Matre
@JonathanVanMatre Benar-benar. Untungnya, ini hanya untuk penggunaan internal, dan semua input sudah dibersihkan oleh aplikasi.
Hotchips
7

Ini terdengar prima untuk solusi tampilan ujung depan. Kueri 1 akan menarik kembali data Anda, Kueri 2 akan menarik kembali nama kolom dan dalam kode ketika Anda membangun struktur apa pun yang Anda gunakan untuk menampilkan Anda mengatur header dari kueri kedua.

Sementara Metode SQL Murni dimungkinkan, itu akan menjadi SQL dinamis dan pemeliharaan kode akan menjadi mimpi buruk.

Mungkin Anda juga mencari sp_executesqldan tidak hanya EXECUTE N'Query String'karena itu dapat menyelesaikan masalah Anda dengan perintah yang berhasil diselesaikan.

RubberChickenLeader
sumber
Saya setuju, dan saya pasti bisa melakukan ini di SSR, tetapi saya tidak bisa melakukannya di perangkat lunak pelaporan lain yang saya gunakan saat ini.
Hotchips