是否可以在 LIKE 语句上进行 PIVOT

Joh*_* N. 10 sql-server pivot sql-server-2014

是否可以按表中的元素(如COLUMN LIKE='Value%')进行分组PIVOT?我有一个表 [DBT].[Status],其中包含各种状态(数据库、实例等),并且不想将所有 PROD 和 TEST 值作为单个值进行透视/查询,而是将它们分组。

例如代替具有用于状态列ProdProd ACCProd APP,...等。我将仅有一个包含的值列Name LIKE 'Prod%'Name LIKE 'Test%'

到目前为止我所拥有的:

表定义

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
Run Code Online (Sandbox Code Playgroud)

表值

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')
Run Code Online (Sandbox Code Playgroud)

透视状态表

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
Run Code Online (Sandbox Code Playgroud)

到目前为止的输出

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
Run Code Online (Sandbox Code Playgroud)

数据库<>小提琴

到目前为止的dbfiddle

我宁愿将它们分组,而不是为各种Test...Prod....值设置多行,类似于以下内容:

DB Status       | Test | Prod | Migrated | Offline | Reserved   
--------------- | ---- | ---- | -------- | ------- | --------
Database Status |    4 |    4 |        1 |       1 |        1
Run Code Online (Sandbox Code Playgroud)

我不知道如何解决我的问题。(老实说,经过大量的反复试验,我昨天才刚刚掌握了 PIVOT)。

这个问题与我已经问过的如何在多个表上创建分组项目的总和/计数的问题松散相关。表 [DBT].[Instance] 和 [DBT].[Database] 包含一个带有 [StatusID] 的列,它对应于我们现在正在查看的表。

McN*_*ets 12

总和(案例

对于有限数量的名称,您可以以这种方式使用 SUM(CASE 解决方案:

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];
Run Code Online (Sandbox Code Playgroud)

如果有大量名称列表但只有少数名称必须重写,您可以维护 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;
Run Code Online (Sandbox Code Playgroud)

db<>在这里摆弄

动态查询

如果你觉得有点懒,不想写所有的列名,可以使用动态查询:

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);
Run Code Online (Sandbox Code Playgroud)

db<>在这里摆弄


Pet*_*ier 7

我认为在此处的一个步骤中严格区分您尝试执行的两项任务非常重要。

  1. 分类
  2. 转型

为了对数据进行分类,我的直觉是推荐一个查找表来将记录严格映射到父类。例如

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) ;
Run Code Online (Sandbox Code Playgroud)

...其中的种子记录StatusType(默认ID为 =1 Status.StatusTypeID)是一个名为“未知”或类似的占位符记录。

当查找数据被播种并使用正确的键更新基本记录时,您可以转至您的核心内容。

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;
Run Code Online (Sandbox Code Playgroud)

完整的 dbfiddle

  • 首先将数据选择到临时表中,这样您就可以控制数据。如果需要,在从中选择要显示的模板后,将其删除。查询完成后,您可以将其烘焙到存储过程中,该存储过程会自动选择临时表并在完成后将其删除。 (2认同)