Apakah mungkin untuk PIVOT pada pernyataan LIKE

9

Apakah mungkin untuk mengelompokkan berdasarkan elemen (seperti dalam COLUMN LIKE='Value%') dalam PIVOTtabel? Saya memiliki tabel [DBT]. [Status] yang berisi berbagai status (dari basis data, instance, dll.) Dan tidak ingin melakukan pivot / kueri semua nilai PROD dan TEST sebagai nilai tunggal, tetapi kelompokkan.

Misalnya Alih-alih memiliki kolom untuk status Prod, Prod ACC, Prod APP, .. dll saya akan hanya memiliki satu kolom yang berisi nilai-nilai untuk Name LIKE 'Prod%'dan Name LIKE 'Test%'.

Apa yang saya miliki sejauh ini:

Definisi Tabel

CREATE TABLE [DBT].[Status](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_Status] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY],
 CONSTRAINT [IX_Status] UNIQUE NONCLUSTERED 
(
    [Name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]

GO

Nilai Tabel

INSERT INTO [DBT].[Status]
(
    -- ID -- this column value is auto-generated
    Name
)
VALUES
('Test ACC'),
('Test APP'),
('Test DBA'),
('Prod ACC'),
('Prod APP'),
('Prod DBA'),
('Prod'),
('Test'),
('Migrated'),
('Offline'),
('Reserved')

Tabel Status Berputar

SELECT 'Database Status' AS [DB Status], 
[1] AS [Test ACC], [2] AS [Test APP], [3] AS [Test DBA], [4] AS [Prod ACC], [5] AS [Prod APP], [6] AS [Prod DBA], [7] AS [Prod], [8] AS [Test], [9] AS [Migrated], [10] AS [Offline], [11] AS [Reserved] 
FROM 
(
    SELECT ID, Name  FROM [DBT].[Status]
) AS Source
PIVOT
(
    COUNT(Name) FOR ID IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11])
) AS PivotTable

Output Sejauh Ini

DB Status       Test ACC    Test APP    Test DBA    Prod ACC    Prod APP    Prod DBA    Prod        Test        Migrated    Offline     Reserved
--------------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
Database Status 1           1           1           1           1           1           1           1           1           1           1

db <> biola

The dbfiddle sejauh ini.

Pertanyaan

Alih-alih memiliki beberapa baris untuk berbagai Test... dan Prod....nilai - nilai, saya lebih suka untuk mereka dikelompokkan, mirip dengan yang berikut:

DB Status       | Test | Prod | Migrated | Offline | Reserved   
--------------- | ---- | ---- | -------- | ------- | --------
Database Status |    4 |    4 |        1 |       1 |        1

Saya tidak tahu bagaimana cara menyelesaikan pertanyaan saya. (Sejujurnya saya baru saja memahami PIVOT kemarin setelah banyak percobaan dan kesalahan).

Pertanyaan ini secara longgar terkait dengan pertanyaan Cara membuat jumlah / jumlah item yang dikelompokkan dalam beberapa tabel yang telah saya tanyakan. Tabel [DBT]. [Instance] dan [DBT]. [Database] berisi kolom dengan [StatusID] yang sesuai dengan tabel yang sedang kita lihat sekarang.

John alias hot2use
sumber

Jawaban:

11

