I have share point list named "Documents" that contains (ID , title , parentID)
where parentID refer to same list and
ID auto generated by share point.
I need to create CAML query that select all documents that parentID equal ID
Maybe you can create a computed field in your List where you do the compare like:
AreIdEquals: [ID] = [ParentId]
And then use:
<Query>
<Where>
<Eq>
<FieldRef Name="AreIdEquals" />
<Value Type="Boolean">1</Value>
</Eq>
</Where>
</Query>
from here: http://social.msdn.microsoft.com/Forums/sharepoint/en-US/ab303453-dfd6-46c4-888a-e15d233c8e57/compare-two-fields-in-caml-query
Related
I have a SQL table Products with 2 columns as below.
ID
ProductDetails
2
<XML>
3
<XML>
The XML column holds the following data:
<Products>
<product key="0" description="">Product1</product>
<product key="1" description="">Product2</product>
<product key="2" description="">Product3</product>
<product key="3" description="">Product4</product>
<product key="4" description="">Product5</product>
<product key="5" description="">Product6</product>
<product key="6" description="">Product7</product>
<product key="7" description="">Product8</product>
</Products>
How can I get the relevant node from the ProductDetails for ProductTitle?
For example: if the ID column has 3, I need to query the ProductDetails column and create a new column with just the ProductTitle to be Product3.
ID
ProductDetails
ProductTitle
5
<XML>
Product5
3
<XML>
Product3
Any help would be appreciated.
Please try the following.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT PRIMARY KEY, ProductDetails XML);
INSERT #tbl (ID, ProductDetails) VALUES
(3, N'<Products>
<product key="0" description="">Product1</product>
<product key="1" description="">Product2</product>
<product key="2" description="">Product3</product>
<product key="3" description="">Product4</product>
<product key="4" description="">Product5</product>
<product key="5" description="">Product6</product>
<product key="6" description="">Product7</product>
<product key="7" description="">Product8</product>
</Products>');
-- DDL and sample data population, end
SELECT ID
, ProductDetails.value('(/Products/product[#key=sql:column("ID")]/text())[1]','VARCHAR(20)') AS ProductTitle
FROM #tbl;
Output
ID
ProductTitle
3
Product4
You need to use the XML .nodes() function to access and filter the "product" XML elements, and then the .value() function to extract the desired text value from that node. Both take xpath parameters to specify the data to be extracted.
Try
SELECT P.*, X.N.value('text()[1]', 'nvarchar(max)')
FROM #Products P
CROSS APPLY #ProductXml.nodes('/Products/product[#key=sql:column("P.ID")]') X(N)
or equivilently:
SELECT P.*, PN.ProductName
FROM #Products P
CROSS APPLY (
SELECT ProductName = X.N.value('text()[1]', 'nvarchar(max)')
FROM #ProductXml.nodes('/Products/product[#key=sql:column("P.ID")]') X(N)
) PN
or even
SELECT P.*, PN.ProductName
FROM #Products P
JOIN (
SELECT
ProductKey = X.N.value('#key', 'nvarchar(max)'),
ProductName = X.N.value('text()[1]', 'nvarchar(max)')
FROM #ProductXml.nodes('/Products/product') X(N)
) PN ON PN.ProductKey = P.ID
The subselect in the latter could also be used to build a temp table for more traditional query access.
In the xpath strings,
/Products/product selects all product nodes
[#key = ...] selects the key attribute to be used as a filter
(equality)
sql:column("P.ID") allows a reference back to a column
in the containing SQL
text() is a special selector that chooses the text within the XML element
[1] filters that down to at most a single value (a singleton)
nvarchar(max) defines the result datatype for the .value() function.
See this db<>fiddle.
I have next below XML message:
<Message xmlns="http://test.org">
<Request Promotion="MULANN">
<ExpireDate>23/10/2020 07:10</ExpireDate>
<Entries>
<Entry>
<Product>
<Product Product="T1" />
</Product>
<Payment>
<Privacy>N</Privacy>
</Payment>
</Entry>
<Entry>
<Product>
<Product Product="T2" />
</Product>
<Payment>
<Privacy>N</Privacy>
</Payment>
</Entry>
<Entry>
<Product>
<Product Product="T3" />
</Product>
<Payment>
<Privacy>Y</Privacy>
</Payment>
</Entry>
</Entries>
</Request>
</Message>
For this xml message, I have three times the xml tag Privacy
How can I get the distinct value of privacy for all of them without fetch the error?.
Now I'm using next below query that contain the error:
select distinct x.Promotion, x.Privacy
from TableName a
cross join XMLTable(XMLNAMESPACES('http://test.org' AS "XML"),
'/XML:Message' passing xmltype(xml_info) columns
Promotion VARCHAR2(20) path 'XML:Request/#Promotion'
Iban_TABD CHAR(1) path 'XML:Request/XML:Entries/XML:Entry/XML:Payment/XML:Privacy')x
I'd like to get something like this:
Promotion Privacy
MULANN N
MULANN Y
The problem is that the XML has multiple levels of nesting.
You solve this by chaining the XMLTABLEs.
If not all information is always available in the nested children, an outer join helps.
SELECT DISTINCT
promotion,
privacy
FROM TableName,
XMLTABLE( XMLNAMESPACES( DEFAULT 'http://test.org'),
'/Message' PASSING XMLTYPE(xml_info)
COLUMNS promotion VARCHAR2(20) PATH 'Request/#Promotion',
entries XMLTYPE PATH 'Request/Entries/Entry'
) x1
LEFT OUTER JOIN (
XMLTABLE( XMLNAMESPACES( DEFAULT 'http://test.org'),
'/Entry' PASSING x1.entries
COLUMNS privacy VARCHAR2(1) PATH 'Payment/Privacy'
)) x2
ON 1=1;
So I have dataset1 that has something like SELECT userID from table1 where ... from DataBase1
And I have dataset2 that has some complicated SQL on DataBase2 that must have parameter ... where userID = :userID...
So how can I pass that userID that I get in SQL from DB1 to SQL that I'm running in DB2?
Here is a simple example. Two queries like you mentioned. I have an incoming parameter to select a set from the first table (parent records). And then I pass the userID to the second query (child records). I show how that works in the data structure too, how each parent record can have child records.
<?xml version="1.0" ?>
<dataTemplate name="DATA_DEFINITION_NAME" version="1.0" defaultPackage="DATA_DEFINITION_CODE">
<properties>
<property name="ENCODING" value="windows-1252"/>
<property name="debug_mode" value="on" />
<property name="scalable_mode" value="on" />
</properties>
<parameters>
<parameter name="i_parameter" dataType="NUMBER" />
</parameters>
<dataQuery>
<sqlStatement name="Q_TABLE_1"><![CDATA[select userid, username from table1 where column1 = :i_parameter ]]></sqlStatement>
<sqlStatement name="Q_TABLE_2"><![CDATA[select ValueColumn from table2 where userid = :userid ]]></sqlStatement>
</dataQuery>
<dataStructure>
<group name="users" source="Q_TABLE_1">
<element name="username" value="username" />
<group name="userdata" source="Q_TABLE_2">
<element name="ValueColumn" value="ValueColumn" />
</group>
</group>
</dataStructure>
</dataTemplate>
I have a task that requires me to pull in a set of xml files, which are all related, then pick out a subset of records from these files, transform some columns, and export to a a single xml file using a different format.
I'm new to SSIS, and so far I've managed to first import two of the xml files (for simplicity, starting with just two files).
The first file we can call "Item", containing some basic metadata, amongst those an ID, which is used to identify related records in the second file "Milestones". I filter my "valid records" using a lookup transformation in my dataflow - now I have the valid Item ID's to fetch the records I need. I funnel these valid ID's (along with the rest of the columns from Item.xml through a Sort, then into a merge join.
The second file is structured with 2 outputs, one containing two columns (ItemID and RowID). The second containing all of the Milestone related data plus a RowID. I put these through a inner merge join, based on RowID, so I have the ItemID in with the milestone data. Then I do a full outer join merge join on both files, using ItemID.
This gives me data sort of like this:
ItemID[1] - MilestoneData[2]
ItemID[1] - MilestoneData[3]
ItemID[1] - MilestoneData[4]
ItemID[1] - MilestoneData[5]
ItemID[2] - MilestoneData[6]
ItemID[2] - MilestoneData[7]
ItemID[2] - MilestoneData[8]
I can put this data through derived column transformations to create the columns of data I actually need, but I can't see how to structure this in a relational way/normalize it into a different xml format.
The idea is to output something like:
<item id="1">
<Milestone id="2">
<Milestone />
<Milestone id="3">
<Milestone />
</item>
Can anyone point me in the right direction?
UPDATE:
A bit more detailed picture of what I have, and what I'd like to achieve:
Item.xml:
<Items>
<Item ItemID="1">
<Title>
Data
</Title>
</Item>
<Item ItemID="2">
...
</Item>
...
</Items>
Milestone.xml:
<Milestones>
<Item ItemID="2">
<MS id="3">
<MS_DATA>
Data
</MS_DATA>
</MS>
<MS id="4">
<MS_DATA>
Data
</MS_DATA>
</MS>
</Item>
<Item ItemID="3">
<MS id="5">
<MS_DATA>
Data
</MS_DATA>
</MS>
</item>
</Milestones>
The way it's presented in SSIS when I use XML source, is not entirely intuitive, meaning the Item rows and the MS rows are two seperate outputs. I had to run these through a join in order to get the Milestones that corresponds to specific Items. No problem here, then run it through a full outer join with the items, so I get a flattened table with multiple rows containing obviously the same data for an Item and with different data for the MS. Basically I get what I tried to show in my table, lots of redundant Item data, for each unique MilestoneData.
In the end it has to look similar to:
<NewItems>
<myNewItem ItemID="2">
<SomeDataDirectlyFromItem>
e.g. Title
</SomeDataDirectlyFromItem>
<DataConstructedFromMultipleColumnsInItem>
<MyMilestones>
<MS_DATA_TRANSFORMED MSID="3">
data
</MS_DATA_TRANSFORMED>
<MS_DATA_TRANSFORMED MSID="4">
data
</MS_DATA_TRANSFORMED>
</MyMilestones>
</DataConstructedFromMultipleColumnsInItem>
<myNewItem ItemID="3">
<SomeDataDirectlyFromItem>
e.g. Title
</SomeDataDirectlyFromItem>
<DataConstructedFromMultipleColumnsInItem>
<MyMilestones>
<MS_DATA_TRANSFORMED MSID="5">
data
</MS_DATA_TRANSFORMED>
</MyMilestones>
</DataConstructedFromMultipleColumnsInItem>
</myNewItem>
<myNewItem ItemID="4">
<SomeDataDirectlyFromItem>
e.g. Title
</SomeDataDirectlyFromItem>
<DataConstructedFromMultipleColumnsInItem>
<MyMilestones></MyMilestones>
</DataConstructedFromMultipleColumnsInItem>
</myNewItem>
</NewItems>
I would try to handle this using a script component with the component type transformation. As you are new to ssis, i assume you haven't used this before. So basically you
define input columns, your component will expect (i.e. column input_xml containing ItemID[1] - MilestoneData[2];...
use c# to create a logic which cuts and sticks together
define output columns your component will use to deliver the transformed row
You will face the problem that one row will probably be used two times in the end, like i.e.
ItemID[1] - MilestoneData[2]
will result in
<item id="1">
<Milestone id="2">
I have done something pretty similar using Pentaho kettle, even without using something like a script component in which you define own logic. But i guess ssis has a lack of tasks here.
How about importing the XML into relational tables ( eg in tempdb ) then using FOR XML PATH to reconstruct the XML? FOR XML PATH offers a high degree of control over how you want the XML to look. A very simple example below:
CREATE TABLE #items ( itemId INT PRIMARY KEY, title VARCHAR(50) NULL )
CREATE TABLE #milestones ( itemId INT, msId INT, msData VARCHAR(50) NOT NULL, PRIMARY KEY ( itemId, msId ) )
GO
DECLARE #itemsXML XML
SELECT #itemsXML = x.y
FROM OPENROWSET( BULK 'c:\temp\items.xml', SINGLE_CLOB ) x(y)
INSERT INTO #items ( itemId, title )
SELECT
i.c.value('#ItemID', 'INT' ),
i.c.value('(Title/text())[1]', 'VARCHAR(50)' )
FROM #itemsXML.nodes('Items/Item') i(c)
GO
DECLARE #milestoneXML XML
SELECT #milestoneXML = x.y
FROM OPENROWSET( BULK 'c:\temp\milestone.xml', SINGLE_CLOB ) x(y)
INSERT INTO #milestones ( itemId, msId, msData )
SELECT
i.c.value('#ItemID', 'INT' ),
i.c.value('(MS/#id)[1]', 'VARCHAR(50)' ) msId,
i.c.value('(MS/MS_DATA/text())[1]', 'VARCHAR(50)' ) msData
FROM #milestoneXML.nodes('Milestones/Item') i(c)
GO
SELECT
i.itemId AS "#ItemID"
FROM #items i
INNER JOIN #milestones ms ON i.itemId = ms.itemId
FOR XML PATH('myNewItem'), ROOT('NewItems'), TYPE
DROP TABLE #items
DROP TABLE #milestones
I am using a CTE to recurse data I have stored in a recursive table. The trouble is I am trying to figure out how I can use "FOR XML" to build the desired xml output. I have a Table of Contents table I am recursing and I want to be able to use that data to generate the XML.
Here is an example of what the data is simliar to:
ID|TOC_ID|TOC_SECTION|TOC_DESCRIPTON|PARENT_ID
1|I|Chapter|My Test Chapter|-1
2|A|Section|My Test Section|1
3|1|SubSection|My SubSection|2
I want to be able to spit out the data like so:
XML Attributes:
ID = Appended values from the TOC_ID field
value = value from TOC_Section field
<FilterData>
<Filter id="I" value="Chapter">
<Description>My Test Chapter</Description>
<Filter id="I_A" value="Section">
<Description>My Test Section</Description>
<Filter id="I_A_1" value="SubSection">
<Description>My Test SubSection</Description>
</Filter>
</Filter>
</Filter>
</FilterData>
Not sure how I can take the CTE data and produce a similar format to the above. When the data is in separate tables it isn't too difficult to build this type of output.
As always appreciate the input.
Thanks,
S
You may get some mileage from Recursive Hierarchies to XML in Christian Wade's blog - it all looks mighty painful to me!
Check this out Will (Not sure you are still following)....this does have a 32 level max, but that should still work fine for my stuff...can't see going deeper than that. Found this on another forum:
CREATE TABLE tree ( id INT, name VARCHAR(5), parent_id INT )
GO
INSERT INTO tree VALUES ( 1, 'N1', NULL )
INSERT INTO tree VALUES ( 3, 'N4', 1 )
INSERT INTO tree VALUES ( 4, 'N10', 3 )
INSERT INTO tree VALUES ( 5, 'N7', 3 )
GO
CREATE FUNCTION dbo.treeList(#parent_id int)
RETURNS XML
WITH RETURNS NULL ON NULL INPUT
BEGIN RETURN
(SELECT id as "#id", name as "#name",
CASE WHEN parent_id=#parent_id
THEN dbo.treeList(id)
END
FROM dbo.tree WHERE parent_id=#parent_id
FOR XML PATH('tree'), TYPE)
END
GO
SELECT id AS "#id", name AS "#name",
CASE WHEN id=1
THEN dbo.treeList(id)
END
FROM tree
WHERE id=1
FOR XML PATH('tree'), TYPE
Now isn't that nice and simple?
Customised from the great example over on http://msdn.microsoft.com/en-us/library/ms345137.aspx