【问题标题】:Query with CROSS APPLY, trying to get a field based on an attribute value使用 CROSS APPLY 查询,尝试根据属性值获取字段
【发布时间】:2018-04-25 20:03:37
【问题描述】:

我尝试根据属性(文化)的值,从存储为 SQL Server 中 XML 的表单中获取所有字段名称。实际上,我可以获取文本值,但它们被连接到 FieldName 列中。

XML 结构如下所示:

<Form>
  <Field>
    <Field Name="email" Type="text" ColumnSize="6">
      <Localizations>
        <Localization Culture="fr">
          <Text>Adresse couriel</Text>
          <Placeholder>Entrez votre adresse courriel</Placeholder>
        </Localization>
        <Localization Culture="fr">
          <Text>Email</Text>
          <Placeholder>Enter your email</Placeholder>
        </Localization>
      </Localizations>
    </Field>
  </Fields>
</Form>

SQL 查询:

DECLARE @language VARCHAR(2)
SET @language = 'en'
SELECT 
    c.query('data(@Name)') AS FieldUniqueName, 
    c.query('data(./Localizations/Localization/Text)') AS FieldName, 
    c.query('data(@Type)') AS FieldType
FROM dbo.Form Form CROSS APPLY FormContent.nodes('/Form/Fields/Field') x(c)
WHERE Id = @formId
AND FormContent.exist('/Form/Fields/Field/Localizations/Localization[@Culture=sql:variable("@language")]') = 1

结果如下所示:

FieldUniqueName  |  FieldName             | FieldType
name             |  Nom Name              | text
email            |  Adresse couriel Email | text
phone            |  Téléphone Phone Number| text

两种语言都在 FieldName 列中!

我也尝试过:

...
c.value('data(./Localizations/Localization/Text)[1]', 'VARCHAR(100)') AS FieldName,
...

但我需要在 [1][2] 之间进行选择才能获得正确的语言...

【问题讨论】:

    标签: sql-server xml sql-server-2012 xml-attribute


    【解决方案1】:

    除此之外,您提供的 XML 中存在一些错误(两者的结构和“fr”),您可以试试这个:

    DECLARE @tbl TABLE(ID INT IDENTITY, FormContent XML);
    INSERT INTO @tbl VALUES
    (N'<Form>
      <Fields>
        <Field Name="email" Type="text" ColumnSize="6">
          <Localizations>
            <Localization Culture="fr">
              <Text>Adresse couriel</Text>
              <Placeholder>Entrez votre adresse courriel</Placeholder>
            </Localization>
            <Localization Culture="en">
              <Text>Email</Text>
              <Placeholder>Enter your email</Placeholder>
            </Localization>
          </Localizations>
        </Field>
      </Fields>
    </Form>');
    

    查询将根据您的变量返回 loc 值。

    DECLARE @language VARCHAR(2)
    SET @language = 'en'
    SELECT 
        fld.value(N'@Name',N'nvarchar(max)') AS FieldUniqueName, 
        fld.value(N'@Type',N'nvarchar(max)') AS FieldType, 
        loc.value(N'(Text/text())[1]','nvarchar(max)') AS LocalText, 
        loc.value(N'(Placeholder/text())[1]','nvarchar(max)') AS LocalPlaceholder
    FROM @tbl Form 
    CROSS APPLY FormContent.nodes(N'/Form/Fields/Field') AS A(fld)
    CROSS APPLY A.fld.nodes(N'Localizations/Localization[@Culture=sql:variable("@language")]') B(loc)
    WHERE Id = 1
    

    【讨论】:

    • 我会试一试,如果它满足我的要求,请标记您的答案。谢谢。
    【解决方案2】:

    好的,我找到了对我的问题的回应!我没有使用 where 子句,而是更改了我的 FieldName 的 XPath。像魅力一样工作:

    DECLARE @language VARCHAR(2)
    SET @language = 'en'
    SELECT 
        c.query('data(@Name)') AS FieldUniqueName, 
        c.query('data(./Localizations/Localization[@Culture=sql:variable("@language")]/Text)') AS FieldName, 
        c.query('data(@Type)') AS FieldType
    FROM dbo.Form Form CROSS APPLY FormContent.nodes('/Form/Fields/Field') x(c)
    WHERE Id = @formId
    

    【讨论】:

    • 您以前的 WHERE 子句将检查是否满足此条件 - XML 中的某个位置。好吧,它是...但是在这里使用data() 不是正确的...最好将条件打包到第二个.nodes() 调用中,如XQuery predicate
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-09
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多