Вот вопрос, на который я пытался ответить в течение довольно долгого времени. Это было сложно, поэтому, пожалуйста, простите длинный текст.SQL Server - выберите полный набор данных для каждой комбинации столбцов
У меня есть база данных MS SQL Server с таблицей, соответствующей всем регионам по всему миру. Есть еще одна таблица с центрами данных, которые находятся в каждом регионе. В другой таблице есть список сред (DEV, PROD и т. Д.), Которые запускаются в каждом центре обработки данных. В другом - список типов виртуальных машин, которые запускаются в каждой среде. Наконец, в другой таблице у меня есть список виртуальных машин на разных датированных этапах «утверждения» для развертывания.
Некоторые примеры «типов» vm могут включать теги, такие как «маленький», «средний» и «большой».
Я хотел бы создать оператор select, который возвращает строки со всеми возможными комбинациями внутри этого семейства отношений, независимо от того, действительно ли данный тип виртуальной машины существует в данных.
За каждый: месяц с прошлого года до следующего года -> количество показов одобренных/несанкционированных виртуальных машин -> для каждой виртуальной машины "тип" для каждой среды на каждый центр данных за область ---> даже если нуль/нуль
Как предлагалось в этом ответе: 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 я написал до сих пор, что не возвращает полный набор данных (там «отсутствует» строки, в которых я бы ожидайте 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
Просьба представить определение каждой таблицы и некоторые данные для работы с. спасибо –
Использование кросс-соединения меня приближает (я продолжаю работать над этим). Он работает, пока я не присоединяюсь к финальной таблице виртуальных машин. Если я не укажу достаточные критерии соответствия для объединения, суммы неточны, и запрос занимает много секунд. Однако, если я определен в критериях соединения для таблицы VM, я получаю точно такой же набор результатов, который я получаю, когда не использую cross-join. – RaWkStAr
Крест-соединение, в зависимости от размера ваших столов, даст вам огромный набор результатов. Если у вас даже было 100 строк в каждой из этих таблиц, вы бы вычислили таблицу со 100 * 100 * 100 * 100 * 100 строк или 10 000 000 000 строк. Технически правильно, что вы просите об этом, да, но на самом деле подумайте, хотите ли вы этого огромного декартового продукта. –