LIKE 문에서 PIVOT이 가능합니까?


9

그것은 (같이 소자 군 수있다 COLUMN LIKE='Value%'A의) PIVOT표? [DBT]. [Status] 테이블이 있는데, 여기에는 데이터베이스, 인스턴스 등의 다양한 상태가 포함되어 있으며 모든 PROD 및 TEST 값을 단일 값으로 피벗 / 쿼리하고 싶지는 않지만 그룹화하십시오.

예 대신 상태에 대한 항목을 갖는들 Prod, Prod ACC, Prod APP, ... 등은 I 값을 포함하는 하나의 칼럼 것 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

테이블 값

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')

피봇 상태 테이블

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

지금까지 출력

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 <> 바이올린

dbfiddle 지금까지.

질문

다양한 값 Test...Prod....값에 대해 여러 행을 갖는 대신 다음과 같이 그룹화하는 것이 좋습니다.

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

내 질문을 해결하는 방법에 대한 단서가 없습니다. (솔직히 말해서 나는 어제 광대 한 시행 착오 끝에 PIVOT을 잡았습니다.)

이 질문은 이미 요청한 여러 테이블에 대해 그룹화 된 항목의 합계 / 횟수를 만드는 방법 과 관련이 있습니다 . [DBT]. [인스턴스] 및 [DBT]. [데이터베이스] 테이블에는 현재보고있는 테이블에 해당하는 [StatusID]가있는 열이 있습니다.

답변:


11

합 (CASE)

제한된 수의 이름에 대해 다음과 같은 방식으로 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];

피벗

광범위한 이름 목록이 있지만 그 중 몇 개만 다시 작성해야하는 경우 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 <> 바이올린 여기

동적 쿼리

약간 게으르고 모든 열 이름을 쓰지 않으려는 경우 동적 쿼리를 사용할 수 있습니다.

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 <> 바이올린 여기


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) ;

...에서 시드 레코드 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;

전체 dbfiddle


귀하의 솔루션에 감사드립니다, 그것은 아주 좋은 해결책입니다. 그러나 현재 기존 테이블 정의를 수정하거나 데이터베이스 디자인에 추가 할 수 없습니다.
John aka hot2use

1
데이터를 제어 할 수있는 방식으로 먼저 데이터를 임시 테이블로 선택하십시오. 원하는 경우 임시 테이블을 선택하여 표시하십시오. 쿼리가 완료되면 임시 프로 시저를 선택하고 완료 한 후 삭제하도록 자동으로 처리하는 저장 프로 시저로 쿼리를 구울 수 있습니다.
khaoliang
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.