Manipulating a Column Containing Key/Value PairsSearch on part of a column in a SQL Server cross-database viewSQL Calculation based on 'similar' rows within tableupdating the entire column with datetime values based on other values in the rowSudden PRIMARY KEY violation on IDENTITY columnHow to optimise multiple joins with OR?Easy way to change Column ID (primary key) of a table to Auto incrementEfficient way to handle multiple CASE statements in SELECTSet up View Column to be last Valuejoin two tables, include one row from the parent table for each primary keyAdd Constraint to check value exists in a non-unique composite key column

Why such a singular place for bird watching?

Isn't the detector always measuring, and thus always collapsing the state?

Why aren't faces sharp in my f/1.8 portraits even though I'm carefully using center-point autofocus?

Enlightenment finding me

Missing quartile in boxplot

Probability of going broke

How important is knowledge of trig identities for use in Calculus

How to say "respectively" in German when listing (enumerating) things

Can Familiars read and use spell scrolls?

Principled construction of the quaternions

Would an object shot from earth fall into the sun?

How do we decide/plan an SLA for an NP-hard optimization process running in production?

Is "weekend warrior" derogatory?

Airport Security - advanced check, 4th amendment breach

How do we know neutrons have no charge?

Is there an in-universe explanation of how Frodo's arrival in Valinor was recorded in the Red Book?

Giving a good fancy look to a simple table

What is the use of command?

Are there types of animals that can't make the trip to space? (physiologically)

How dangerous are my worn rims?

Can UK supreme court justices be evaluated ideologically?

How to have hashes doubled _and_ things expanded?

Knights and Knaves: What does C say?

Does the US Armed Forces refuse to recruit anyone with an IQ less than 83?



Manipulating a Column Containing Key/Value Pairs


Search on part of a column in a SQL Server cross-database viewSQL Calculation based on 'similar' rows within tableupdating the entire column with datetime values based on other values in the rowSudden PRIMARY KEY violation on IDENTITY columnHow to optimise multiple joins with OR?Easy way to change Column ID (primary key) of a table to Auto incrementEfficient way to handle multiple CASE statements in SELECTSet up View Column to be last Valuejoin two tables, include one row from the parent table for each primary keyAdd Constraint to check value exists in a non-unique composite key column






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









4















I'm accessing and creating reports from a vendor via a replicated SQL Server database. They've done some absolutely insane things that I've been trying to solve for, but this one takes the cake.



They have a table that has many standard columns. But this table also has a column called "Data". The column is a legacy "text" data type, and it contains a giant (hundreds) list of key/value pairs. Each pair is separated by a CRLF, and the key and value are separated by an equal sign. Example:



select myTable.[data] from myTable where tblKey = 123


Result:



Key 1=Value 1
Key 2=Value 2
Key 3=Value 3
...
Key 500=Value 500


I'm trying to determine the most efficient way to break that column out into a usable table of data. The end goal would be to be able to query the table in a way that returns the table key along with specified key/values as column/fields as such:



tblKey | [Key 1] | [Key 3] | [Key 243]
-------|---------|---------|-----------
123 Value 1 Value 3 Value 243
124 Value 1 Value 3 Value 243
125 Value 1 Value 3 Value 243


Is there a way to mold that column into a View? I can't imagine that a Function would be particularly efficient, but I'm sure I could parse things out that way using a string_split or something of that sort. Has anyone run into this type of atrocity before and found a good way to manipulate it into usable data?



Edit to add dbfiddle sample data.



The data is replicated from a vendor's source, so I can't create new tables. I can create views, procedures and functions. That's what I'm looking for advice for a decent way to accomplish.










share|improve this question









New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





















  • There are currently 517 keys, but that number occasionally grows. The name of the database is not emdb.

    – Andy
    7 hours ago

















4















I'm accessing and creating reports from a vendor via a replicated SQL Server database. They've done some absolutely insane things that I've been trying to solve for, but this one takes the cake.



They have a table that has many standard columns. But this table also has a column called "Data". The column is a legacy "text" data type, and it contains a giant (hundreds) list of key/value pairs. Each pair is separated by a CRLF, and the key and value are separated by an equal sign. Example:



select myTable.[data] from myTable where tblKey = 123


Result:



Key 1=Value 1
Key 2=Value 2
Key 3=Value 3
...
Key 500=Value 500


I'm trying to determine the most efficient way to break that column out into a usable table of data. The end goal would be to be able to query the table in a way that returns the table key along with specified key/values as column/fields as such:



tblKey | [Key 1] | [Key 3] | [Key 243]
-------|---------|---------|-----------
123 Value 1 Value 3 Value 243
124 Value 1 Value 3 Value 243
125 Value 1 Value 3 Value 243


Is there a way to mold that column into a View? I can't imagine that a Function would be particularly efficient, but I'm sure I could parse things out that way using a string_split or something of that sort. Has anyone run into this type of atrocity before and found a good way to manipulate it into usable data?



Edit to add dbfiddle sample data.



The data is replicated from a vendor's source, so I can't create new tables. I can create views, procedures and functions. That's what I'm looking for advice for a decent way to accomplish.










share|improve this question









