sqlsql-serverxmlxsdxml-schema-collection

sql server, defined xml schema to column


i m trying to add the xml schema to the columns of my table. what i would to do is:

my problem is how to exclude some options in the schema, like the possibility to don t check empty elements.

so, for example:

create table #t1 (c1 int not null,c2 int null)

  select CONVERT(xml,(select *
    from #t1
    where 0=1
    for xml raw,elements,XMLSCHEMA('XXX')
    ))

this get me

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" targetNamespace="XXX" elementFormDefault="qualified">
  <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
  <xsd:element name="row">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="c1" type="sqltypes:int" />
        <xsd:element name="c2" type="sqltypes:int" minOccurs="0" />
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

how can define all elements with "minOccurs="0""??

thank you!


Solution

  • There is - for sure! - no easy going! The engine is obliged to return the schema as it was found. You might take the schema as an XML and modify it, you might use a string based approach (or some kind of regex). The following is a quirky, but working dynamic approach:

    The procedure sp_describe_first_result_set is used to get meta data of an unknown result set. You can store its return in a table.

    Using the information you can create a copy of your table, where all columns are nullable. Use this new table to get your schema:

    create table #FirstResult(is_hidden BIT
                             ,column_ordinal INT
                             ,name NVARCHAR(MAX)
                             ,is_nullable BIT
                             ,system_type_id BIT
                             ,system_type_name VARCHAR(MAX)
                             ,max_length INT
                             ,[precision] INT
                             ,scale INT
                             ,collation_name VARCHAR(MAX)
                             ,user_type_id INT
                             ,user_type_database VARCHAR(MAX)
                             ,user_type_schema VARCHAR(MAX)
                             ,user_type_name VARCHAR(MAX)
                             ,assembly_qualified_type_name VARCHAR(MAX)
                             ,xml_collection_id VARCHAR(MAX)
                             ,xml_collection_database VARCHAR(MAX)
                             ,xml_collection_schema VARCHAR(MAX)
                             ,xml_collection_name VARCHAR(MAX)
                             ,is_xml_document BIT
                             ,is_case_sensitive BIT
                             ,is_fixed_length_clr_type BIT
                             ,source_server VARCHAR(MAX)
                             ,source_database VARCHAR(MAX)
                             ,source_schema VARCHAR(MAX)
                             ,source_table VARCHAR(MAX)
                             ,source_column VARCHAR(MAX)
                             ,is_identity_column BIT
                             ,is_part_of_unique_key BIT
                             ,is_updateable BIT
                             ,is_computed_column BIT
                             ,is_sparse_column_set BIT
                             ,ordinal_in_order_by_list INT
                             ,order_by_is_descending BIT
                             ,order_by_list_length INT
                             ,tds_type_id INT
                             ,tds_length INT
                             ,tds_collation_id INT
                             ,tds_collation_sort_id INT);
    

    --Your use case

    create table #t1 (c1 int not null,c2 int null);
    GO
    
    INSERT INTO #FirstResult
    exec sp_describe_first_result_set @tsql=N'SELECT * FROM #t1';
    
    DECLARE @cmd NVARCHAR(MAX)=
    (
    SELECT N'DECLARE @tmp TABLE('
    +
    STUFF(
    (
    SELECT N',' + name + ' ' + system_type_name + N' NULL' 
    FROM #FirstResult
    FOR XML PATH(''),TYPE
    ).value('text()[1]','nvarchar(max)'),1,1,'')
    +N'); 
    SELECT * FROM @tmp AS SomeTable FOR XML RAW,ELEMENTS,XMLSCHEMA(''XXX'')'
    );
    EXEC (@cmd);
    
    GO
    drop table #t1;
    drop table #FirstResult;
    GO
    

    The result

    <xsd:schema targetNamespace="XXX" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sqltypes="http://schemas.microsoft.com/sqlserver/2004/sqltypes" elementFormDefault="qualified">
      <xsd:import namespace="http://schemas.microsoft.com/sqlserver/2004/sqltypes" schemaLocation="http://schemas.microsoft.com/sqlserver/2004/sqltypes/sqltypes.xsd" />
      <xsd:element name="row">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="c1" type="sqltypes:int" minOccurs="0" />
            <xsd:element name="c2" type="sqltypes:int" minOccurs="0" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>