Loop through results returned by Pivot Table

I thought you had two different kinds of delimiter

Actually they are two delimiters, but I treat the ":" with some logic after the ITEM is returned from the Split function. I guess that the best thing for entries without the ":" - that in all other cases separates the feature from it's value- is to assign it as "feature" and leave the value to "blank". Otherwise it would be NULL and then the feature will probably get lost for that ItemID.

What are you going to do with the output?

The idea is to map all these items to PDF templates of construction drawings and then to place the construction relevant data in the right place with C#. But first we need to analyze and cluster, data patterns with the different templates, and this will be done in html. So the next step will be set it up for web display.

Sounds fine :slight_smile:

Hopefully you can use my seconds example (... into Table Cells (for HTML)) as the basis for something in HTML, or as the basis for inclusion in PDF file

1 Like

Separating feature and value at the first ":" leads to double entries for the feature column in some cases as I detect now.
the text string is

Prueba de presión y de estabilidad: Prueba de presión y de estabilidad: Prueba hidrostática de presión exterior - 1,5 x PN - 3 min.<br />
Prueba de presión y de estabilidad: Prueba hidrostática de presión interior - 500 bar - 3 min.<br />

Does this forces me to introduce a third key column as you were proposing in the beginning, or is there another way?
If I could apply a reasonable logic that cuts between feature and value after the second ":" once it detects that the string up to the first ":" is not unique... and that there is another ":" delimiter. I will think on this but if you have a good idea, feel free... probably getting the second ":" coming from the right; but this is kind of risky as the value part often contains more text and there might be an extra ":" somewhere
Martin

You could "mangle" the second "Prueba de presión y de estabilidad", when you detect that there is a duplicate, but then how would you match up all the "Prueba de presión y de estabilidad" attribute tags?

If you introduce a third key column then you haven't got to worry about duplicate TAGs at all (apart from whether they should, logically, be there or not). If you try to code around it my expectation is that you will be tinkering with that process in the future - when you get a Third duplicate ... when you get a duplicate tag that you have not allowed for (e.g. because "It can't possibly happen" :slight_smile: ). Each time it happens the import will fail, and will not work at all until you have fixed it - it will probably be a nuisance to have that critical-repair as it is bound to happen at a bad time :frowning: Hence my thought to have the third key - you then don't have to do anything, all the data will import OK, and you can check for duplicates as a separate issue, and "post process" them (e.g. to force them to be unique, if you need them to be, as a less time-critical task)

Great! I added the ItemNumber Jeff's Split function is returning and use this as the third key. I then added the same feature to my (stolen) Split function to do a benchmark test. To add 1000 items in the feature table, using Jeff's function it took 8 seconds, while "mine" was instantaneous...

I've been struggling for some hours now and I can't make the pivot work the way I want it - the third key column now messes up everything.

Declare @features varchar(max) = ''
Select @features += QUOTENAME(FI_Key) +','
from #FeatureItems 
GROUP BY FI_Key
ORDER BY FI_Key

set @features = left (@features, len(@features)-1)
print @features

declare @sql nvarchar(max)
set @sql = 
'SELECT * from #FeatureItems

PIVOT (min(FI_Value) for FI_Key in (' + @features + ')) as pvt'
exec sp_executesql @sql

This displays the table with all features as columns, but logically not grouped by only FI_SD_ID but even by FI_Key2.
How can I pack all in one row for one item, assigning to those non unique-features the sum of their value strings?

momentary eclipse of sight and logic... this does it

set @sql = 
'SELECT * from (SELECT FI_SD_ID, FI_Key, STUFF(
     (SELECT ''' + @para1 +''' + FI_Value
      FROM  #FeatureItems as x
      WHERE x.FI_Key = #FeatureItems.FI_Key and x.FI_SD_ID = #FeatureItems.FI_SD_ID
      FOR XML PATH (''''))
      , 1, 1, '''')  AS FI_Value
from #FeatureItems
GROUP By FI_SD_ID, FI_Key)a

PIVOT (min(FI_Value) for FI_Key in (' + @features + ')) as pvt'

Yours is loop-based, have I remembered that right?

If so there is something not right ... we'd need to see the code to figure out what.

why can't I post the reply... forbidden???

now...?
This is the one that I use: (I had to do some replace action to kill delimiters that where in the beginning and in the end):

ALTER FUNCTION [dbo].[Split] (
      @InputString                  VARCHAR(8000),
      @Delimiter                    VARCHAR(50)
)

RETURNS @Items TABLE (
  Item                          VARCHAR(8000),
  ItemNumber				    INT
)

AS
BEGIN
  IF @Delimiter = ' '
  BEGIN
        SET @Delimiter = ','
        SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
  END

  IF (@Delimiter IS NULL OR @Delimiter = '')
        SET @Delimiter = ','

  DECLARE @Item                 VARCHAR(8000)
  DECLARE @ItemList       VARCHAR(8000)
  DECLARE @DelimIndex     INT
  DECLARE @ItemLine		  INT

  SET @ItemList = REPLACE(@InputString+'XXX123XX', @Delimiter+'XXX123XX','')
  SET @ItemList = REPLACE('XXX123XX'+@ItemList, 'XXX123XX'+@Delimiter,'')
  SET @ItemList = REPLACE(@ItemList, 'XXX123XX','')
  SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
  SET @ItemLine = 0
  WHILE (@DelimIndex != 0)
  BEGIN
        SET @ItemLine = @ItemLine + 1
		SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
        INSERT INTO @Items VALUES (@Item,@ItemLine)

        -- Set @ItemList = @ItemList minus one less item
        SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+len(@Delimiter), LEN(@ItemList)-@DelimIndex)
        SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
    END -- End WHILE

  IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
  BEGIN
        SET @ItemLine = @ItemLine + 1
		SET @Item = @ItemList
        INSERT INTO @Items VALUES (@Item,@ItemLine)

  END

  -- No delimiters were encountered in @InputString, so just return @InputString
  ELSE INSERT INTO @Items VALUES (@InputString,NULL)

  RETURN

END -- End Function

and Jeff's one:

ALTER FUNCTION [dbo].[DelimitedSplit8K]
--===== Define I/O parameters
    (@pString VARCHAR(8000), @pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE!  IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
 -- enough to cover VARCHAR(8000)
  WITH E1(N) AS (
             SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
             SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
             SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
            ),                          --10E+1 or 10 rows
   E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
   E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
                 -- for both a performance gain and prevention of accidental "overruns"
             SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
            ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
             SELECT 1 UNION ALL
             SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
            ),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
             SELECT s.N1,
                    ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
               FROM cteStart s
            )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
    Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l
;

The returned values are processed as nvarchar(20)