New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





















  • There are currently 517 keys, but that number occasionally grows. The name of the database is not emdb.

    – Andy
    7 hours ago













4












4








4








I'm accessing and creating reports from a vendor via a replicated SQL Server database. They've done some absolutely insane things that I've been trying to solve for, but this one takes the cake.



They have a table that has many standard columns. But this table also has a column called "Data". The column is a legacy "text" data type, and it contains a giant (hundreds) list of key/value pairs. Each pair is separated by a CRLF, and the key and value are separated by an equal sign. Example:



select myTable.[data] from myTable where tblKey = 123


Result:



Key 1=Value 1
Key 2=Value 2
Key 3=Value 3
...
Key 500=Value 500


I'm trying to determine the most efficient way to break that column out into a usable table of data. The end goal would be to be able to query the table in a way that returns the table key along with specified key/values as column/fields as such:



tblKey | [Key 1] | [Key 3] | [Key 243]
-------|---------|---------|-----------
123 Value 1 Value 3 Value 243
124 Value 1 Value 3 Value 243
125 Value 1 Value 3 Value 243


Is there a way to mold that column into a View? I can't imagine that a Function would be particularly efficient, but I'm sure I could parse things out that way using a string_split or something of that sort. Has anyone run into this type of atrocity before and found a good way to manipulate it into usable data?



Edit to add dbfiddle sample data.



The data is replicated from a vendor's source, so I can't create new tables. I can create views, procedures and functions. That's what I'm looking for advice for a decent way to accomplish.










share|improve this question









New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I'm accessing and creating reports from a vendor via a replicated SQL Server database. They've done some absolutely insane things that I've been trying to solve for, but this one takes the cake.



They have a table that has many standard columns. But this table also has a column called "Data". The column is a legacy "text" data type, and it contains a giant (hundreds) list of key/value pairs. Each pair is separated by a CRLF, and the key and value are separated by an equal sign. Example:



select myTable.[data] from myTable where tblKey = 123


Result:



Key 1=Value 1
Key 2=Value 2
Key 3=Value 3
...
Key 500=Value 500


I'm trying to determine the most efficient way to break that column out into a usable table of data. The end goal would be to be able to query the table in a way that returns the table key along with specified key/values as column/fields as such:



tblKey | [Key 1] | [Key 3] | [Key 243]
-------|---------|---------|-----------
123 Value 1 Value 3 Value 243
124 Value 1 Value 3 Value 243
125 Value 1 Value 3 Value 243


Is there a way to mold that column into a View? I can't imagine that a Function would be particularly efficient, but I'm sure I could parse things out that way using a string_split or something of that sort. Has anyone run into this type of atrocity before and found a good way to manipulate it into usable data?



Edit to add dbfiddle sample data.



The data is replicated from a vendor's source, so I can't create new tables. I can create views, procedures and functions. That's what I'm looking for advice for a decent way to accomplish.







sql-server sql-server-2016 join view enterprise-edition






share|improve this question









New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.










share|improve this question









New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








share|improve this question




share|improve this question








edited 8 hours ago







Andy













New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.








asked 8 hours ago









AndyAndy

213 bronze badges




213 bronze badges




New contributor



Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.




New contributor




Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

















  • There are currently 517 keys, but that number occasionally grows. The name of the database is not emdb.

    – Andy
    7 hours ago

















  • There are currently 517 keys, but that number occasionally grows. The name of the database is not emdb.

    – Andy
    7 hours ago
















There are currently 517 keys, but that number occasionally grows. The name of the database is not emdb.

– Andy
7 hours ago





There are currently 517 keys, but that number occasionally grows. The name of the database is not emdb.

– Andy
7 hours ago










3 Answers
3






active

oldest

votes


















2
















It seems to me that the source data is not that far from JSON format.



You could convert it pretty directly then use OPENJSON to produce a relational output:



SELECT
F.FruitID,
F.[Name],
OJ.[key 1],
OJ.[key 2],
OJ.[key 3],
OJ.[key 4],
OJ.[key 5],
F.[Description]
FROM dbo.Fruit AS F
CROSS APPLY OPENJSON
(
-- Convert source data to JSON format
'' +
CHAR(34) +
REPLACE
(
REPLACE
(
CONVERT(varchar(max), F.Data),
'=', CHAR(34) + ':' + CHAR(34)
),
CHAR(13) + CHAR(10),
CHAR(34) + ',' + CHAR(34)
) +
CHAR(34) +
''
)
WITH
(
[key 1] varchar(100),
[key 2] varchar(100),
[key 3] varchar(100),
[key 4] varchar(100),
[key 5] varchar(100)
) AS OJ;


Output:





FruitID | Name | key 1 | key 2 | key 3 | key 4 | key 5 | Description
------: | :----- | :------ | :------ | :------ | :------ | :------ | :----------
1 | Banana | value 1 | value 2 | value 3 | value 4 | value 5 | Delicious
2 | Pear | value 1 | value 2 | value 3 | value 4 | value 5 | Rotton
3 | Kiwi | value 1 | value 2 | value 3 | value 4 | value 5 | Okay



db<>fiddle demo






