Search code examples
sql-serverxmlvalidationsql-server-2012schema

How do I validate SQL tables data using a schema


My understanding is poor so really need a place to start looking for information.

I have 4 SQL tables of data. I would like to output all of them to an XML file.

I have an XML Schema to work with but no idea how to use it or where it should be used.

Long term objective is to have 30 hand off tables which we can run validation scripts against and then using the XML Scheme given generate 1 XML file for submission.

I am a novice here and learning as I go so any suggestions where to look would be appreciated.

SAMPLE XML DATA

<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2013 rel. 2 sp2 (http://www.altova.com)-->
-<MSDS:MSDS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:MSDS="http://www.datadictionary.nhs.uk/messages/MSDS-v1-0" xsi:schemaLocation="http://www.datadictionary.nhs.uk/messages/MSDS-v1-0 ../Schemas/MSDSMSDS_XMLSchema-v1-0.xsd">

-<MATHDRHeader>

<Version>1.0</Version>
<OrgCodeProv>5BC</OrgCodeProv>
<OrgCodeSubmitter>YEA</OrgCodeSubmitter>
<RPStartDate>2013-01-01</RPStartDate>
<RPEndDate>2013-03-12</RPEndDate>
<FileCreationDateTime>2013-03-13T13:00:27</FileCreationDateTime>
<RecordCount>1</RecordCount>


-<MAT001MothersDemographics>

<LocalPatientIdMother>112552254</LocalPatientIdMother>
<OrgCodeLocalPatientIdMother>5BC</OrgCodeLocalPatientIdMother>
<OrgCodeRes>5BC</OrgCodeRes>
<NHSNumberMother>1111111111</NHSNumberMother>
<NHSNumberStatusMother>01</NHSNumberStatusMother>
<PersonBirthDateMother>1982-01-05</PersonBirthDateMother>
<Postcode>LS1 4HY</Postcode>
<EthnicCategoryMother>99</EthnicCategoryMother>
<PersonDeathDateTimeMother>1900-01-01T00:00:00</PersonDeathDateTimeMother>


-<MAT003GPPracticeRegistration>

<LocalPatientIdMother>112552254</LocalPatientIdMother>
<OrgCodeGMPMother>4RT</OrgCodeGMPMother>
<StartDateGMPRegistration>2012-01-06</StartDateGMPRegistration>
<EndDateGMPRegistration>1900-01-01</EndDateGMPRegistration>
<OrgCodeCommissioner>6TY</OrgCodeCommissioner>
</MAT003GPPracticeRegistration>


-<MAT101BookingAppointmentDetails>

<AntenatalAppDate>2013-03-01</AntenatalAppDate>
<LocalPatientIdMother>112552254</LocalPatientIdMother>
<EDDAgreed>2013-05-01</EDDAgreed>
<EDDMethodAgreed>01</EDDMethodAgreed>
<PregnancyFirstContactDate>2013-11-11</PregnancyFirstContactDate>
<PregnancyFirstContactCareProfessionalType>060</PregnancyFirstContactCareProfessionalType>
<LastMenstrualPeriodDate>2012-10-01</LastMenstrualPeriodDate>
<PhysicalDisabilityStatusIndMother>Y</PhysicalDisabilityStatusIndMother>
<FirstLanguageEnglishIndMother>Y</FirstLanguageEnglishIndMother>
<EmploymentStatusMother>04</EmploymentStatusMother>
<SupportStatusMother>Y</SupportStatusMother>
<EmploymentStatusPartner>06</EmploymentStatusPartner>
<PreviousCaesareanSections>0</PreviousCaesareanSections>
<PreviousLiveBirths>0</PreviousLiveBirths>
<PreviousStillBirths>0</PreviousStillBirths>
<PreviousLossesLessThan24Weeks>0</PreviousLossesLessThan24Weeks>
<SubstanceUseStatus>01</SubstanceUseStatus>
<SmokingStatus>03</SmokingStatus>
<CigarettesPerDay>0</CigarettesPerDay>
<AlcoholUnitsPerWeek>0</AlcoholUnitsPerWeek>
<FolicAcidSupplement>03</FolicAcidSupplement>
<MHPredictionDetectionIndMother>N</MHPredictionDetectionIndMother>
<PersonWeight>75.0</PersonWeight>
<PersonHeight>1.45</PersonHeight>
<ComplexSocialFactorsInd>N</ComplexSocialFactorsInd>

</MAT101BookingAppointmentDetails>

</MATHDRHeader>

</MSDS:MSDS>

SAMPLE XDS

 <xs:complexType name="MSDSMAT001MothersDemographicsType">
      <xs:sequence>
         <xs:element name="LocalPatientIdMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>LOCAL PATIENT IDENTIFIER (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="OrgCodeLocalPatientIdMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>ORGANISATION CODE (LOCAL PATIENT IDENTIFIER (MOTHER))</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="OrgCodeRes" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>ORGANISATION CODE (RESIDENCE RESPONSIBILITY)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="NHSNumberMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>NHS NUMBER (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="NHSNumberStatusMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>NHS NUMBER STATUS INDICATOR CODE (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="PersonBirthDateMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>PERSON BIRTH DATE (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="Postcode" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>POSTCODE OF USUAL ADDRESS (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="EthnicCategoryMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>ETHNIC CATEGORY (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="PersonDeathDateTimeMother" type="ST" minOccurs="0" maxOccurs="1">
            <xs:annotation>
               <xs:appinfo>PERSON DEATH DATE TIME (MOTHER)</xs:appinfo>
            </xs:annotation>
         </xs:element>
         <xs:element name="MAT003GPPracticeRegistration" type="MSDSMAT003GPPracticeRegistrationType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT101BookingAppointmentDetails"
                     type="MSDSMAT101BookingAppointmentDetailsType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT112DatingScanProcedure" type="MSDSMAT112DatingScanProcedureType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT201BloodGroupRhesusTest" type="MSDSMAT201BloodGroupRhesusTestType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT203RubellaSusceptibilityTest"
                     type="MSDSMAT203RubellaSusceptibilityTestType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT205HepatitisBScreeningTest"
                     type="MSDSMAT205HepatitisBScreeningTestType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT210AsymptomaticBacteriuriaScreeningOffer"
                     type="MSDSMAT210AsymptomaticBacteriuriaScreeningOfferType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT211HaemoglobinopathyScreeningTest"
                     type="MSDSMAT211HaemoglobinopathyScreeningTestType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT301MaternityCarePlan" type="MSDSMAT301MaternityCarePlanType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT303DownsSyndromeScreeningTest"
                     type="MSDSMAT303DownsSyndromeScreeningTestType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT305FetalAnomalyScreeningTest"
                     type="MSDSMAT305FetalAnomalyScreeningTestType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT306AntenatalAppointment" type="MSDSMAT306AntenatalAppointmentType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT307MedicalDiag" type="MSDSMAT307MedicalDiagType" minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT309MaternityObstetricDiag" type="MSDSMAT309MaternityObstetricDiagType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT310AntenatalAdmission" type="MSDSMAT310AntenatalAdmissionType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT404LabourAndDelivery" type="MSDSMAT404LabourAndDeliveryType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT408MCI" type="MSDSMAT408MCIType" minOccurs="0" maxOccurs="unbounded"/>
         <xs:element name="MAT501FetusOutcome" type="MSDSMAT501FetusOutcomeType" minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT502BabysDemographicsAndBirthDetails"
                     type="MSDSMAT502BabysDemographicsAndBirthDetailsType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT602PostpartumDischarge" type="MSDSMAT602PostpartumDischargeType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
         <xs:element name="MAT603PostpartumReadmission" type="MSDSMAT603PostpartumReadmissionType"
                     minOccurs="0"
                     maxOccurs="unbounded"/>
      </xs:sequence>
   </xs:complexType>

Solution

  • Appears this one is too hard as cant get a reply anywhere online on any site

    Well, I cannot let this pass unchallenged :-D

    too hard must be discussed... One problem is, that the schema, as well as the data you provide is not complete / invalid... In your attempts to shorten the provided sample data (which is great!) you created invalid sample data... I would have to invest a lot of time first to understand what you really want and then to set up a mock-up project.

    And now we are in the very center of too hard: I do not have the time for this...

    SQL Server doesn't support a built-in schema check or schema related export automatisms. Therefore I told you in my first comment, that T-SQL might be the wrong tool...

    You did not answer the question Are there any other tools / languages available ...

    This code is a very simple C# code. It will create the internal structure of the dataset out of a schema and then load the given XML into this DataSet. This will fail, when the XML is not compatible. That might be a schema check for you.

            var ds = new System.Data.DataSet("TestSchema");
            ds.ReadXmlSchema(@"C:\SomePath\MotherSchema.xml");
            ds.ReadXml(@"C:\SomePath\MotherData.xml");
    

    //The above in a try-catch, wrapped in a function might be enough as schema checked
    //The following code would read the data into a string to check the success (totally untested...)

            var sb = new System.Text.StringBuilder();
            foreach (var t in ds.Tables) {
                var tbl = t as System.Data.DataTable;
                foreach (var r in tbl.Rows) {
                    var rw = r as System.Data.DataRow;
                    foreach (var c in tbl.Columns) {
                        var cl = c as System.Data.DataColumn;
                        sb.AppendLine(string.Format("{0}.{1}: {2}",tbl.TableName,cl.ColumnName,rw[cl].ToString()));
                    }
                }
            }
            var str = sb.ToString();
    

    Finally (as pointed out in my comment If I understand this correctly, you do not need a schema at all) I'd create the XML using FOR XML PATH exactly the way you need it. That is roughly the same approach your complicated Access legacy code is doing: Just create a correct XML. Does the Access solution reflect any schema? Probably not... See what I mean?

    UPDATE Just to give you an idea:

    USE master;
    GO
    CREATE DATABASE TestDB;
    GO
    USE TestDB;
    GO
    

    --Some tiny tables with tiny data. More columns are just more of the same...

    CREATE TABLE MAT001MothersDemographics(ID BIGINT, Code VARCHAR(100));
    INSERT INTO MAT001MothersDemographics VALUES(1111111,'1A1')
                                               ,(222222,'2B2');
    
    CREATE TABLE MAT003GPPracticeRegistration(ID BIGINT,MotherID BIGINT,StartDate Date);
    INSERT INTO MAT003GPPracticeRegistration VALUES(1,111111,{d'2001-01-01'})
                                                  ,(2,222222,{d'2002-02-02'});
    

    --I create the innner XML without namespaces as they seem to appear in the outer most node only...

    DECLARE @MotherID BIGINT=222222;
    DECLARE @innerXML XML= --without namespaces
    (
    SELECT '1.0' AS [MVersion]
          ,'5BC' AS [OrgCodeProv]
          ,GETDATE() AS [FileCreationDateTime]
          ,(
            SELECT ID AS LocalPatientIdMother
                  ,Code AS OrgCodeLocalPatientIdMother
            FROM MAT001MothersDemographics
            WHERE ID=@MotherID
            FOR XML PATH('MAT001MothersDemographics'),TYPE
           )
          ,(
            SELECT MotherID AS LocalPatientIdMother
                  ,StartDate AS StartDateGMPRegistration
            FROM MAT003GPPracticeRegistration
            WHERE MotherID=@MotherID
            FOR XML PATH('MAT003GPPracticeRegistration'),TYPE
           )
    FOR XML PATH('MATHDRHeader')
    );
    

    --This will wrap the previously created XML with the <MSDS:MSDS> node

    WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' AS xsi 
                      ,'http://www.datadictionary.nhs.uk/messages/MSDS-v1-0' AS MSDS
                      ,'http://www.datadictionary.nhs.uk/messages/MSDS-v1-0 ../Schemas/MSDSMSDS_XMLSchema-v1-0.xsd' AS schemaLocation)
    SELECT @innerXML
    FOR XML PATH('MSDS:MSDS');
    

    --Clear Up

    GO
    USE master;
    GO
    DROP DATABASE TestDB;
    GO
    

    The result for this tiny portion look pretty much the way you need it:

        <MSDS:MSDS xmlns:schemaLocation="http://www.datadictionary.nhs.uk/messages/MSDS-v1-0 ../Schemas/MSDSMSDS_XMLSchema-v1-0.xsd" xmlns:MSDS="http://www.datadictionary.nhs.uk/messages/MSDS-v1-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
          <MATHDRHeader>
            <MVersion>1.0</MVersion>
            <OrgCodeProv>5BC</OrgCodeProv>
            <FileCreationDateTime>2017-04-21T10:45:57.590</FileCreationDateTime>
            <MAT001MothersDemographics>
              <LocalPatientIdMother>222222</LocalPatientIdMother>
              <OrgCodeLocalPatientIdMother>2B2</OrgCodeLocalPatientIdMother>
            </MAT001MothersDemographics>
            <MAT003GPPracticeRegistration>
              <LocalPatientIdMother>222222</LocalPatientIdMother>
              <StartDateGMPRegistration>2002-02-02</StartDateGMPRegistration>
            </MAT003GPPracticeRegistration>
          </MATHDRHeader>
        </MSDS:MSDS>