Is it possible to group by elements (as in `COLUMN LIKE='Value%'`) in a `PIVOT` table? I have a table [DBT].[Status] which contains various statuses (of databases, instances, etc.) and don't want to pivot/query all the PROD and TEST values as single values, but group them. E.g. Instead of having columns for the statuses `Prod`, `Prod ACC`, `Prod APP`, .. etc. I would have only one column containing the values for `Name LIKE 'Prod%'` and `Name LIKE 'Test%'`. What I have so far: ## Table Definition 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 ## Table Values 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') ## The Pivoted Status Table 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 So Far 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<>fiddle The [dbfiddle][L2] so far. # Question Instead of having multiple rows for the various `Test...` and `Prod....` values, I would prefer to have them grouped, similar to the following: DB Status | Test | Prod | Migrated | Offline | Reserved --------------- | ---- | ---- | -------- | ------- | -------- Database Status | 4 | 4 | 1 | 1 | 1 I don't have any clue how to go about solving my question. (To be honest I only just grasped PIVOT yesterday after extensive trial and errors). *This question is loosely related to the question **[How to create sums/counts of grouped items over multiple tables][L1]** I have already asked. The tables [DBT].[Instance] and [DBT].[Database] contain a column with the [StatusID] which corresponds to the table we are looking at now.* [L1]: https://dba.stackexchange.com/q/163577/15356 [L2]: https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=c65a0d71de94fcf675301efe4078ae2a
I think it's important to strictly separate the two tasks you're trying to perform in one step here. 1. Classification 2. Transformation For classifying the data, my instinct here is to recommend a lookup table to rigorously map records to a parent class. e.g. ```sql 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) ; ``` ...where the seed record in `StatusType` (`ID`=1 for the `Status.StatusTypeID` default) is a placeholder record named "Unknown" or similar. When the lookup data is seeded and base records are updated with the correct keys, you can pivot to your heart's content. ```sql 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; ``` [Full dbfiddle][1] [1]: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=15c0a2eec15497f57be0c9f19a73c61a
**SUM(CASE** For a limited number of Names you can use a SUM(CASE solution in this way: 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]; **PIVOT** If there is an extensive list of Names but only few of them must be rewritten you can maintain the PIVOT solution: 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<>fiddle [here](https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=425fac8c5421fef07d33c301caa7e199)* **DYNAMIC QUERY** If you feel a bit lazy and don't want to write all column names, you can use a dynamic query: 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<>fiddle [here](https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=cefd5b16562b37968fd6cda43978400e)*