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
Related
SELECT XMLSERIALIZE(
XMLELEMENT(
NAME "row",
XMLFOREST(
A.TITLE AS "title",
A.TAG as "tag" )))
FROM ARTICLES A;
Expected Result:
Instead of Mentioned Column name(TITLE ,TAG) ,shall we able to keep '*' (means - select * from Articles)
because my table contains 150 columns.
As #data_henrik said, your question it not clear ...
But If I got you right, you want to create a xml doc for all columns from your base table, without having to code all 150 columns in the query.
I don't know a direct way of doing it, but you can do it in a 2 step way.
1st step will be a SELECT statement, that will BUILD your final SELECT based on the columns from your base table..
Let's take DEPARTMENT table from sample db as an example:
db2 => select * from department
DEPTNO DEPTNAME MGRNO ADMRDEPT LOCATION
------ ------------------------------------ ------ -------- ----------------
A00 SPIFFY COMPUTER SERVICE DIV. 000010 A00 -
B01 PLANNING 000020 A00 -
C01 INFORMATION CENTER 000030 A00 -
...
it has 5 columns. The following select will build your final SELECT ...
select
'SELECT XMLROW( ' ||
listagg(rtrim(colname) || ' AS "' || lcase(rtrim(colname)) || '"' , ', ')
|| ' ) FROM DEPARTMENT'
from syscat.columns
where tabname = 'DEPARTMENT'
------------------------------------------------------------------------------------------------------------
SELECT XMLROW( ADMRDEPT AS "admrdept", DEPTNAME AS "deptname", DEPTNO AS "deptno", LOCATION AS "location", MGRNO AS "mgrno" ) FROM DEPARTMENT
If you execute the resulting SELECT. it will produce the xml, similar to what you want.
----------------------------------------------------------------------------------------------------------
<row><admrdept>A00</admrdept><deptname>SPIFFY COMPUTER SERVICE DIV.</deptname><deptno>A00</deptno><mgrno>000010</mgrno></row>
<row><admrdept>A00</admrdept><deptname>PLANNING</deptname><deptno>B01</deptno><mgrno>000020</mgrno></row>
<row><admrdept>A00</admrdept><deptname>INFORMATION CENTER</deptname><deptno>C01</deptno><mgrno>000030</mgrno></row>
Note:
I have used XMLROW, for simplicity.. instead of yours XMLSERIALIZE( XMLELEMEENT( XMLFOREST ... just as an example.. so you get the idea..
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 |
I have a column called 'uri' which has values as follows:
file://c:\file1.txt
file://\\1.1.1.1\folder1\folder1a\file2.txt
file://d:\sub1\sub2\sub3\file3.txt
I'm trying to remove the filename from the uri to leave
file://c:\
file://\\1.1.1.1\folder1\folder1a\
file://d:\sub1\sub2\sub3\
You can use regexp_replace:
with t (col) as (
select 'file://c:\file1.txt' union all
select 'file://\\1.1.1.1\folder1\folder1a\file2.txt' union all
select 'file://d:\sub1\sub2\sub3\file3.txt'
)
select regexp_replace(col, '(^.*?)[^\\]*$', '\1') as output from t;
Produces:
output
---------------------------------
file://c:\
file://\\1.1.1.1\folder1\folder1a\
file://d:\sub1\sub2\sub3\
Demo
Let's say I have a table with two columns:
create table #counties(
state varchar(max),
name varchar(max)
)
insert #counties(state,name) values('Alabama','Autauga')
insert #counties(state,name) values('Alabama','Baldwin')
insert #counties(state,name) values('Texas','Adams')
insert #counties(state,name) values('Texas','Houston')
insert #counties(state,name) values('Wisconsin','Adair')
insert #counties(state,name) values('Wisconsin','Wood')
I'd like the result to be a single string like this:
Autauga;Baldwin^^Adams;Houston^^Adair;Wood
For each change in the first column, I'd like the ^^ delimiter, and for each change in the second column, I'd like the ; delimiter.
I'm aware of the coalesce function but I can't figure out how to use it over two columns, not just one:
declare #c varchar(max)
select #c = COALESCE(#c + ';', '') + name from #counties order by state, name
select #c
This is just for a data load but I'd still like to learn how to do it elegantly with just a select, and hopefully without a cursor loop.
Try it like this
With NamesPerState AS
(
SELECT c1.[state]
,STUFF(
(
SELECT ';' + c2.[name]
FROM #counties AS c2
WHERE c1.[state]=c2.[state]
ORDER BY c2.[name]
FOR XML PATH('')
),1,1,'') AS names
FROM #counties AS c1
GROUP BY c1.[state]
)
SELECT STUFF
(
(
SELECT '^^' + names
FROM NamesPerState
ORDER BY [state]
FOR XML PATH('')
),1,2,''
)
UPDATE
Just to show you, how easy this was with a clean and modern approach:
SELECT [state]
,
(
SELECT c2.[name]
FROM #counties AS c2
WHERE c1.[state]=c2.[state]
ORDER BY c2.[name]
FOR XML RAW('county'),TYPE
)
FROM #counties AS c1
GROUP BY c1.[state]
FOR XML RAW('state'),ROOT('counties')
The result
<counties>
<state state="Alabama">
<county name="Autauga" />
<county name="Baldwin" />
</state>
<state state="Texas">
<county name="Adams" />
<county name="Houston" />
</state>
<state state="Wisconsin">
<county name="Adair" />
<county name="Wood" />
</state>
</counties>
UPDATE 2 Just for fun: the minimal output
SELECT [state] AS [*]
,
(
SELECT c2.[name] AS [*]
FROM #counties AS c2
WHERE c1.[state]=c2.[state]
ORDER BY c2.[name]
FOR XML PATH('c'),TYPE
)
FROM #counties AS c1
GROUP BY c1.[state]
FOR XML PATH('s'),ROOT('counties')
The result
<counties>
<s>Alabama<c>Autauga</c><c>Baldwin</c></s>
<s>Texas<c>Adams</c><c>Houston</c></s>
<s>Wisconsin<c>Adair</c><c>Wood</c></s>
</counties>
And this would get your list back:
DECLARE #x XML=
'<counties>
<s>Alabama<c>Autauga</c><c>Baldwin</c></s>
<s>Texas<c>Adams</c><c>Houston</c></s>
<s>Wisconsin<c>Adair</c><c>Wood</c></s>
</counties>';
SELECT s.value('(text())[1]','nvarchar(max)') AS [state]
,c.value('.','nvarchar(max)') AS [name]
FROM #x.nodes('/counties/s') AS A(s)
OUTER APPLY s.nodes('c') AS B(c)
My requirement is as follows:
Am using Postgresql and ireport 4.0.1 for generating this report.
I've four tables like g_employee,g_year,g_period,g_salary, by joining these four tables and passing parameter are fromDate and toDate these parameter values like '01/02/14' between '01/05/14'.Based this parameters the displaying months will be vary in the headings as i shown in the below example:
EmpName
01/02/14 01/03/14 01/04/14 01/05/14
abc
2000 3000 3000 2000
Can anyone help me in this getting output?
What you're describing sounds like the number of columns would grow or shrink based on the number of months between the 2 parameters, which just doesn't work.
I don't know any way to add additional columns based on an interval between 2 parameters without a procedural code generated sql statement.
What is possible is:
emp_id1 period1 salary
emp_id1 period2 salary
emp_id1 period3 salary
epd_id1 period4 salary
emp_id2 period1 salary
emp_id2 period2 salary
emp_id2 period3 salary
epd_id2 period4 salary
generated with something like:
select g_employee_id,
g_period_start,
g_salary_amt
from g_employee, g_year, g_period, g_salary
where <join everything>
and g_period_start between date_param_1 and date_param_2
group by g_employee_id, g_period_start;
Hard to get more specific with out the table structure.
As the range between date_param_1 and date_param_2 grew, the number of rows would grow for each employee with pay in that "g_period"
EDIT - Other option:
The less dynamic option which requires more parameters would be:
select g_employee_id,
(select g_salary_amount
from g_period, g_salary
where g_period_id = g_salary_period_id
and g_salard_emp_id = g_employee_id
and g_period_start = <DATE_PARAM_1> ) as "DATE_PARAM_1_desc",
(select g_salary_amount
from g_period, g_salary
where g_period_id = g_salary_period_id
and g_salard_emp_id = g_employee_id
and g_period_start = <DATE_PARAM_2> ) as "DATE_PARAM_2_desc",
(select g_salary_amount
from g_period, g_salary
where g_period_id = g_salary_period_id
and g_salard_emp_id = g_employee_id
and g_period_start = <DATE_PARAM_3> ) as "DATE_PARAM_3_desc"
,..... -- dynamic not possible
from employee;
i create one table #g_employee and insert dummy data
create table #g_employee(empid int,yearid int,periodid int,salary int)
insert into #g_employee(empid,yearid,periodid,salary)
select 1,2014,02,2000
union
select 2,2014,02,2000
union
select 3,2014,02,2000
union
select 3,2014,03,2000
union
select 1,2014,03,3000
union
select 1,2014,04,4000
output query as per your requirement :
Solution 1 :
select empid, max(Case when periodid=2 and yearid=2014 then salary end) as '01/02/2014'
, max(Case when periodid=3 and yearid=2014 then salary end) as '01/03/2014'
, max(Case when periodid=4 and yearid=2014 then salary end) as '01/04/2014'
from #g_employee
group by empid
you can do with dynamic sql :
Solution 2 :
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(periodid)
from #g_employee
group by periodid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT empid,' + #cols + ' from
(
select salary, periodid,empid
from #g_employee
) x
pivot
(
max(salary)
for periodid in (' + #cols + ')
) p '
execute(#query)
hope this will help