Проблема XML AUTO и UNION в SQL Server 2012 - PullRequest
0 голосов
/ 26 февраля 2019

Мы находимся в процессе обновления SQL Server 2008 R2 до SQL Server 2012 (я знаю, я знаю, у нас мало версий, но это временное решение), чтобы использовать некоторые функции, которые недоступныв 2008 году. В процессе мы выявили проблему / разницу в том, как SQL Server 2012 обрабатывает XML Auto при наличии оператора UNION.

Вот формат, который я пытаюсь достичь:

<Product Color="Black" EnglishProductName="Full-Finger Gloves, L" Customizable="0">
  <ProductSubCategory EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
</Product>
<Product Color="Black" EnglishProductName="Full-Finger Gloves, M" Customizable="0">
  <ProductSubCategory EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
</Product>
<Product Color="Black" EnglishProductName="Full-Finger Gloves, S" Customizable="0">
  <ProductSubCategory EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
</Product>
<Product Color="Black" EnglishProductName="Half-Finger Gloves, L" Customizable="0">
  <ProductSubCategory EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
</Product>
<Product Color="Black" EnglishProductName="Half-Finger Gloves, M" Customizable="0">
  <ProductSubCategory EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
</Product>
<Product Color="Black" EnglishProductName="Half-Finger Gloves, S" Customizable="0">
  <ProductSubCategory EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
</Product>

Вот код, который произвел вышеуказанное (с использованием AdventureWorksDB):

Select Distinct Product.Color, Product.EnglishProductName, 0 as Customizable,
    ProductSubCategory.EnglishProductSubcategoryName,
    ProductSubCategory.FrenchProductSubcategoryName
    From dbo.DimProduct as Product
    Inner Join dbo.DimProductSubcategory As ProductSubCategory On ProductSubCategory.ProductSubcategoryKey = Product.ProductSubcategoryKey
    For Xml Auto

Но как только я добавляю оператор UNION, он прерывает мой вывод XML:

<Product Color="Black" EnglishProductName="Full-Finger Gloves, L" Customizable="0" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Full-Finger Gloves, L" Customizable="1" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Full-Finger Gloves, M" Customizable="0" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Full-Finger Gloves, M" Customizable="1" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Full-Finger Gloves, S" Customizable="0" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Full-Finger Gloves, S" Customizable="1" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Half-Finger Gloves, L" Customizable="0" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Half-Finger Gloves, L" Customizable="1" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Half-Finger Gloves, M" Customizable="0" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Half-Finger Gloves, M" Customizable="1" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Half-Finger Gloves, S" Customizable="0" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />
<Product Color="Black" EnglishProductName="Half-Finger Gloves, S" Customizable="1" EnglishProductSubcategoryName="Gloves" FrenchProductSubcategoryName="Gants" />

Здесьэто код, который произвел выше:

Select Distinct Product.Color, Product.EnglishProductName, 0 as Customizable,
ProductSubCategory.EnglishProductSubcategoryName,
ProductSubCategory.FrenchProductSubcategoryName
From dbo.DimProduct as Product
Inner Join dbo.DimProductSubcategory As ProductSubCategory On ProductSubCategory.ProductSubcategoryKey = Product.ProductSubcategoryKey
Union
Select Distinct Product.Color, Product.EnglishProductName, 1 as Customizable,
ProductSubCategory.EnglishProductSubcategoryName,
ProductSubCategory.FrenchProductSubcategoryName
From dbo.DimProduct as Product
Inner Join dbo.DimProductSubcategory As ProductSubCategory On ProductSubCategory.ProductSubcategoryKey = Product.ProductSubcategoryKey
For Xml Auto

Мне нужно, чтобы ProductSubCategory оставалась дочерней по отношению к узлу Product в выводе XML даже с оператором UNION.UNION не влиял на вывод XML в 2008 году, но по какой-то причине SQL Server 2012 по-разному обрабатывает один и тот же оператор.Любая помощь приветствуется.Надеюсь, я был достаточно ясен.Спасибо.

1 Ответ

0 голосов
/ 27 февраля 2019

В следующий раз, пожалуйста, предоставьте некоторые примеры данных в формате расходных материалов, лучше всего использовать DDL, INSERT и ваш рабочий код как автономный MCVE .Это очень помогает.На этот раз я набрал его для вас:

Некоторые таблицы макетов с данными:

