sql-server-2008t-sqlfor-xml-path

Using distinct within for xml path without including in select


The top query looks in a table that will only ever have one record per statement, so if a customer has 7 statements the number of rows should be 7 and the query would list them like so 1,2,3,4,5,6,7

The bottom query looks in a table which will have the 7 statements like above, but more often than not, they will be split, so if there is 2 lines for each statement there would be 14, i.e. 1,1,2,2,3,3,4,4,5,5,6,6,7,7

Now, what I'm trying to achieve is the following, the top query is fine as it is, however the bottom query needs to be made distinct. Look at result number 2 on the bottom image, I want this to come back as 1,2,3,4,5,6,7,8,9,10.

If there was a particular instance where the statements went up to 8 and 4 respectively, i would want 1,2,3,4,5,6,7,8. Basically It is in most cases duplicating the statement numbers for the bottom query and I would like it to just do a distinct occross the whole result, however I have tried putting a distinct in and it complains that order by items must be contained in the select statement if contained within a distinct, this ruins my query.

The ultimate aim of these two queries is to compare the top result set against the bottom and bring back only the ones that dont match (as that will mean I am missing a statement in the top queries table)

--Shows the each consolidated statement number that exisits for that particular customer reference number within the dbo.rss table.

Select Main.cust_ref,
       Left(CAST(Main.consolidatedstatements as varchar(max)),Len(CAST(Main.consolidatedstatements as varchar(max)))-1) As "consolidatedstatements"
From(Select distinct ST2.cust_ref, 
           (Select CAST(ST1.consolidated_stmt_num as varchar(max)) + ',' AS [text()]
            From dbo.rss ST1
            Where ST1.cust_ref = ST2.cust_ref
            ORDER BY ST1.cust_ref
            For XML PATH ('')) [consolidatedstatements]
     From dbo.rss ST2) [Main]


--Shows the each consolidated statement number that exisits for that particular customer reference number within the dbo.SC table.
Select Main.cust_ref,
       Left(CAST(Main.consolidatedstatements as varchar(max)),Len(CAST(Main.consolidatedstatements as varchar(max)))-1) As "consolidatedstatements"
From(Select distinct ST2.cust_ref, 
           (Select  CAST(ST1.consolidated_stmt_num as varchar(max)) + ',' AS [text()]
            From dbo.SC ST1
            Where ST1.cust_ref = ST2.cust_ref
            ORDER BY ST1.cust_ref
            For XML PATH ('')) [consolidatedstatements]
     From dbo.SC ST2) [Main]

enter image description here


Solution

  • CREATE TABLE #rss(cust_ref VARCHAR(32), consolidated_stmt_num INT);
    
    CREATE TABLE #SC(cust_ref VARCHAR(32), consolidated_stmt_num INT);
    
    INSERT #SC VALUES
    ('A',1),('A',2),('A',3),('A',4),('A',5),('A',6),('A',7),('A',8),('A',9),
    ('B',1),('B',2),('B',3),('B',4),('B',5),('B',6),('B',7),('B',8),('B',9),
    ('C',1),('C',2),('C',3),('C',4),('C',5),('C',6),('C',7),('C',8),('C',9);
    
    -- missing A,7 and C,2/C,4:
    INSERT #rss VALUES
    ('A',1),('A',2),('A',3),('A',4),('A',5),('A',6),        ('A',8),('A',9),
    ('B',1),('B',2),('B',3),('B',4),('B',5),('B',6),('B',7),('B',8),('B',9),
    ('C',1),        ('C',3),        ('C',5),('C',6),('C',7),('C',8),('C',9);
    
    GO
    

    -- This alone will tell you the cust_refs with missing statements (and which ones they are):

    SELECT cust_ref, consolidated_stmt_num FROM #SC
    EXCEPT
    SELECT cust_ref, consolidated_stmt_num FROM #rss;
    

    -- This will allow you to get the full concatenated list from each table, on one line:

    ;WITH x AS
    (
      SELECT DISTINCT cust_ref FROM 
      (
        SELECT cust_ref, consolidated_stmt_num FROM #SC
        EXCEPT
        SELECT cust_ref, consolidated_stmt_num FROM #rss
      ) AS y
    )
    SELECT x.cust_ref, 
        rss = STUFF((SELECT ',' + CONVERT(VARCHAR(12), r.consolidated_stmt_num) 
          FROM #rss AS r WHERE r.cust_ref = x.cust_ref
          ORDER BY r.cust_ref
        FOR XML PATH(''), TYPE).value('./text()[1]','varchar(max)'),1,1,''),
        sc =  STUFF((SELECT ',' + CONVERT(VARCHAR(12), s.consolidated_stmt_num)
          FROM #SC  AS s WHERE s.cust_ref = x.cust_ref
          ORDER BY s.cust_ref
        FOR XML PATH(''), TYPE).value('./text()[1]','varchar(max)'),1,1,'')
    FROM x;
    

    -- if you need them on separate lines:

    ;WITH x AS
    (
      SELECT DISTINCT cust_ref FROM 
      (
        SELECT cust_ref, consolidated_stmt_num FROM #SC
        EXCEPT
        SELECT cust_ref, consolidated_stmt_num FROM #rss
      ) AS y
    )
    SELECT x.cust_ref, source = 'rss',
        list = STUFF((SELECT ',' + CONVERT(VARCHAR(12), r.consolidated_stmt_num) 
          FROM #rss AS r WHERE r.cust_ref = x.cust_ref
          ORDER BY r.cust_ref
        FOR XML PATH(''), TYPE).value('./text()[1]','varchar(max)'),1,1,'')
        FROM x
    UNION ALL SELECT x.cust_ref, 'sc',
        list = STUFF((SELECT ',' + CONVERT(VARCHAR(12), s.consolidated_stmt_num)
          FROM #SC  AS s WHERE s.cust_ref = x.cust_ref
          ORDER BY s.cust_ref
        FOR XML PATH(''), TYPE).value('./text()[1]','varchar(max)'),1,1,'')
        FROM x
    ORDER BY cust_ref, source;
    

    -- clean up:

    DROP TABLE #rss, #SC;