-1

I have a table where I store column name and its value ticker & client wise.

This is my table with data. screen shot attached. enter image description here

Here i tried this sql which is throwing error for duplicate values in field name. i got this code from this post https://stackoverflow.com/a/15745076/9359783

But their code is not working for my scenario. please guide me what i need to alter in code.

DECLARE @cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(FieldName) 
                    from DynamicForm WHERE Ticker='X' AND ClientCode='Z'
                    group by FieldName, id,Ticker,ClientCode
                    order by id
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query = N'SELECT ' + @cols + N' from 
             (
                select value, FieldName
                from DynamicForm WHERE Ticker=''X'' AND ClientCode=''Z''
            ) x
            pivot 
            (
                max(value)
                for FieldName in (' + @cols + N')
            ) p '

exec sp_executesql @query;

OUTPUT would be look like

+-------------+----------------------+-----------------+
| Last Update |        Broker        |     Analyst     |
+-------------+----------------------+-----------------+
| 7/6/2021    |    JMP Securities    | David M Scharf  |
| 4/28/2021   |  Argus Research Corp | David E Coleman |
+-------------+----------------------+-----------------+  

See here two records is coming and JMP Securities is getting first records because its orderid is 1. so data should be displayed as per Ticker & client code wise and orderId wise data should be order.

Here is script which help you to get data.