SUM (KASUS

Untuk sejumlah Nama yang terbatas, Anda dapat menggunakan SUM (solusi KASUS dengan cara ini:

SELECT 
    'Database status' as [DB Status],
    SUM(CASE WHEN Name LIKE 'Test%' THEN 1 ELSE 0 END) As Test,
    SUM(CASE WHEN Name LIKE 'Prod%' THEN 1 ELSE 0 END) AS Prod,
    SUM(CASE WHEN Name = 'Migrated' THEN 1 ELSE 0 END) AS Migrated,
    SUM(CASE WHEN Name = 'Offline' THEN 1 ELSE 0 END) AS Offline,
    SUM(CASE WHEN Name = 'Reserved' THEN 1 ELSE 0 END) AS Reserved
FROM 
    [Status];

POROS

Jika ada daftar nama yang luas tetapi hanya sedikit dari mereka yang harus ditulis ulang, Anda dapat mempertahankan solusi PIVOT:

SELECT 'Database Status' AS [DB Status],
[Test], [Prod], [Migrated], [Offline], [Reserved]
FROM
(
    SELECT 
        ID, 
        CASE
            WHEN Name LIKE 'Test%' THEN 'Test'
            WHEN Name LIKE 'Prod%' THEN 'Prod'
            ELSE Name
        END AS Name
    FROM 
        [Status]
) AS Source
PIVOT
(
    COUNT(ID) FOR Name IN ([Test], [Prod], [Migrated], [Offline], [Reserved])
) AS PivotTable;

db <> biola di sini

QUERY DINAMIS

Jika Anda merasa sedikit malas dan tidak ingin menulis semua nama kolom, Anda dapat menggunakan kueri dinamis:

DECLARE @cols nvarchar(max);

SET @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(CASE WHEN Name LIKE 'Test%' THEN 'Test'
                                                    WHEN Name LIKE 'Prod%' THEN 'Prod'
                                                    ELSE Name END)
                   FROM [Status]
                   FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '');

DECLARE @cmd nvarchar(max);

SET @cmd = 
'SELECT ''Database Status'' AS [DB Status],' + @cols + ' FROM
    (SELECT 
        ID, 
        CASE
            WHEN Name LIKE ''Test%'' THEN ''Test''
            WHEN Name LIKE ''Prod%'' THEN ''Prod''
            ELSE Name
        END AS Name
    FROM 
        [Status]
) AS Source
PIVOT
(
    COUNT(ID) FOR Name IN (' + @cols + ')
) PVT'

EXEC(@cmd);

db <> biola di sini

McNets
sumber
7

Saya pikir sangat penting untuk memisahkan dengan ketat dua tugas yang Anda coba lakukan dalam satu langkah di sini.

  1. Klasifikasi
  2. Transformasi

Untuk mengklasifikasikan data, naluri saya di sini adalah merekomendasikan tabel pencarian untuk memetakan rekaman secara ketat ke kelas induk. misalnya

CREATE TABLE StatusType (
  ID     INT         IDENTITY PRIMARY KEY,
  [Name] VARCHAR(10) NOT NULL UNIQUE
);
GO
ALTER TABLE [Status] 
  ADD StatusTypeID INT NOT NULL 
    DEFAULT 1
    FOREIGN KEY REFERENCES StatusType (ID) ;

... tempat rekaman unggulan dalam StatusType( ID= 1 untuk Status.StatusTypeIDdefault) adalah catatan placeholder bernama "Tidak Dikenal" atau serupa.

Ketika data pencarian diunggah dan catatan dasar diperbarui dengan kunci yang benar, Anda dapat berputar ke isi hati Anda.

select 'Database Status' AS [DB Status],
    [Test], [Prod], [Migrated], [Offline], [Reserved]
from (
    select s.ID,
           st.Name as StatusTypeName
    from status s
    join statusType st on st.ID = s.StatusTypeID
) as Source
pivot (
    count(ID) for StatusTypeName in ([Test],[Prod],[Migrated],[Offline],[Reserved],[Unknown])
) as pvt;

Dbfiddle penuh

Peter Vandivier
sumber
Terima kasih atas solusinya, ini adalah solusi yang cukup bagus. Namun, saya saat ini tidak dapat mengubah definisi tabel yang ada atau menambah desain database.
John aka hot2use
1
Pilih data menjadi tabel sementara terlebih dahulu, dengan begitu Anda memiliki kendali atas data. Jatuhkan temptable setelah Anda memilih darinya untuk ditampilkan, jika Anda mau. Setelah kueri Anda selesai, Anda bisa memanggangnya menjadi prosedur tersimpan yang secara otomatis mengurus memilih ke dalam temptable dan menjatuhkannya setelah Anda selesai.
khaoliang