share|improve this answer
































    2
















    The only solution I can figure out is by splitting key/values and then pivot it to obtain the desired result.



    Unfortunately there are some inconveniences:



    • STRING_SPLIT doesn't works with text columns. Hence you must cast it to varchar before you are able to manipulate it.

    • STRING_SPLIT requires a nchar(1) or nvarchar(1), ergo you should replace CHAR(3)+CHAR(10) by a single character.

    • Aggregate function on PIVOT works better with numeric values, then you should cast Value to some numeric data type.

    • PIVOT needs a well-known number of columns, in my example I have used a few of them but you should write the whole sequence unless you'd rather deal with dynamic queries.

    This is what I've got using your sample data:



    WITH KP AS
    (
    SELECT FruitID, Name, Description, value as KPair
    FROM Fruit
    CROSS APPLY STRING_SPLIT(REPLACE(CAST(Data AS varchar(max)), CHAR(13)+CHAR(10), ','), ',') /* STRING_SPLIT only allows nchar(1), varchar(1) */
    )
    , KP1 AS
    (
    SELECT
    FruitID,
    SUBSTRING(KPair, 5, CHARINDEX('=', KPair) - 5) AS [Key],
    SUBSTRING(KPair, CHARINDEX('=', KPair) + 7, LEN(KPair) - CHARINDEX('=', KPair) - 6) AS [Value]
    FROM
    KP
    )
    SELECT [FruitID], [1],[2],[3],[4],[5]
    FROM KP1
    PIVOT (MAX([Value]) FOR [Key] IN ([1],[2],[3],[4],[5])) AS PVT;


    First CTE split every Key X=Value Y. The second one cut this value to obtain each [Key] and [Value]. And the final PIVOT compose the final result in columns.





    FruitID | 1 | 2 | 3 | 4 | 5
    ------: | :- | :- | :- | :- | :-
    1 | 1 | 2 | 3 | 4 | 5
    2 | 1 | 2 | 3 | 4 | 5
    3 | 1 | 2 | 3 | 4 | 5



    db<>fiddle here



    NOTE: I'm not sure if I should maintain [Key 1] & [Value 1] or it should be converted as a column named [Key] & [Value].



    A different approach



    When I work with 3rd party databases I usually add a new database, on the same server/instance if possible, and then I use it for my own purposes, just to avoid conflicts with the DB owners.



    In this case you could add a new table and periodically throw a process to update it with the new values.



    You could use a table with all columns:



    CREATE TABLE [FruitKeys]
    (
    [FruitID] int NOT NULL PRIMARY KEY,
    [V1] int NULL,
    [V2] int NULL,
    [V3] int NULL,
    [V4] int NULL,
    [V5] int NULL
    );


    or a table with Key/Value pairs and use a pivot to obtain the final result:



    CREATE TABLE [FruitKeys]
    (
    [FruitID] int NOT NULL,
    [Key] int NOT NULL,
    [Value] int NOT NULL,
    CONSTRAINT [PK_FruitKeys] PRIMARY KEY ([FruitID], [Key])
    );





    share|improve this answer



























    • This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

      – Andy
      3 hours ago


















    0
















    McNets provided a reasonable approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.



    Because I'm working with hundreds of key/value pairs and also thousands of records in the table itself, I'm thinking about implementing a user defined function (below) to use as-needed in reports and queries where a specific key/value pair is needed (and known).



    CREATE FUNCTION udfsv_GetFruitDataValue(
    @FruitID int,
    @DataId varchar(100)
    )
    RETURNS varchar(100)
    AS BEGIN
    DECLARE @DataVal varchar(100)

    set @DataVal = (
    select
    replace(replace(split1, @DataId + '=', ''), char(13), '') as DataValue
    from Fruit
    left outer join (
    select
    FruitID,
    value as split1
    from Fruit
    cross apply string_split(cast([data] as varchar(max)), char(10))
    ) line1 on line1.FruitID = Fruit.FruitID
    where Fruit.FruitID = @FruitID
    and split1 like @DataId + '=%'
    )

    RETURN @DataVal
    END


    With this I'd be able to perform queries to include specified key/values, just not all key/values.



    SELECT
    FruitID,
    Name,
    Description,
    udfsv_GetFruitDataValue(FruitID, 'Key 1') as [Key 1],
    udfsv_GetFruitDataValue(FruitID, 'Key 4') as [Key 4]
    FROM
    Fruit
    WHERE FruitID = 123





    share|improve this answer








    New contributor



    Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      Your Answer








      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "182"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );







      Andy is a new contributor. Be nice, and check out our Code of Conduct.









      draft saved

      draft discarded
















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f249593%2fmanipulating-a-column-containing-key-value-pairs%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2
















      It seems to me that the source data is not that far from JSON format.



      You could convert it pretty directly then use OPENJSON to produce a relational output:



      SELECT
      F.FruitID,
      F.[Name],
      OJ.[key 1],
      OJ.[key 2],
      OJ.[key 3],
      OJ.[key 4],
      OJ.[key 5],
      F.[Description]
      FROM dbo.Fruit AS F
      CROSS APPLY OPENJSON
      (
      -- Convert source data to JSON format
      '' +
      CHAR(34) +
      REPLACE
      (
      REPLACE
      (
      CONVERT(varchar(max), F.Data),
      '=', CHAR(34) + ':' + CHAR(34)
      ),
      CHAR(13) + CHAR(10),
      CHAR(34) + ',' + CHAR(34)
      ) +
      CHAR(34) +
      ''
      )
      WITH
      (
      [key 1] varchar(100),
      [key 2] varchar(100),
      [key 3] varchar(100),
      [key 4] varchar(100),
      [key 5] varchar(100)
      ) AS OJ;


      Output:





      FruitID | Name | key 1 | key 2 | key 3 | key 4 | key 5 | Description
      ------: | :----- | :------ | :------ | :------ | :------ | :------ | :----------
      1 | Banana | value 1 | value 2 | value 3 | value 4 | value 5 | Delicious
      2 | Pear | value 1 | value 2 | value 3 | value 4 | value 5 | Rotton
      3 | Kiwi | value 1 | value 2 | value 3 | value 4 | value 5 | Okay



      db<>fiddle demo






      share|improve this answer





























        2
















        It seems to me that the source data is not that far from JSON format.



        You could convert it pretty directly then use OPENJSON to produce a relational output:



        SELECT
        F.FruitID,
        F.[Name],
        OJ.[key 1],
        OJ.[key 2],
        OJ.[key 3],
        OJ.[key 4],
        OJ.[key 5],
        F.[Description]
        FROM dbo.Fruit AS F
        CROSS APPLY OPENJSON
        (
        -- Convert source data to JSON format
        '' +
        CHAR(34) +
        REPLACE
        (
        REPLACE
        (
        CONVERT(varchar(max), F.Data),
        '=', CHAR(34) + ':' + CHAR(34)
        ),
        CHAR(13) + CHAR(10),
        CHAR(34) + ',' + CHAR(34)
        ) +
        CHAR(34) +
        ''
        )
        WITH
        (
        [key 1] varchar(100),
        [key 2] varchar(100),
        [key 3] varchar(100),
        [key 4] varchar(100),
        [key 5] varchar(100)
        ) AS OJ;


        Output:





        FruitID | Name | key 1 | key 2 | key 3 | key 4 | key 5 | Description
        ------: | :----- | :------ | :------ | :------ | :------ | :------ | :----------
        1 | Banana | value 1 | value 2 | value 3 | value 4 | value 5 | Delicious
        2 | Pear | value 1 | value 2 | value 3 | value 4 | value 5 | Rotton
        3 | Kiwi | value 1 | value 2 | value 3 | value 4 | value 5 | Okay



        db<>fiddle demo






        share|improve this answer



























          2














          2










          2









          It seems to me that the source data is not that far from JSON format.



          You could convert it pretty directly then use OPENJSON to produce a relational output:



          SELECT
          F.FruitID,
          F.[Name],
          OJ.[key 1],
          OJ.[key 2],
          OJ.[key 3],
          OJ.[key 4],
          OJ.[key 5],
          F.[Description]
          FROM dbo.Fruit AS F
          CROSS APPLY OPENJSON
          (
          -- Convert source data to JSON format
          '' +
          CHAR(34) +
          REPLACE
          (
          REPLACE
          (
          CONVERT(varchar(max), F.Data),
          '=', CHAR(34) + ':' + CHAR(34)
          ),
          CHAR(13) + CHAR(10),
          CHAR(34) + ',' + CHAR(34)
          ) +
          CHAR(34) +
          ''
          )
          WITH
          (
          [key 1] varchar(100),
          [key 2] varchar(100),
          [key 3] varchar(100),
          [key 4] varchar(100),
          [key 5] varchar(100)
          ) AS OJ;


          Output:





          FruitID | Name | key 1 | key 2 | key 3 | key 4 | key 5 | Description
          ------: | :----- | :------ | :------ | :------ | :------ | :------ | :----------
          1 | Banana | value 1 | value 2 | value 3 | value 4 | value 5 | Delicious
          2 | Pear | value 1 | value 2 | value 3 | value 4 | value 5 | Rotton
          3 | Kiwi | value 1 | value 2 | value 3 | value 4 | value 5 | Okay



          db<>fiddle demo






          share|improve this answer













          It seems to me that the source data is not that far from JSON format.



          You could convert it pretty directly then use OPENJSON to produce a relational output:



          SELECT
          F.FruitID,
          F.[Name],
          OJ.[key 1],
          OJ.[key 2],
          OJ.[key 3],
          OJ.[key 4],
          OJ.[key 5],
          F.[Description]
          FROM dbo.Fruit AS F
          CROSS APPLY OPENJSON
          (
          -- Convert source data to JSON format
          '' +
          CHAR(34) +
          REPLACE
          (
          REPLACE
          (
          CONVERT(varchar(max), F.Data),
          '=', CHAR(34) + ':' + CHAR(34)
          ),
          CHAR(13) + CHAR(10),
          CHAR(34) + ',' + CHAR(34)
          ) +
          CHAR(34) +
          ''
          )
          WITH
          (
          [key 1] varchar(100),
          [key 2] varchar(100),
          [key 3] varchar(100),
          [key 4] varchar(100),
          [key 5] varchar(100)
          ) AS OJ;


          Output:





          FruitID | Name | key 1 | key 2 | key 3 | key 4 | key 5 | Description
          ------: | :----- | :------ | :------ | :------ | :------ | :------ | :----------
          1 | Banana | value 1 | value 2 | value 3 | value 4 | value 5 | Delicious
          2 | Pear | value 1 | value 2 | value 3 | value 4 | value 5 | Rotton
          3 | Kiwi | value 1 | value 2 | value 3 | value 4 | value 5 | Okay



          db<>fiddle demo







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 2 hours ago









          Paul WhitePaul White

          59.8k16 gold badges310 silver badges489 bronze badges




          59.8k16 gold badges310 silver badges489 bronze badges


























              2
















              The only solution I can figure out is by splitting key/values and then pivot it to obtain the desired result.



              Unfortunately there are some inconveniences:



              • STRING_SPLIT doesn't works with text columns. Hence you must cast it to varchar before you are able to manipulate it.

              • STRING_SPLIT requires a nchar(1) or nvarchar(1), ergo you should replace CHAR(3)+CHAR(10) by a single character.

              • Aggregate function on PIVOT works better with numeric values, then you should cast Value to some numeric data type.

              • PIVOT needs a well-known number of columns, in my example I have used a few of them but you should write the whole sequence unless you'd rather deal with dynamic queries.

              This is what I've got using your sample data:



              WITH KP AS
              (
              SELECT FruitID, Name, Description, value as KPair
              FROM Fruit
              CROSS APPLY STRING_SPLIT(REPLACE(CAST(Data AS varchar(max)), CHAR(13)+CHAR(10), ','), ',') /* STRING_SPLIT only allows nchar(1), varchar(1) */
              )
              , KP1 AS
              (
              SELECT
              FruitID,
              SUBSTRING(KPair, 5, CHARINDEX('=', KPair) - 5) AS [Key],
              SUBSTRING(KPair, CHARINDEX('=', KPair) + 7, LEN(KPair) - CHARINDEX('=', KPair) - 6) AS [Value]
              FROM
              KP
              )
              SELECT [FruitID], [1],[2],[3],[4],[5]
              FROM KP1
              PIVOT (MAX([Value]) FOR [Key] IN ([1],[2],[3],[4],[5])) AS PVT;


              First CTE split every Key X=Value Y. The second one cut this value to obtain each [Key] and [Value]. And the final PIVOT compose the final result in columns.





              FruitID | 1 | 2 | 3 | 4 | 5
              ------: | :- | :- | :- | :- | :-
              1 | 1 | 2 | 3 | 4 | 5
              2 | 1 | 2 | 3 | 4 | 5
              3 | 1 | 2 | 3 | 4 | 5



              db<>fiddle here



              NOTE: I'm not sure if I should maintain [Key 1] & [Value 1] or it should be converted as a column named [Key] & [Value].



              A different approach



              When I work with 3rd party databases I usually add a new database, on the same server/instance if possible, and then I use it for my own purposes, just to avoid conflicts with the DB owners.



              In this case you could add a new table and periodically throw a process to update it with the new values.



              You could use a table with all columns:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL PRIMARY KEY,
              [V1] int NULL,
              [V2] int NULL,
              [V3] int NULL,
              [V4] int NULL,
              [V5] int NULL
              );


              or a table with Key/Value pairs and use a pivot to obtain the final result:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL,
              [Key] int NOT NULL,
              [Value] int NOT NULL,
              CONSTRAINT [PK_FruitKeys] PRIMARY KEY ([FruitID], [Key])
              );





              share|improve this answer



























              • This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

                – Andy
                3 hours ago















              2
















              The only solution I can figure out is by splitting key/values and then pivot it to obtain the desired result.



              Unfortunately there are some inconveniences:



              • STRING_SPLIT doesn't works with text columns. Hence you must cast it to varchar before you are able to manipulate it.

              • STRING_SPLIT requires a nchar(1) or nvarchar(1), ergo you should replace CHAR(3)+CHAR(10) by a single character.

              • Aggregate function on PIVOT works better with numeric values, then you should cast Value to some numeric data type.

              • PIVOT needs a well-known number of columns, in my example I have used a few of them but you should write the whole sequence unless you'd rather deal with dynamic queries.

              This is what I've got using your sample data:



              WITH KP AS
              (
              SELECT FruitID, Name, Description, value as KPair
              FROM Fruit
              CROSS APPLY STRING_SPLIT(REPLACE(CAST(Data AS varchar(max)), CHAR(13)+CHAR(10), ','), ',') /* STRING_SPLIT only allows nchar(1), varchar(1) */
              )
              , KP1 AS
              (
              SELECT
              FruitID,
              SUBSTRING(KPair, 5, CHARINDEX('=', KPair) - 5) AS [Key],
              SUBSTRING(KPair, CHARINDEX('=', KPair) + 7, LEN(KPair) - CHARINDEX('=', KPair) - 6) AS [Value]
              FROM
              KP
              )
              SELECT [FruitID], [1],[2],[3],[4],[5]
              FROM KP1
              PIVOT (MAX([Value]) FOR [Key] IN ([1],[2],[3],[4],[5])) AS PVT;


              First CTE split every Key X=Value Y. The second one cut this value to obtain each [Key] and [Value]. And the final PIVOT compose the final result in columns.





              FruitID | 1 | 2 | 3 | 4 | 5
              ------: | :- | :- | :- | :- | :-
              1 | 1 | 2 | 3 | 4 | 5
              2 | 1 | 2 | 3 | 4 | 5
              3 | 1 | 2 | 3 | 4 | 5



              db<>fiddle here



              NOTE: I'm not sure if I should maintain [Key 1] & [Value 1] or it should be converted as a column named [Key] & [Value].



              A different approach



              When I work with 3rd party databases I usually add a new database, on the same server/instance if possible, and then I use it for my own purposes, just to avoid conflicts with the DB owners.



              In this case you could add a new table and periodically throw a process to update it with the new values.



              You could use a table with all columns:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL PRIMARY KEY,
              [V1] int NULL,
              [V2] int NULL,
              [V3] int NULL,
              [V4] int NULL,
              [V5] int NULL
              );


              or a table with Key/Value pairs and use a pivot to obtain the final result:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL,
              [Key] int NOT NULL,
              [Value] int NOT NULL,
              CONSTRAINT [PK_FruitKeys] PRIMARY KEY ([FruitID], [Key])
              );





              share|improve this answer



























              • This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

                – Andy
                3 hours ago













              2














              2










              2









              The only solution I can figure out is by splitting key/values and then pivot it to obtain the desired result.



              Unfortunately there are some inconveniences:



              • STRING_SPLIT doesn't works with text columns. Hence you must cast it to varchar before you are able to manipulate it.

              • STRING_SPLIT requires a nchar(1) or nvarchar(1), ergo you should replace CHAR(3)+CHAR(10) by a single character.

              • Aggregate function on PIVOT works better with numeric values, then you should cast Value to some numeric data type.

              • PIVOT needs a well-known number of columns, in my example I have used a few of them but you should write the whole sequence unless you'd rather deal with dynamic queries.

              This is what I've got using your sample data:



              WITH KP AS
              (
              SELECT FruitID, Name, Description, value as KPair
              FROM Fruit
              CROSS APPLY STRING_SPLIT(REPLACE(CAST(Data AS varchar(max)), CHAR(13)+CHAR(10), ','), ',') /* STRING_SPLIT only allows nchar(1), varchar(1) */
              )
              , KP1 AS
              (
              SELECT
              FruitID,
              SUBSTRING(KPair, 5, CHARINDEX('=', KPair) - 5) AS [Key],
              SUBSTRING(KPair, CHARINDEX('=', KPair) + 7, LEN(KPair) - CHARINDEX('=', KPair) - 6) AS [Value]
              FROM
              KP
              )
              SELECT [FruitID], [1],[2],[3],[4],[5]
              FROM KP1
              PIVOT (MAX([Value]) FOR [Key] IN ([1],[2],[3],[4],[5])) AS PVT;


              First CTE split every Key X=Value Y. The second one cut this value to obtain each [Key] and [Value]. And the final PIVOT compose the final result in columns.





              FruitID | 1 | 2 | 3 | 4 | 5
              ------: | :- | :- | :- | :- | :-
              1 | 1 | 2 | 3 | 4 | 5
              2 | 1 | 2 | 3 | 4 | 5
              3 | 1 | 2 | 3 | 4 | 5



              db<>fiddle here



              NOTE: I'm not sure if I should maintain [Key 1] & [Value 1] or it should be converted as a column named [Key] & [Value].



              A different approach



              When I work with 3rd party databases I usually add a new database, on the same server/instance if possible, and then I use it for my own purposes, just to avoid conflicts with the DB owners.



              In this case you could add a new table and periodically throw a process to update it with the new values.



              You could use a table with all columns:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL PRIMARY KEY,
              [V1] int NULL,
              [V2] int NULL,
              [V3] int NULL,
              [V4] int NULL,
              [V5] int NULL
              );


              or a table with Key/Value pairs and use a pivot to obtain the final result:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL,
              [Key] int NOT NULL,
              [Value] int NOT NULL,
              CONSTRAINT [PK_FruitKeys] PRIMARY KEY ([FruitID], [Key])
              );





              share|improve this answer















              The only solution I can figure out is by splitting key/values and then pivot it to obtain the desired result.



              Unfortunately there are some inconveniences:



              • STRING_SPLIT doesn't works with text columns. Hence you must cast it to varchar before you are able to manipulate it.

              • STRING_SPLIT requires a nchar(1) or nvarchar(1), ergo you should replace CHAR(3)+CHAR(10) by a single character.

              • Aggregate function on PIVOT works better with numeric values, then you should cast Value to some numeric data type.

              • PIVOT needs a well-known number of columns, in my example I have used a few of them but you should write the whole sequence unless you'd rather deal with dynamic queries.

              This is what I've got using your sample data:



              WITH KP AS
              (
              SELECT FruitID, Name, Description, value as KPair
              FROM Fruit
              CROSS APPLY STRING_SPLIT(REPLACE(CAST(Data AS varchar(max)), CHAR(13)+CHAR(10), ','), ',') /* STRING_SPLIT only allows nchar(1), varchar(1) */
              )
              , KP1 AS
              (
              SELECT
              FruitID,
              SUBSTRING(KPair, 5, CHARINDEX('=', KPair) - 5) AS [Key],
              SUBSTRING(KPair, CHARINDEX('=', KPair) + 7, LEN(KPair) - CHARINDEX('=', KPair) - 6) AS [Value]
              FROM
              KP
              )
              SELECT [FruitID], [1],[2],[3],[4],[5]
              FROM KP1
              PIVOT (MAX([Value]) FOR [Key] IN ([1],[2],[3],[4],[5])) AS PVT;


              First CTE split every Key X=Value Y. The second one cut this value to obtain each [Key] and [Value]. And the final PIVOT compose the final result in columns.





              FruitID | 1 | 2 | 3 | 4 | 5
              ------: | :- | :- | :- | :- | :-
              1 | 1 | 2 | 3 | 4 | 5
              2 | 1 | 2 | 3 | 4 | 5
              3 | 1 | 2 | 3 | 4 | 5



              db<>fiddle here



              NOTE: I'm not sure if I should maintain [Key 1] & [Value 1] or it should be converted as a column named [Key] & [Value].



              A different approach



              When I work with 3rd party databases I usually add a new database, on the same server/instance if possible, and then I use it for my own purposes, just to avoid conflicts with the DB owners.



              In this case you could add a new table and periodically throw a process to update it with the new values.



              You could use a table with all columns:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL PRIMARY KEY,
              [V1] int NULL,
              [V2] int NULL,
              [V3] int NULL,
              [V4] int NULL,
              [V5] int NULL
              );


              or a table with Key/Value pairs and use a pivot to obtain the final result:



              CREATE TABLE [FruitKeys]
              (
              [FruitID] int NOT NULL,
              [Key] int NOT NULL,
              [Value] int NOT NULL,
              CONSTRAINT [PK_FruitKeys] PRIMARY KEY ([FruitID], [Key])
              );






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited 2 hours ago

























              answered 6 hours ago









              McNetsMcNets

              17.7k5 gold badges27 silver badges62 bronze badges




              17.7k5 gold badges27 silver badges62 bronze badges















              • This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

                – Andy
                3 hours ago

















              • This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

                – Andy
                3 hours ago
















              This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

              – Andy
              3 hours ago





              This is an effective approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.

              – Andy
              3 hours ago











              0
















              McNets provided a reasonable approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.



              Because I'm working with hundreds of key/value pairs and also thousands of records in the table itself, I'm thinking about implementing a user defined function (below) to use as-needed in reports and queries where a specific key/value pair is needed (and known).



              CREATE FUNCTION udfsv_GetFruitDataValue(
              @FruitID int,
              @DataId varchar(100)
              )
              RETURNS varchar(100)
              AS BEGIN
              DECLARE @DataVal varchar(100)

              set @DataVal = (
              select
              replace(replace(split1, @DataId + '=', ''), char(13), '') as DataValue
              from Fruit
              left outer join (
              select
              FruitID,
              value as split1
              from Fruit
              cross apply string_split(cast([data] as varchar(max)), char(10))
              ) line1 on line1.FruitID = Fruit.FruitID
              where Fruit.FruitID = @FruitID
              and split1 like @DataId + '=%'
              )

              RETURN @DataVal
              END


              With this I'd be able to perform queries to include specified key/values, just not all key/values.



              SELECT
              FruitID,
              Name,
              Description,
              udfsv_GetFruitDataValue(FruitID, 'Key 1') as [Key 1],
              udfsv_GetFruitDataValue(FruitID, 'Key 4') as [Key 4]
              FROM
              Fruit
              WHERE FruitID = 123





              share|improve this answer








              New contributor



              Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
              Check out our Code of Conduct.

























                0
















                McNets provided a reasonable approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.



                Because I'm working with hundreds of key/value pairs and also thousands of records in the table itself, I'm thinking about implementing a user defined function (below) to use as-needed in reports and queries where a specific key/value pair is needed (and known).



                CREATE FUNCTION udfsv_GetFruitDataValue(
                @FruitID int,
                @DataId varchar(100)
                )
                RETURNS varchar(100)
                AS BEGIN
                DECLARE @DataVal varchar(100)

                set @DataVal = (
                select
                replace(replace(split1, @DataId + '=', ''), char(13), '') as DataValue
                from Fruit
                left outer join (
                select
                FruitID,
                value as split1
                from Fruit
                cross apply string_split(cast([data] as varchar(max)), char(10))
                ) line1 on line1.FruitID = Fruit.FruitID
                where Fruit.FruitID = @FruitID
                and split1 like @DataId + '=%'
                )

                RETURN @DataVal
                END


                With this I'd be able to perform queries to include specified key/values, just not all key/values.



                SELECT
                FruitID,
                Name,
                Description,
                udfsv_GetFruitDataValue(FruitID, 'Key 1') as [Key 1],
                udfsv_GetFruitDataValue(FruitID, 'Key 4') as [Key 4]
                FROM
                Fruit
                WHERE FruitID = 123





                share|improve this answer








                New contributor



                Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                Check out our Code of Conduct.























                  0














                  0










                  0









                  McNets provided a reasonable approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.



                  Because I'm working with hundreds of key/value pairs and also thousands of records in the table itself, I'm thinking about implementing a user defined function (below) to use as-needed in reports and queries where a specific key/value pair is needed (and known).



                  CREATE FUNCTION udfsv_GetFruitDataValue(
                  @FruitID int,
                  @DataId varchar(100)
                  )
                  RETURNS varchar(100)
                  AS BEGIN
                  DECLARE @DataVal varchar(100)

                  set @DataVal = (
                  select
                  replace(replace(split1, @DataId + '=', ''), char(13), '') as DataValue
                  from Fruit
                  left outer join (
                  select
                  FruitID,
                  value as split1
                  from Fruit
                  cross apply string_split(cast([data] as varchar(max)), char(10))
                  ) line1 on line1.FruitID = Fruit.FruitID
                  where Fruit.FruitID = @FruitID
                  and split1 like @DataId + '=%'
                  )

                  RETURN @DataVal
                  END


                  With this I'd be able to perform queries to include specified key/values, just not all key/values.



                  SELECT
                  FruitID,
                  Name,
                  Description,
                  udfsv_GetFruitDataValue(FruitID, 'Key 1') as [Key 1],
                  udfsv_GetFruitDataValue(FruitID, 'Key 4') as [Key 4]
                  FROM
                  Fruit
                  WHERE FruitID = 123





                  share|improve this answer








                  New contributor



                  Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.









                  McNets provided a reasonable approach, but the splitting for every pair, while obviously necessary, is a pretty time consuming process. With 500+ key/value pairs for every record in the table, I'm not sure it's going to work for my purposes. It's probably a decent approach if there are fewer pairs and a small number of rows in the affected table.



                  Because I'm working with hundreds of key/value pairs and also thousands of records in the table itself, I'm thinking about implementing a user defined function (below) to use as-needed in reports and queries where a specific key/value pair is needed (and known).



                  CREATE FUNCTION udfsv_GetFruitDataValue(
                  @FruitID int,
                  @DataId varchar(100)
                  )
                  RETURNS varchar(100)
                  AS BEGIN
                  DECLARE @DataVal varchar(100)

                  set @DataVal = (
                  select
                  replace(replace(split1, @DataId + '=', ''), char(13), '') as DataValue
                  from Fruit
                  left outer join (
                  select
                  FruitID,
                  value as split1
                  from Fruit
                  cross apply string_split(cast([data] as varchar(max)), char(10))
                  ) line1 on line1.FruitID = Fruit.FruitID
                  where Fruit.FruitID = @FruitID
                  and split1 like @DataId + '=%'
                  )

                  RETURN @DataVal
                  END


                  With this I'd be able to perform queries to include specified key/values, just not all key/values.



                  SELECT
                  FruitID,
                  Name,
                  Description,
                  udfsv_GetFruitDataValue(FruitID, 'Key 1') as [Key 1],
                  udfsv_GetFruitDataValue(FruitID, 'Key 4') as [Key 4]
                  FROM
                  Fruit
                  WHERE FruitID = 123






                  share|improve this answer








                  New contributor



                  Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.








                  share|improve this answer



                  share|improve this answer






                  New contributor



                  Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.








                  answered 3 hours ago









                  AndyAndy

                  213 bronze badges




                  213 bronze badges




                  New contributor



                  Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.




                  New contributor




                  Andy is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.


























                      Andy is a new contributor. Be nice, and check out our Code of Conduct.









                      draft saved

                      draft discarded

















                      Andy is a new contributor. Be nice, and check out our Code of Conduct.












                      Andy is a new contributor. Be nice, and check out our Code of Conduct.











                      Andy is a new contributor. Be nice, and check out our Code of Conduct.














                      Thanks for contributing an answer to Database Administrators Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f249593%2fmanipulating-a-column-containing-key-value-pairs%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

                      Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

                      François Viète Contents Biography Work and thought Bibliography See also Notes Further reading External links Navigation menup. 21Google Bookspp. 75–77Google BooksDe thou (from University of Saint Andrews)ArchivedGoogle BooksGoogle BooksGoogle BooksGoogle booksGoogle Bookscc-parthenay.frL'histoire universelle (fr)Universal History (en)ArchivedAdsabs.harvard.eduPagesperso-orange.frArchive.orgChikara Sasaki. Descartes' mathematical thought p.259Google BooksGoogle BooksGoogle Bookspp. 152 and onwardGoogle BooksGoogle BooksScribd.comGoogle Books1257-7979Google BooksGoogle BooksGoogle BooksGoogle BooksGoogle BooksGoogle BooksGallica.bnf.frGoogle BooksGoogle Books"François Viète"Francois Viète: Father of Modern Algebraic NotationThe Lawyer and the GamblerAbout TarporleySite de Jean-Paul GuichardL'algèbre nouvelle"About the Harmonicon"cb120511976(data)1188044800000 0001 0913 5903n82164680ola2013766880073431702w6vt1sb70287374827140948071409480