CREATE TABLE [dbo].[DynamicForm](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [FieldName] [varchar](100) NULL,
    [Value] [varchar](100) NULL,
    [Ticker] [varchar](10) NULL,
    [ClientCode] [varchar](10) NULL,
    [Order] [int] NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[DynamicForm] ON 
GO
INSERT [dbo].[DynamicForm] ([ID], [FieldName], [Value], [Ticker], [ClientCode], [Order]) VALUES (1, N'Last Update
', N'4/28/2021
', N'X', N'Z', 1)
GO
INSERT [dbo].[DynamicForm] ([ID], [FieldName], [Value], [Ticker], [ClientCode], [Order]) VALUES (2, N'Broker
', N'Argus Research Corp
', N'X', N'Z', 1)
GO
INSERT [dbo].[DynamicForm] ([ID], [FieldName], [Value], [Ticker], [ClientCode], [Order]) VALUES (3, N'Analyst 
', N'David E Coleman
', N'X', N'Z', 1)
GO
INSERT [dbo].[DynamicForm] ([ID], [FieldName], [Value], [Ticker], [ClientCode], [Order]) VALUES (4, N'Last Update
', N'7/6/2021
', N'X', N'Z', 2)
GO
INSERT [dbo].[DynamicForm] ([ID], [FieldName], [Value], [Ticker], [ClientCode], [Order]) VALUES (5, N'Broker
', N'JMP Securities
', N'X', N'Z', 2)
GO
INSERT [dbo].[DynamicForm] ([ID], [FieldName], [Value], [Ticker], [ClientCode], [Order]) VALUES (6, N'Analyst 
', N'David M Scharf
', N'X', N'Z', 2)
GO
SET IDENTITY_INSERT [dbo].[DynamicForm] OFF
GO
  • if i do as you said then multiple value is not coming. my requirement is to show all values for specific ticker & client code. how to achieve it –  Aug 10 '21 at 12:33
  • it is unfair to underrate answers. My answer was based on your previous question. later you edit the question when I asked and showed you. – Gudwlk Aug 15 '21 at 10:38

2 Answers2

3

Here i tried this sql which is throwing error for duplicate values in field name.

This is because your GROUP BY is on FieldName, id,Ticker,ClientCode. You are therefore telling the RDBMS you want a row for every distinct group of those columns, and very clearly that would result in multiple rows for the same value of FieldName.

Very likely the GROUP BY and ORDER BY shouldn't be there at all:

SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(FieldName) 
                      FROM dbo.DynamicForm
                      WHERE Ticker='X'
                        AND ClientCode='Z'
                      FOR XML PATH(''), TYPE).value('(./text())[1]', 'nvarchar(MAX)') ,1,1,'');

Now we have sample data, I can provide a full solution. Personally, as well, I would use a conditional aggregate, rather than the restrictive PIVOT operator, and build my entire statement in one go. I continue to use FOR XML PATH as I assume you used it (rather than STRING_AGG) due to being on SQL Server 2016 or prior.

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

SET @SQL = N'SELECT ' + STUFF((SELECT N',' + @CRLF + N'       ' +
                                      N'MAX(CASE FieldName WHEN ' + QUOTENAME(FieldName,'''') + N' THEN Value END) AS ' + QUOTENAME(FieldName)
                               FROM dbo.DynamicForm
                               GROUP BY FieldName
                               ORDER BY MIN(ID)
                               FOR XML PATH(''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,10,N'') + @CRLF +
           N'FROM dbo.DynamicForm' + @CRLF +
           N'WHERE Ticker = @Ticker' + @CRLF +
           N'  AND ClientCode = @ClientCode' + @CRLF + 
           N'GROUP BY [Order]' + @CRLF + --ORDER is a reserved keyword, and should not be used for object names
           N'ORDER BY [Order];'; --ORDER is a reserved keyword, and should not be used for object names

DECLARE @Ticker varchar(10) = 'X',
        @ClientCode varchar(10) = 'Z';

--Print @SQL; -- Your best friend
EXEC sys.sp_executesql @SQL, N'@Ticker varchar(10), @ClientCode varchar(10)', @Ticker, @ClientCode;

db<>fiddle

Thom A
  • 88,727
  • 11
  • 45
  • 75
  • Sir now script is working but it is showing single data but i have to show multiple data for that ticker & client code wise. –  Aug 10 '21 at 12:37
  • Unfortunately I can't run the above SQL, as I don't have access to your instance, and we don't have your expected results. If you [edit](https://stackoverflow.com/posts/68726792/edit) your question to include **consumable** sample data and expected results, @BabuBhatt , that'll greatly help. This, at present answers why you were getting an error, which is what you were asking about. – Thom A Aug 10 '21 at 12:38
  • Also, please don't assume the genders of the users here; I don't state anywhere what my gender is and you could very easily offend a user here by assuming they are male, @BabuBhatt . – Thom A Aug 10 '21 at 12:39
  • Sorry Sir/Madam. –  Aug 10 '21 at 12:40
  • You're better off with gender neutral language, @BabuBhatt . It is what you agreed to use in the [Code of Conduct](https://stackoverflow.com/conduct). – Thom A Aug 10 '21 at 12:42
  • sure i will do it from next time –  Aug 10 '21 at 12:45
  • I did this changes but still no luck. `set @query = N'SELECT ' + @cols + N',ticker, clientcode from ( select value, fieldname, ticker, clientcode from DynamicForm WHERE Ticker=''X'' AND ClientCode=''Z'' ) x pivot ( max(value) for FieldName in (' + @cols + N') ) p '` –  Aug 10 '21 at 13:19
  • ... Edit your question as I asked in my [comment](https://stackoverflow.com/questions/68726792/sql-server-how-to-convert-rows-to-columns/68726899?noredirect=1#comment121459300_68726899), @BabuBhatt . – Thom A Aug 10 '21 at 13:23
  • @Larnu Since you are using Distinct (By looking at the provided data) you dont need a where clause here. – Gudwlk Aug 10 '21 at 13:27
  • @BabuBhatt Your where clause inside dynamic PIVOT which filters records gives you single row as a result. Check my answer. I mentioned it there. – Gudwlk Aug 10 '21 at 13:28
  • i have edited my questions and there i mention what output should be. please have a look. thanks –  Aug 10 '21 at 13:28
  • i have seen if i remove where clause then still getting same output....no luck. –  Aug 10 '21 at 13:31
  • Without consumable sample data, I can't help you, @BabuBhatt . I can't copy text out of an image. – Thom A Aug 10 '21 at 13:32
  • @Larnu please check my post. now i shared script which you can copy and get data. thanks –  Aug 10 '21 at 13:43
  • @Larnu this line is not clear. how does it create field by field `N'MAX(CASE FieldName WHEN ' + QUOTENAME(FieldName,'''') + N' THEN Value END) AS ' + QUOTENAME(FieldName)` in select ? –  Aug 10 '21 at 14:44
  • @Larnu can i filter data by ticker & client code where using Stuff() function like ` N'MAX(CASE FieldName WHEN ' + QUOTENAME(FieldName,'''') + N' THEN Value END) AS ' + QUOTENAME(FieldName) FROM dbo.DynamicForm WHERE Ticker=''X'' AND ClientCode = ''Z''` if i do not filter here then stuff will load all data irrespective of ticker & client code. so i like to use filter here too and as well as filter will be there in outer query too which is present now. thanks –  Aug 10 '21 at 14:48
  • It's called conditional aggregation, @BabuBhatt . As I said, I used this instead of the more restrictive `PIVOT` operator. – Thom A Aug 10 '21 at 14:51
  • *"an i filter data by ticker & client code"* yes, you can parametrise the `FOR XML PATH` query too. – Thom A Aug 10 '21 at 14:52
  • i am not good in sql. please add one more ticker & client code filter in the select where Stuff() has been used. –  Aug 10 '21 at 15:10
  • @BabuBhatt with the greatest respect, it's you who needs to understand the query. Parametrising a query isn't particularly difficult. If you uncomment the `PRINT` statement you can see an example of it in the dynamic statement... You just need to add the same clauses in `WHERE` that are in the dynamic statement (look at lines 10 and 11). – Thom A Aug 10 '21 at 15:13
  • sure i will try & let you know face any difficulties. thank you so much –  Aug 10 '21 at 15:50
  • @Larnu what is the reason for using XML as the expectation is in PIVOT in the question ? – Gudwlk Aug 15 '21 at 10:39
  • @Gudwlk that is for the String Aggregation, not the pivoting. – Thom A Aug 15 '21 at 11:50
  • But same thing you can try with PIVOT as well. it might be a less complicated solution as well. @Larnu – Gudwlk Aug 16 '21 at 01:33
  • From the answe @Gudwlk ... *"Personally, as well, I would use a conditional aggregate, rather than the restrictive `PIVOT` operator"*, that is why I don't use `PIVOT`. – Thom A Aug 16 '21 at 07:26
-2

If you change the query which assigns values to @Col variable as below added your query will work. To define a table columns they should be identical. No table can have two columns with same name. That was your error given by the code. But I am not sure about your expected output. As I see a where clause which filters data I hope your answer will have only one row.

DECLARE @cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(FieldName) 
                from DynamicForm                    -              
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')


  set @query = N'SELECT ' + @cols + N' from 
         (
            select  value, FieldName
            from DynamicForm WHERE Ticker=''X'' AND ClientCode=''Z''
        ) x
        pivot 
        (
            max(value)
            for FieldName in (' + @cols + N')
        ) p '

   exec sp_executesql @query;

Result

Gudwlk
  • 1,177
  • 11
  • 11
  • 1
    How does this differ from my answer (which was posted 50~ minutes prior to yours)? – Thom A Aug 10 '21 at 13:23
  • @Larnu once after posted I saw your answer :( Sorry about that. if you are to keep the answer I will remove mine. – Gudwlk Aug 10 '21 at 13:25
  • 1
    i have edited my questions and there i mention what output should be. please have a look. thanks –  Aug 10 '21 at 13:28