SQL Server - 为每个可能的列组合

时间:2016-09-01 18:56:12

标签: sql sql-server

这是我一直试图回答的问题。这很难,所以请原谅长篇文章。

我有一个MS SQL Server数据库,其中的表格按名称对应于全球区域。还有另一个表,其中包含驻留在每个区域中的数据中心。在另一个表中,有一个在每个数据中心中运行的环境列表(DEV,PROD等)。另一方面,虚拟机"类型"在每个环境中运行。最后,在另一个表中,我有一个虚拟机列表,这些虚拟机处于"批准"用于部署。

vm"类型的一些例子"可能包括像"小","中"和"大"等标签。

我想创建一个select语句,该语句返回在该系列关系中具有所有可能组合的行,而不管数据中是否存在给定的虚拟机类型。

每一个:     从去年到明年的月份 - >显示已批准/未批准的VM的计数 - >每个虚拟机"类型",每个环境,每个数据中心,每个区域--->即使零/空

正如在这个答案中所建议的那样:SQL- pad results with extra rows我一直在使用像UNPIVOT和OUTER / CROSS APPLY这样的技巧,但无济于事,因为我不只是想获得二维结果。就我而言,有五个。

表格和数据(已简化):

USE [infra]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[datacenter](
   [datacenter_id] [int] IDENTITY(1,1) NOT NULL,
   [region_id] [int] NULL,
   [datacenter] [nvarchar](50) NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[env](
   [env_id] [int] IDENTITY(1,1) NOT NULL,
   [env] [nvarchar](50) NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[region](
   [region_id] [int] IDENTITY(1,1) NOT NULL,
   [region] [nvarchar](10) NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[vm_class](
   [vm_class_id] [int] IDENTITY(1,1) NOT NULL,
   [vm_class] [nvarchar](50) NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[virtual_machine](
   [virtual_machine_id] [int] IDENTITY(1,1) NOT NULL,
   [hostname] [nvarchar](255) NULL,
   [region] [nvarchar](255) NULL,
   [datacenter] [nvarchar](255) NULL,
   [env] [nvarchar](255) NULL,
   [approval_status] [nvarchar](255) NULL,
   [deployment_month] [date] NULL
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[datacenter] ON

GO
INSERT [dbo].[datacenter] ([datacenter_id], [region_id], [datacenter]) VALUES (1, 1, N'Datacenter A')
GO
INSERT [dbo].[datacenter] ([datacenter_id], [region_id], [datacenter]) VALUES (2, 2, N'Datacenter B')
GO
INSERT [dbo].[datacenter] ([datacenter_id], [region_id], [datacenter]) VALUES (3, 3, N'Datacenter C')
GO
INSERT [dbo].[datacenter] ([datacenter_id], [region_id], [datacenter]) VALUES (4, 4, N'Datacenter D')
GO
INSERT [dbo].[datacenter] ([datacenter_id], [region_id], [datacenter]) VALUES (5, 1, N'Datacenter E')
GO
SET IDENTITY_INSERT [dbo].[datacenter] OFF
GO
SET IDENTITY_INSERT [dbo].[env] ON

GO
INSERT [dbo].[env] ([env_id], [env]) VALUES (1, N'LAB')
GO
INSERT [dbo].[env] ([env_id], [env]) VALUES (2, N'DEV')
GO
INSERT [dbo].[env] ([env_id], [env]) VALUES (3, N'QA')
GO
INSERT [dbo].[env] ([env_id], [env]) VALUES (4, N'COB')
GO
INSERT [dbo].[env] ([env_id], [env]) VALUES (5, N'PROD')
GO
SET IDENTITY_INSERT [dbo].[env] OFF
GO
SET IDENTITY_INSERT [dbo].[region] ON

GO
INSERT [dbo].[region] ([region_id], [region]) VALUES (1, N'EUR')
GO
INSERT [dbo].[region] ([region_id], [region]) VALUES (2, N'APAC')
GO
INSERT [dbo].[region] ([region_id], [region]) VALUES (3, N'NAM')
GO
INSERT [dbo].[region] ([region_id], [region]) VALUES (4, N'LATAM')
GO
SET IDENTITY_INSERT [dbo].[region] OFF
GO
SET IDENTITY_INSERT [dbo].[vm_class] ON

GO
INSERT [dbo].[vm_class] ([vm_class_id], [vm_class]) VALUES (1, N'SMALL')
GO
INSERT [dbo].[vm_class] ([vm_class_id], [vm_class]) VALUES (2, N'MEDIUM')
GO
INSERT [dbo].[vm_class] ([vm_class_id], [vm_class]) VALUES (3, N'LARGE')
GO
INSERT [dbo].[vm_class] ([vm_class_id], [vm_class]) VALUES (4, N'ELASTIC')
GO
SET IDENTITY_INSERT [dbo].[vm_class] OFF
GO

这是我到目前为止编写的SQL,它没有返回完整的数据集(有#34;缺少"行,其中我期待NULL)

SELECT
    all_dates.unpivoted_date,
    r.region,
    d.datacenter,
    e.env,
    v.vm_class,
    ISNULL(SUM(virtual_machine), 0) AS [vm count]
FROM vmachines vms
FULL OUTER JOIN region r ON r.region = vms.region
FULL OUTER JOIN datacenter d on d.datacenter = vms.dc_label_final
FULL OUTER JOIN env e on e.env = fcast.env
FULL OUTER JOIN vm_class v on v.vm_class = vms.vm_class
FULL OUTER JOIN 
(
    SELECT CONVERT( DATE, mapped_date ) AS unpivoted_date FROM
    (
        SELECT
            DATEADD( MONTH, -13, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_12,
            DATEADD( MONTH, -12, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_11,
            DATEADD( MONTH, -11, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_10,
            DATEADD( MONTH, -10, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_09,
            DATEADD( MONTH, -9, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_08,
            DATEADD( MONTH, -8, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_07,
            DATEADD( MONTH, -7, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_06,
            DATEADD( MONTH, -6, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_05,
            DATEADD( MONTH, -5, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_04,
            DATEADD( MONTH, -4, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_03,
            DATEADD( MONTH, -3, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_02,
            DATEADD( MONTH, -2, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_01,
            DATEADD( MONTH, -1, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_00,
            DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) m_01,
            DATEADD( MONTH, 1, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_02,
            DATEADD( MONTH, 2, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_03,
            DATEADD( MONTH, 3, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_04,
            DATEADD( MONTH, 4, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_05,
            DATEADD( MONTH, 5, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_06,
            DATEADD( MONTH, 6, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_07,
            DATEADD( MONTH, 7, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_08,
            DATEADD( MONTH, 8, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_09,
            DATEADD( MONTH, 9, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_10,
            DATEADD( MONTH, 10, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_11,
            DATEADD( MONTH, 11, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_12
    ) pvt
    UNPIVOT
    (
        mapped_date FOR date_item IN
        (
            mp_12,          mp_11,          mp_10,          mp_09,
            mp_08,          mp_07,          mp_06,          mp_05,
            mp_04,          mp_03,          mp_02,          mp_01,
            m_00,           m_01,           m_02,           m_03,
            m_04,           m_05,           m_06,           m_07,
            m_08,           m_09,           m_10,           m_11,
            m_12
        )
    ) AS wd
) all_dates ON all_dates.unpivoted_date = CONVERT( DATE, vms.approval_month )
WHERE unpivoted_date IS NOT NULL
GROUP BY
    all_dates.unpivoted_date,
    r.region,
    d.datacenter,
    e.env, 
    v.vm_class
ORDER BY
    all_dates.unpivoted_date,
    r.region,
    d.datacenter,
    e.env,
    v.vm_class

2 个答案:

答案 0 :(得分:0)

我认为问题在于您是根据approval_month日期条件加入[vmachines]表,这将删除结果中的所有记录,其中特定区域/数据中心/类组合没有现有的vmachines记录。 / p>

在没有日期信息的情况下尝试查询的简化版本,以验证没有日期加入,将返回完整记录。

SELECT
    r.region,
    d.datacenter,
    e.env,
    v.vm_class,
    ISNULL(SUM(virtual_machine), 0) AS [vm count]
FROM vmachines vms
FULL OUTER JOIN region r ON r.region = vms.region
FULL OUTER JOIN datacenter d on d.datacenter = vms.dc_label_final
FULL OUTER JOIN env e on e.env = fcast.env
FULL OUTER JOIN vm_class v on v.vm_class = vms.vm_class
GROUP BY r.region, d.datacenter, e.env, v.vm_class

作为解决方案,请考虑创建一个用户函数,该函数将approval_month转换为所需的月份类别以包含在SELECT和GROUP BY中。

select
    .....
    dbo.ApprovalMonth(vms.approval_month) as appmonth
GROUP BY .....,  appmonth

当批准日期值为NULL(没有匹配的区域/数据中心/类组合)或返回您选择的字符串时,该函数可以返回NULL。

答案 1 :(得分:0)

这是适合我的SQL代码(交叉连接,unpivots和子查询的组合):

SELECT xjoin.*,
COUNT(virtual_machine.*) AS [vm count]
-- and I also added a few more aggregate functions here --
FROM
(
    SELECT
        r.region,
        d.datacenter,
        e.env,
        v.vm_class,
        all_dates.unpivoted_date
    FROM region r
    CROSS JOIN datacenter d
    CROSS JOIN env e
    CROSS JOIN vm_class v
    CROSS JOIN
    (
        SELECT CONVERT( DATE, mapped_date ) AS unpivoted_date FROM
        (
            SELECT
                DATEADD( MONTH, -13, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_12,
                DATEADD( MONTH, -12, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_11,
                DATEADD( MONTH, -11, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_10,
                DATEADD( MONTH, -10, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_09,
                DATEADD( MONTH, -9, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_08,
                DATEADD( MONTH, -8, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_07,
                DATEADD( MONTH, -7, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_06,
                DATEADD( MONTH, -6, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_05,
                DATEADD( MONTH, -5, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_04,
                DATEADD( MONTH, -4, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_03,
                DATEADD( MONTH, -3, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_02,
                DATEADD( MONTH, -2, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) mp_01,
                DATEADD( MONTH, -1, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_00,
                DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) m_01,
                DATEADD( MONTH, 1, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_02,
                DATEADD( MONTH, 2, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_03,
                DATEADD( MONTH, 3, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_04,
                DATEADD( MONTH, 4, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_05,
                DATEADD( MONTH, 5, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_06,
                DATEADD( MONTH, 6, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_07,
                DATEADD( MONTH, 7, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_08,
                DATEADD( MONTH, 8, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_09,
                DATEADD( MONTH, 9, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_10,
                DATEADD( MONTH, 10, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_11,
                DATEADD( MONTH, 11, ( DATEADD( DAY, 1, EOMONTH( CURRENT_TIMESTAMP ) ) ) ) m_12
        ) pvt
        UNPIVOT
        (
            mapped_date FOR date_item IN
            (
                mp_12,          mp_11,          mp_10,          mp_09,
                mp_08,          mp_07,          mp_06,          mp_05,
                mp_04,          mp_03,          mp_02,          mp_01,
                m_00,           m_01,           m_02,           m_03,
                m_04,           m_05,           m_06,           m_07,
                m_08,           m_09,           m_10,           m_11,
                m_12
            )
        ) AS wd
    ) all_dates
) xjoin
FULL OUTER JOIN [virtual_machine] vm ON
    vm.deployment_month = xjoin.unpivoted_date
    AND vm.region = xjoin.region
    AND vm.datacenter = xjoin.datacenter
    AND vm.env = xjoin.env
    AND vm.vm_class = xjoin.vm_class
GROUP BY
    xjoin.region,
    xjoin.datacenter,
    xjoin.env,
    xjoin.vm_class,
    xjoin.unpivoted_date
ORDER BY
    region,
    datacenter,
    env,
    vm_class,
    unpivoted_date