Help on Generating XML

  • I am having problem on how to generate an XML out of this data below.

    Sample Data:

    SELECT 'Region1' AS Description,'NULL' AS StoreID,'NULL' AS CompanyID,0 AS Level UNION ALL

    SELECT 'District1','NULL','NULL','1' UNION ALL

    SELECT '111/12345','111','12345','2' UNION ALL

    SELECT '222/12345','222','12345','2' UNION ALL

    SELECT 'District2','NULL','NULL','1' UNION ALL

    SELECT '333/3456','333','3456','2'

    The expected XML output should be in this format:

    <Region Description="Region1">

    <District Description="District1">

    <Store CompanyID="12345" StoreID="111" Description="111/12345" />

    <Store CompanyID="12345" StoreID="222" Description="222/12345" />

    </District>

    <District Description="District2">

    <Store CompanyID="3456" StoreID="333" Description="333/3456" />

    </District>

    </Region>

    I tried using the FOR XML PATH() but I failed. Any sample working code is highly appreciated.

    Thanks for your time.

  • SELECT 'Region1' AS Description,'NULL' AS StoreID,'NULL' AS CompanyID,0 AS Level UNION ALL

    SELECT 'District1','NULL','NULL','1' UNION ALL

    SELECT '111/12345','111','12345','2' UNION ALL

    SELECT '222/12345','222','12345','2' UNION ALL

    SELECT 'District2','NULL','NULL','1' UNION ALL

    SELECT '333/3456','333','3456','2'

    There's no way of determining which rows where Level=2 should be the child elements of which rows where Level= 1 in your data. I realise that you have attempted to specify this information by the order of the rows, but this row order is not significant to SQL Server. Also, you are effectively modelling 3 separate entities - Region, District and Store - in one table, which doesn't make much sense. Is this data derived from other tables that correctly model your data entities and the relations between them? If so it would be better to generate the XML from those tables instead.

  • I've changed your table to include ID and ParentID columns, which allow the parent-child relationship of the rows to be properly defined. Note that this amended table still has the ugly feature that it is modelling 3 separate entities in one table, but I'll ignore that issue for the purposes of the example query below.

    Here's the amended test data:

    CREATE TABLE #xmlData (

    ID int NOT NULL PRIMARY KEY,

    ParentID int,

    Description varchar(50),

    StoreID varchar(10),

    CompanyID varchar(10)

    )

    INSERT INTO #xmlData (ID, ParentID, Description, StoreID, CompanyID)

    SELECT 1, NULL, 'Region1', NULL, NULL UNION ALL

    SELECT 2, 1, 'District1', NULL, NULL UNION ALL

    SELECT 3, 2, '111/12345', '111', '12345' UNION ALL

    SELECT 4, 2, '222/12345', '222', '12345' UNION ALL

    SELECT 5, 1, 'District2', NULL, NULL UNION ALL

    SELECT 6, 5, '333/3456', '333', '3456'

    Given the above data, you can generate the XML using the FOR XML PATH clause as follows:

    SELECT

    X0.Description AS [@Description],

    (

    SELECT

    X1.Description AS [@Description],

    (

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Description AS [@Description]

    FROM #xmlData X2

    WHERE (X2.ParentID = X1.ID)

    FOR XML PATH('Store'), TYPE

    )

    FROM #xmlData X1

    WHERE (X1.ParentID = X0.ID)

    FOR XML PATH('District'), TYPE

    )

    FROM #xmlData X0

    WHERE (X0.ParentID IS NULL)

    FOR XML PATH('Region')

    This query generates the following XML:

    <Region Description="Region1">

    <District Description="District1">

    <Store CompanyID="12345" StoreID="111" Description="111/12345" />

    <Store CompanyID="12345" StoreID="222" Description="222/12345" />

    </District>

    <District Description="District2">

    <Store CompanyID="3456" StoreID="333" Description="333/3456" />

    </District>

    </Region>

  • Thanks for your prompt response andrewd.smith.

    Actually I have those data that you need by the time I generate the hierarchical data from the mapping table. I apologize for not making things clear. I have here the sample tables in the attachment. I was trying to query on the StoreRoleMapping table in hierarchical way.

    The order of hierarchy for levels should be Region -> District -> Stores. And so if I want to display all stores under Region1 (assuming the StoreRoleMappingID on StoreRolesTable is 3) then it should include the District 1 & 2 under StoreRoleMappingID 5,6 and retrieve the stores under those districts which are under StoreRoleMappingID 9,10, and 11.

    If I wanted to display all stores under District1 only using StoreRoleMappingID 5, then it should display stores under StoreRoleMappingID 9 and 10.

    All display should be in XML format using the xml hierarchy that I showed from the previous post. Any insights on how to deal with this kind of scenario is greatly appreciated.

    Thanks for the help.

  • James,

    Glad to be of assistance.

    Thanks for your feedback.

    --Andrew

  • andrewd.smith (4/7/2009)


    James,

    Glad to be of assistance.

    Thanks for your feedback.

    --Andrew

    Actually I have those data that you need by the time I generate the hierarchical data from the mapping table. I apologize for not making things clear. I have here the sample tables in the attachment. I was trying to query on the StoreRoleMapping table in hierarchical way.

    The order of hierarchy for levels should be Region -> District -> Stores. And so if I want to display all stores under Region1 (assuming the StoreRoleMappingID on StoreRolesTable is 3) then it should include the District 1 & 2 under StoreRoleMappingID 5,6 and retrieve the stores under those districts which are under StoreRoleMappingID 9,10, and 11.

    If I wanted to display all stores under District1 only using StoreRoleMappingID 5, then it should display stores under StoreRoleMappingID 9 and 10.

    All display should be in XML format using the xml hierarchy that I showed from the previous post. Any insights on how to deal with this kind of scenario is greatly appreciated.

    Thanks for the help.

  • If I wanted to display all stores under District1 only using StoreRoleMappingID 5, then it should display stores under StoreRoleMappingID 9 and 10.

    What XML do you want to be generated in this case:

    <Region Description="Region1">

    <District Description="District1">

    <Store CompanyID="12345" StoreID="111" Description="111/12345" />

    <Store CompanyID="12345" StoreID="222" Description="222/12345" />

    </District>

    </Region>

    or

    <District Description="District1">

    <Store CompanyID="12345" StoreID="111" Description="111/12345" />

    <Store CompanyID="12345" StoreID="222" Description="222/12345" />

    </District>

  • andrewd.smith (4/7/2009)


    If I wanted to display all stores under District1 only using StoreRoleMappingID 5, then it should display stores under StoreRoleMappingID 9 and 10.

    What XML do you want to be generated in this case:

    <Region Description="Region1">

    <District Description="District1">

    <Store CompanyID="12345" StoreID="111" Description="111/12345" />

    <Store CompanyID="12345" StoreID="222" Description="222/12345" />

    </District>

    </Region>

    or

    <District Description="District1">

    <Store CompanyID="12345" StoreID="111" Description="111/12345" />

    <Store CompanyID="12345" StoreID="222" Description="222/12345" />

    </District>

    It should display the second one. But if you would be so kind also on how to display the first one then that would be great. I really appreciate your help.

    Thank you for your time.

  • The T-SQL below queries your StoreRoleMapping table to generate the XML. You can specify the StoreRoleMappingID (?primary) column value of any row where the StoreRoleLevelID column value is 3 (Region), 4 (District) or 5 (Store).

    DECLARE @StoreRoleMappingID int

    DECLARE @StoreLevelID int

    SELECT @StoreRoleMappingID = 3

    SELECT @StoreLevelID = StoreRoleLevelID FROM dbo.StoreRoleMapping

    WHERE (StoreRoleMappingID = @StoreRoleMappingID)

    IF (@StoreLevelID = 3) BEGIN /* Region */

    SELECT

    X0.Value AS [@Description],

    (

    SELECT

    X1.Value AS [@Description],

    (

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Value AS [@Description]

    FROM dbo.StoreRoleMapping X2

    WHERE (X2.Parent = X1.StoreRoleMappingID)

    AND (X2.StoreRoleLevelID = 5)

    FOR XML PATH('Store'), TYPE

    )

    FROM dbo.StoreRoleMapping X1

    WHERE (X1.Parent = X0.StoreRoleMappingID)

    AND (X1.StoreRoleLevelID = 4)

    FOR XML PATH('District'), TYPE

    )

    FROM dbo.StoreRoleMapping X0

    WHERE (X0.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('Region')

    END

    ELSE IF (@StoreLevelID = 4) BEGIN /* District */

    SELECT

    X1.Value AS [@Description],

    (

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Value AS [@Description]

    FROM dbo.StoreRoleMapping X2

    WHERE (X2.Parent = X1.StoreRoleMappingID)

    AND (X2.StoreRoleLevelID = 5)

    FOR XML PATH('Store'), TYPE

    )

    FROM dbo.StoreRoleMapping X1

    WHERE (X1.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('District')

    END

    ELSE IF (@StoreLevelID = 5) BEGIN /* Store */

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Value AS [@Description]

    FROM dbo.StoreRoleMapping X2

    WHERE (X2.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('Store')

    END

    If you wish to generate the 3-level XML hierarchy even if the @StoreRoleMappingID variable specifies a District or Store node, then the following should do the job.

    EDIT: The query I posted originally was incorrect. Version below has been corrected.

    DECLARE @StoreRoleMappingID int

    DECLARE @StoreLevelID int

    SELECT @StoreRoleMappingID = 5

    SELECT @StoreLevelID = StoreRoleLevelID FROM dbo.StoreRoleMapping

    WHERE (StoreRoleMappingID = @StoreRoleMappingID)

    IF (@StoreLevelID = 3) BEGIN /* Region */

    SELECT

    X0.Value AS [@Description],

    (

    SELECT

    X1.Value AS [@Description],

    (

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Value AS [@Description]

    FROM dbo.StoreRoleMapping X2

    WHERE (X2.Parent = X1.StoreRoleMappingID)

    AND (X2.StoreRoleLevelID = 5)

    FOR XML PATH('Store'), TYPE

    )

    FROM dbo.StoreRoleMapping X1

    WHERE (X1.Parent = X0.StoreRoleMappingID)

    AND (X1.StoreRoleLevelID = 4)

    FOR XML PATH('District'), TYPE

    )

    FROM dbo.StoreRoleMapping X0

    WHERE (X0.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('Region')

    END

    ELSE IF (@StoreLevelID = 4) BEGIN /* District */

    SELECT

    X0.Value AS [@Description],

    (

    SELECT

    X1.Value AS [@Description],

    (

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Value AS [@Description]

    FROM dbo.StoreRoleMapping X2

    WHERE (X2.Parent = X1.StoreRoleMappingID)

    AND (X2.StoreRoleLevelID = 5)

    FOR XML PATH('Store'), TYPE

    )

    FROM dbo.StoreRoleMapping X1

    WHERE (X1.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('District'), TYPE

    )

    FROM dbo.StoreRoleMapping X0

    INNER JOIN dbo.StoreRoleMapping X1J

    ON (X1J.Parent = X0.StoreRoleMappingID AND X1J.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('Region')

    END

    ELSE IF (@StoreLevelID = 5) BEGIN /* Store */

    SELECT

    X0.Value AS [@Description],

    (

    SELECT

    X1.Value AS [@Description],

    (

    SELECT

    X2.CompanyID AS [@CompanyID],

    X2.StoreID AS [@StoreID],

    X2.Value AS [@Description]

    FROM dbo.StoreRoleMapping X2

    WHERE (X2.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('Store'), TYPE

    )

    FROM dbo.StoreRoleMapping X1

    INNER JOIN dbo.StoreRoleMapping X2J

    ON (X2J.Parent = X1.StoreRoleMappingID AND X2J.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('District'), TYPE

    )

    FROM dbo.StoreRoleMapping X0

    INNER JOIN dbo.StoreRoleMapping X1J

    ON (X1J.Parent = X0.StoreRoleMappingID)

    INNER JOIN dbo.StoreRoleMapping X2J

    ON (X2J.Parent = X1J.StoreRoleMappingID AND X2J.StoreRoleMappingID = @StoreRoleMappingID)

    FOR XML PATH('Region')

    END

  • Andrew,

    Yes it is okay now. Thanks for the great script, it is working...I really appreciate it.

    One thing I have been working on though (which was an added functionality lately) is that if a user has multiple-roles, like he/she can be an Administrator or User, it should retrieve all stores under each role mapping. Also in addition, stores that is present under a certain Branch/District should not be displayed outside if there are roles that are mapped to a store directly, if not then it will include in the displayed stores.

    Thanks,

    - James

Viewing 10 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic. Login to reply