Looking to pivot/transpose with tsql (or something else)? on a table with multiple rows per item number, one row per Code (unit of measure).
It would have to be dynamic as there could be lot of different unit of measure codes per item.
Current data table:
select [Item No_], Code, [Qty_ per Unit of Measure], Weight, Cubage
from [mycompany$Item Unit of Measure]
where [Item No_] in ('007967','007968')
Desired output would be:
Addiotional info
We have a table that holds all the possible Unit of Measure codes that perhaps could be used in the final code?
select
Code
from [mycompany$Unit of Measure]
How to acchieve this, and what would the SQL code look like?
Suggested solution from #Larnu :
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(Code)
FROM [mycompany$Unit of Measure]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query =
'SELECT *
FROM
(
SELECT
o.[Item No_],
p.Code,
o.Weight
FROM [mycompany$Item Unit of Measure] AS o
INNER JOIN [mycompany$Unit of Measure] AS p ON o.Code = p.Code
) AS t
PIVOT
(
MAX(Weight)
FOR Code IN( ' + #cols + ' )' +
' ) AS p ; ';
execute(#query);
However this only give max value for Weight and not Cubage. Also it doesn't meet the desired end results as column heads are not tagged with CODE.Cubage, CODE.Weight etc. (PALLET.Weight, PALLET.Cubage)
Screenshot of results with above code:
Below have the xml framing fields,
**Xml_value=
<docs><doc_id>1234</doc_id>
<reci><reci_code>ss</reci_code>
</reci></docs>**
Select doc.value('doc_id[1]',varchar(8)')doc_id,
Reci.value('reci_code'[1],char(8)')reci_code
From xml_value.nodes('docs/doc')docs(doc)
cross apply docs.nodes('reci/reci')reci'(reci')
Output:
doc_id reci_code
1234 ss
The above mentioned query is for SQL server.
need to extract all XML fields into a separate columns as like above output statement in db2.
How to achieve this in db 2.
can you help on this.
Try this:
/*
WITH MYTABLE AS
(
SELECT T.*
FROM
(
VALUES XMLPARSE
(
DOCUMENT '
<docs>
<doc_id>1234</doc_id>
<reci>
<reci_code>ss</reci_code>
</reci>
</docs>
'
)
) T(X)
)
*/
SELECT V.DOC_ID, V.RECI_CODE
FROM
MYTABLE T
, XMLTABLE
(
'$D/docs/reci' PASSING T.X AS "D"
COLUMNS
DOC_ID INT PATH '../doc_id'
, RECI_CODE VARCHAR(10) PATH 'reci_code'
) V;
|DOC_ID |RECI_CODE |
|----------|----------|
|1234 |ss |
In db2,
<row><element name>January</element name>
<error code>1010<\error code></row>
Need to frame as like this in db2 select statement.
In SQL server will handle this with the help of XML path()
Try this:
SELECT T.*
FROM
(
VALUES
'
<row>
<element_name>January</element_name>
<error_code>1010</error_code>
</row>
'
,
'
<row>
<element_name>February</element_name>
<error_code>2020</error_code>
</row>
'
) D(X)
, XMLTABLE
(
'$X/row' PASSING XMLPARSE (DOCUMENT D.X) AS "X"
COLUMNS
ENAME VARCHAR(10) PATH 'element_name'
, ERROR INT PATH 'error_code'
) T
which produces this output
ENAME ERROR
-------- -----
January 1010
February 2020
I tried this query
DECLARE #AdvancedSearchSelectedDropdownName TABLE (
SelectedIds VARCHAR(2048),
AdvanceSearchOptionTypeId INT
)
INSERT INTO #AdvancedSearchSelectedDropdownName
VALUES ('4_0,5_1,6_2,7_3', 23),
('62_3', 21), ('2_4', 23)
DECLARE #selectedIds VARCHAR(MAX) = '';
SELECT #selectedIds +=
CASE WHEN SelectedIds IS NULL
THEN #selectedIds + ISNULL(SelectedIds + ',', '')
WHEN SelectedIds IS NOT NULL
THEN SUBSTRING(SelectedIds, 0, CHARINDEX('_', SelectedIds, 0)) + ','
END
FROM #AdvancedSearchSelectedDropdownName WHERE advanceSearchOptionTypeId = 23
SELECT #selectedIds
Current output: 4,2
Required output: 4,5,6,7,2
We may have n number of comma separated values in the SelectedIds column.
You might go this route:
WITH Casted AS
(
SELECT *
,CAST('<x><y>' + REPLACE(REPLACE(SelectedIds,'_','</y><y>'),',','</y></x><x><y>') + '</y></x>' AS XML) SplittedToXml
FROM #AdvancedSearchSelectedDropdownName
)
SELECT *
FROM Casted;
This will return your data in this form:
<x>
<y>4</y>
<y>0</y>
</x>
<x>
<y>5</y>
<y>1</y>
</x>
<x>
<y>6</y>
<y>2</y>
</x>
<x>
<y>7</y>
<y>3</y>
</x>
Now we can grab all the x and just the first y:
WITH Casted AS
(
SELECT *
,CAST('<x><y>' + REPLACE(REPLACE(SelectedIds,'_','</y><y>'),',','</y></x><x><y>') + '</y></x>' AS XML) SplittedToXml
FROM #AdvancedSearchSelectedDropdownName
)
SELECT Casted.AdvanceSearchOptionTypeId AS TypeId
,x.value('y[1]/text()[1]','int') AS IdValue
FROM Casted
CROSS APPLY SplittedToXml.nodes('/x') A(x);
The result:
TypeId IdValue
23 4
23 5
23 6
23 7
21 62
23 2
Hint: Do not store comma delimited values!
It is a very bad idea to store your data in this format. You can use a generic format like my XML to store this or a structure of related side tables. But such construction tend to turn out as a real pain in the neck...
After a little re-think. Perhaps something a little more straightforward.
Now, if you have a limited number of _N
Example
;with cte as (
Select *
,RN = Row_Number() over(Order by (Select NULL))
From #AdvancedSearchSelectedDropdownName A
)
Select AdvanceSearchOptionTypeId
,IDs = replace(
replace(
replace(
replace(
replace(
stuff((Select ',' +SelectedIds From cte Where AdvanceSearchOptionTypeId=A.AdvanceSearchOptionTypeId Order by RN For XML Path ('')),1,1,'')
,'_0','')
,'_1','')
,'_2','')
,'_3','')
,'_4','')
From cte A
Group By AdvanceSearchOptionTypeId
Returns
AdvanceSearchOptionTypeId IDs
21 62
23 4,5,6,7,2
If interested in a helper function.
Tired of extracting strings (left, right, charindex, patindex, ...) I modified s split/parse function to accept TWO non-like delimiters. In this case a , and _.
Example
;with cte as (
Select A.AdvanceSearchOptionTypeId
,B.*
,RN = Row_Number() over(Order by (Select NULL))
From #AdvancedSearchSelectedDropdownName A
Cross Apply [dbo].[tvf-Str-Extract](','+A.SelectedIds,',','_') B
)
Select AdvanceSearchOptionTypeId
,IDs = stuff((Select ',' +RetVal From cte Where AdvanceSearchOptionTypeId=A.AdvanceSearchOptionTypeId Order by RN,RetVal For XML Path ('')),1,1,'')
From cte A
Group By AdvanceSearchOptionTypeId
Returns
AdvanceSearchOptionTypeId IDs
21 62
23 4,5,6,7,2
The TVF if Interested
CREATE FUNCTION [dbo].[tvf-Str-Extract] (#String varchar(max),#Delimiter1 varchar(100),#Delimiter2 varchar(100))
Returns Table
As
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 N1,cte1 N2,cte1 N3,cte1 N4,cte1 N5,cte1 N6) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter1) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter1)) = #Delimiter1),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter1,#String,s.N),0)-S.N,8000) From cte3 S)
Select RetSeq = Row_Number() over (Order By N)
,RetPos = N
,RetVal = left(RetVal,charindex(#Delimiter2,RetVal)-1)
From (
Select *,RetVal = Substring(#String, N, L)
From cte4
) A
Where charindex(#Delimiter2,RetVal)>1
)
/*
Max Length of String 1MM characters
Declare #String varchar(max) = 'Dear [[FirstName]] [[LastName]], ...'
Select * From [dbo].[tvf-Str-Extract] (#String,'[[',']]')
*/
Disclaimer.As per first Normal form, you should not store multiple values in a single cell. I would suggest you to avoid storing this way.
Still the approach would be: Create a UDF function which separates comma separated list into a table valued variable. Below code I have not tested. but, it gives idea on how to approach this problem.
Refer to CSV to table approaches
Declare #selectedIds varchar(max) = '';
SET #selectedIds = SELECT STUFF
(SELECT ','+ (SUBSTRING(c.value, 0, CHARINDEX('_', c.value, 0))
FROM #AdvancedSearchSelectedDropdownName AS tv
CROSS APPLY dbo.udfForCSVToList(SelectedIds) AS c
WHERE advanceSearchOptionTypeId = 23
FOR XML PATH('')),1,2,'');
SELECT #selectedIds
I have a table where one field is JSON string.
"CX.UW.001": "03/08/2017", "CX.UW.001.AUDIT": "admin",
I want to produce an SSRS report where it appears in readable format like:
CX.UW.001: 03/08/2017
CX.UW.001.AUDIT: admin
Is it possible?
If you are looking for multiple records, just about any parse/split function will do, or you can use a simple CROSS APPLY in concert with a little XML
Declare #YourTable table (ID int, JSON varchar(max))
Insert Into #YourTable values
(1,'"CX.UW.001": "03/08/2017", "CX.UW.001.AUDIT": "admin"')
Select A.ID
,DisplayAs = replace(B.RetVal,'"','')
From #YourTable A
Cross Apply (
Select RetSeq = Row_Number() over (Order By (Select null))
,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(A.JSON,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as X
Cross Apply x.nodes('x') AS B(i)
) B
Returns
ID DisplayAs
1 CX.UW.001: 03/08/2017
1 CX.UW.001.AUDIT: admin
Or If you want the string to wrap
Select A.ID
,DisplayAs = replace(replace(JSON,',',char(13)),'"','')
From #YourTable A
Returns
1 CX.UW.001: 03/08/2017
CX.UW.001.AUDIT: admin
Right click that field, choose expression, locate Text from Common Functions category, use Replace function, should be the syntax like :
Replace (Fields!Yours.Value.Value,"""","")
Or in TSQL:
Select Replace(JSON_COLUMN,'"','')
From table