DECLARE @Product TABLE(ProductKey INT IDENTITY,Color VARCHAR(100),EnglishProductName VARCHAR(100),ProductSubcategoryKey INT);
INSERT INTO @Product VALUES('Black','Full-Finger Gloves, L',1)
                          ,('Black','Full-Finger Gloves, M',1)
                          ,('Black','Full-Finger Gloves, S',1)
                          ,('Black','Half-Finger Gloves, L',1)
                          ,('Black','Half-Finger Gloves, M',1)
                          ,('Black','Half-Finger Gloves, S',1);

DECLARE @ProductSubCategory TABLE(ProductSubcategoryKey INT IDENTITY,EnglishProductSubcategoryName VARCHAR(100));
INSERT INTO @ProductSubCategory VALUES('Gloves');

- в запросе используется FOR XML PATH вместо режима AUTO.Я объясню это позже

Select Distinct Product.Color AS [@Color]
              , Product.EnglishProductName AS [@EnglishProductName]
              , 0 as [@Customizable]
              , ProductSubCategory.EnglishProductSubcategoryName AS [ProductSubCategory/@EnglishProductSubcategoryName]
    From @Product as Product
    Inner Join @ProductSubCategory As ProductSubCategory On ProductSubCategory.ProductSubcategoryKey = Product.ProductSubcategoryKey

UNION 
Select Distinct Product.Color AS [@Color]
              , Product.EnglishProductName AS [@EnglishProductName]
              , 1 as [@Customizable]
              , ProductSubCategory.EnglishProductSubcategoryName AS [ProductSubCategory/@EnglishProductSubcategoryName]
    From @Product as Product
    Inner Join @ProductSubCategory As ProductSubCategory On ProductSubCategory.ProductSubcategoryKey = Product.ProductSubcategoryKey
For Xml PATH('Product');

Некоторое объяснение:

Ваш подход с AUTO позволяет двигателю решить, что вы получите.Вообще мне не нравится такая идея.Любое изменение внутренней реализации может взорвать систему в производстве.Лучше использовать PATH, что дает вам самый глубокий контроль над тем, что вы получите.

Некоторые замечания:

Объединение не требуется

ЕслиЯ правильно понял, вы используете UNION просто для добавления каждого продукта дважды.Одна строка с нулем в @Customizable, вторая с 1. Простой CROSS JOIN с набором VALUES будет делать то же самое, но быстрее и лучше читать:

Select Distinct Product.Color AS [@Color]
              , Product.EnglishProductName AS [@EnglishProductName]
              , A.Customizable as [@Customizable]
              , ProductSubCategory.EnglishProductSubcategoryName AS [ProductSubCategory/@EnglishProductSubcategoryName]
    From @Product as Product
    Inner Join @ProductSubCategory As ProductSubCategory On ProductSubCategory.ProductSubcategoryKey = Product.ProductSubcategoryKey
    CROSS JOIN (VALUES(1),(0)) A(Customizable)
For Xml PATH('Product')

Удобочитаемость

Хорошо использовать псевдонимы таблиц, но я бы предложил использовать более короткие псевдонимы, как здесь

Select Distinct p.Color AS [@Color]
              , p.EnglishProductName AS [@EnglishProductName]
              , A.Customizable as [@Customizable]
              , sc.EnglishProductSubcategoryName AS [ProductSubCategory/@EnglishProductSubcategoryName]
    From @Product as p
    Inner Join @ProductSubCategory As sc On sc.ProductSubcategoryKey = p.ProductSubcategoryKey
    CROSS JOIN (VALUES(1),(0)) A(Customizable)
For Xml PATH('Product');

Структура

Рано или поздно у вас появится продукт, который входит в состав нескольких подкатегорий.Я бы посоветовал спроектировать это как n:m связанную систему с таблицей сопоставления между

Окончательный XML

Поскольку ваша подкатегория больше похожа на Семейство продуктов Вы можете создать что-то вроде

<ProductSubCategory EnglishProductSubcategoryName="Gloves">
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, L" Customizable="0" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, L" Customizable="1" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, M" Customizable="0" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, M" Customizable="1" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, S" Customizable="0" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, S" Customizable="1" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, L" Customizable="0" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, L" Customizable="1" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, M" Customizable="0" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, M" Customizable="1" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, S" Customizable="0" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, S" Customizable="1" />    
<ProductSubCategory>

Или даже проще

<ProductSubCategory EnglishProductSubcategoryName="Gloves">
  <Customizable value=1>
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, L" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, M" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, S" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, L" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, M" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, S" />    
  </Customizable>
  <Customizable value=0>
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, L" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, M" />
    <Product Color="Black" EnglishProductName="Full-Finger Gloves, S" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, L" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, M" />
    <Product Color="Black" EnglishProductName="Half-Finger Gloves, S" />    
  </Customizable>
<ProductSubCategory>
...