这是我一直试图回答的问题。这很难,所以请原谅长篇文章。
我有一个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
答案 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