I am using snowflake
I am looking to insert data to a table while using a variable
The purpose of using the variable is so when I can change it without doing a find and replace all
CREATE OR REPLACE TABLE DB1.PUBLIC.HUMANS (
HUMAN VARCHAR(32)
)
;
The following works
INSERT INTO DB1.PUBLIC.HUMANS
SELECT 'SUCESS';
The following does not work
SET EXPORT_TABLE = 'DB1.PUBLIC.HUMANS';
INSERT INTO TABLE($EXPORT_TABLE)
SELECT 'FAILURE';
HOWEVER this works.
SELECT * FROM TABLE($EXPORT_TABLE);
Is there is a way to insert into a table defined by a table literal?
reference documentation:
https://docs.snowflake.com/en/sql-reference/literals-table.html
https://docs.snowflake.com/en/sql-reference/sql/insert.html
======================================================
Update: Answer found by comments below.
Thanks to Biraja Mohanty and Greg Pavlik
To make this work have to wrap the IDENTIFIER().
INSERT INTO IDENTIFIER($EXPORT_TABLE);
https://docs.snowflake.com/en/sql-reference/session-variables.html
SET EXPORT_TABLE = 'DB1.PUBLIC.HUMANS';
INSERT INTO identifier($EXPORT_TABLE)
SELECT 'FAILURE';
I'm trying to update some XML data in SQL Server. The XML contains data that looks like this:
<root>
<id>1</id>
<timestamp>16-10-2017 19:24:55</timestamp>
</root>
Let's say this XML exists in a column called Data in a table called TestTable.
I would like to be able to change the hyphens in the timestamp to forward slashes.
I was hoping I might be able to do something like:
update TestTable
set Data.modify('replace value of
(/root/timestamp/text())[1] with REPLACE((/root/timestamp/text())[1], "-", "/")')
I get the following error:
XQuery [TestTable]: There is no function '{http://www.w3.org/2004/07/xpath-functions}:REPLACE()'
When I think about it, this makes sense. But I wonder, is there a way to do this in a single update statement? Or do I first need to query the timestamp value and save it as a variable, and then update the XML with the variable?
You can also do this with a join to an inline view and use the SQL REPLACE function:
CREATE TABLE TestTable
(
Id INT IDENTITY(1,1) NOT NULL,
Data XML NOT NULL
)
INSERT TestTable (Data) VALUES ('<root>
<id>1</id>
<timestamp>16-10-2017 19:24:55</timestamp>
</root>')
UPDATE TestTable
SET Data.modify('replace value of
(/root/timestamp/text())[1] with sql:column("T2.NewData")')
FROM TestTable T1
INNER JOIN (
SELECT Id
, REPLACE( Data.value('(/root/timestamp/text())[1]', 'nvarchar(max)'), '-', '/') AS NewData
FROM TestTable
) T2
ON T1.Id = T2.Id
SELECT * FROM TestTable
Note: this answer assumes you want to have this formatted for the purpose of displaying this as a string, and not parsing the content as a xs:dateTime. If you want the latter, Shungo's answer will format it as such.
It seems that replace is not a supported XQuery function in SQL Server at the time of this writing. You can use the substring function along with the concat function in a "replace value of (XML DML)" though.
CREATE TABLE #t(x XML);
INSERT INTO #t(x)VALUES(N'<root><id>1</id><timestamp>16-10-2017 19:24:55</timestamp></root>');
UPDATE
#t
SET
x.modify('replace value of (/root/timestamp/text())[1]
with concat(substring((/root/timestamp/text())[1],1,2),
"/",
substring((/root/timestamp/text())[1],4,2),
"/",
substring((/root/timestamp/text())[1],7)
) ')
SELECT*FROM #t;
Giving as a result:
<root><id>1</id><timestamp>16/10/2017 19:24:55</timestamp></root>
If there's no external need you have to fullfill, you should use ISO8601 date/time strings within XML.
Your dateTime-string is culture related. Reading this on different systems with differing language or dateformat settings will lead to errors or - even worse!!! - to wrong results.
A date like "08-10-2017" can be the 8th of October or the 10th of August...
The worst point is, that this might pass all your tests successfully, but will break on a customer's machine with strange error messages or bad results down to real data dammage!
Switching the hyphens to slashes is just cosmetic! An XML is a strictly defined data container. Any non-string data must be represented as a secure convertible string.
This is what you should do:
DECLARE #tbl TABLE(ID INT IDENTITY,YourXML XML);
INSERT INTO #tbl VALUES
(N'<root>
<id>1</id>
<timestamp>16-10-2017 19:24:55</timestamp>
</root>');
UPDATE #tbl SET YourXml.modify(N'replace value of (/root/timestamp/text())[1]
with concat( substring((/root/timestamp/text())[1],7,4), "-"
,substring((/root/timestamp/text())[1],4,2), "-"
,substring((/root/timestamp/text())[1],1,2), "T"
,substring((/root/timestamp/text())[1],12,8)
) cast as xs:dateTime?');
SELECT * FROM #tbl;
The result
<root>
<id>1</id>
<timestamp>2017-10-16T19:24:55</timestamp>
</root>
you can try string replacement like below
update testtable
set data= cast(
concat(
left(cast(data as varchar(max)),charindex('<timestamp>',cast(data as varchar(max)))+len('<timestamp>')-1),
replace(
substring(
cast(data as varchar(max)),
len('<timestamp>') +
charindex( '<timestamp>', cast(data as varchar(max))) ,
charindex('</timestamp>',cast(data as varchar(max)))
-charindex('<timestamp>',cast(data as varchar(max)))
-len('<timestamp>')
),
'-','/'),
right(cast(data as varchar(max)),len(cast(data as varchar(max)))-charindex('</timestamp>',cast(data as varchar(max)))+1)
) as xml)
select *
from testtable
working demo
I have a column of type nvarchar(1000) that contains something that looks like an XML:
<Master>
<NodeA>lorem ipsum</NodeA>
<NodeB>lorem ipsum</NodeB>
<NodeC>lorem ipsum</NodeC>
<NodeD>lorem ipsum</NodeD>
</Master>
The value might have some carriage return and new lines embedded on it.
What would be the easiest way to get the value inside NodeA?
I've tried to remove the hardcoded string value <masterA> but then I feel I'm doing something wrong here.
Try this:
DECLARE #XmlTable TABLE (ID INT NOT NULL, XmlContent NVARCHAR(1000))
INSERT INTO #XmlTable (ID, XmlContent)
VALUES (1, N'<Master>
<NodeA>lorem ipsum</NodeA>
<NodeB>lorem ipsum</NodeB>
<NodeC>lorem ipsum</NodeC>
<NodeD>lorem ipsum</NodeD>
</Master>')
SELECT
CAST(XmlContent AS XML).value('(/Master/NodeA)[1]', 'varchar(50)')
FROM
#XmlTable
WHERE
ID = 1
But if your column really only stores XML - you should make it an XML column - that's easier (no need to always do a CAST(... AS XML) before applying any XQuery methods), and it's also optimized in terms of storage.
I have a table with an ntext type column that holds xml. I have tried to apply many examples of how to pull the value for the company's name from the xml for a particular node, but continue to get a syntax error. Below is what I've done, except substituted my select statement for the actual xml output
DECLARE #companyxml xml
SET #companyxml =
'<Home>
<slideshowImage1>1105</slideshowImage1>
<slideshowImage2>1106</slideshowImage2>
<slideshowImage3>1107</slideshowImage3>
<slideshowImage4>1108</slideshowImage4>
<slideshowImage5>1109</slideshowImage5>
<bottomNavImg1>1155</bottomNavImg1>
<bottomNavImg2>1156</bottomNavImg2>
<bottomNavImg3>1157</bottomNavImg3>
<pageTitle>Acme Capital Management |Homepage</pageTitle>
<metaKeywords><![CDATA[]]></metaKeywords>
<metaDescription><![CDATA[]]></metaDescription>
<companyName>Acme Capital Management</companyName>
<logoImg>1110</logoImg>
<pageHeader></pageHeader>
</Home>'
SELECT c.value ('companyName','varchar(1000)') AS companyname
FROM #companyxml.nodes('/Home') AS c
For some reason, the select c.value statement has a syntax problem that I can't figure out. On hover in SSMS, it says 'cannot find either column "c" or the user-defined function or aggregate "c.value", or the name is ambiguous.'
Any help on the syntax would be greatly appreciated.
try this
DECLARE #companyxml xml
SET #companyxml =
'<Home>
<slideshowImage1>1105</slideshowImage1>
<slideshowImage2>1106</slideshowImage2>
<slideshowImage3>1107</slideshowImage3>
<slideshowImage4>1108</slideshowImage4>
<slideshowImage5>1109</slideshowImage5>
<bottomNavImg1>1155</bottomNavImg1>
<bottomNavImg2>1156</bottomNavImg2>
<bottomNavImg3>1157</bottomNavImg3>
<pageTitle>Acme Capital Management Homepage</pageTitle>
<metaKeywords>CDATA</metaKeywords>
<metaDescription>CDATA</metaDescription>
<companyName>Acme Capital Management</companyName>
<logoImg>1110</logoImg>
<pageHeader></pageHeader>
</Home>'
DECLARE #Result AS varchar(50)
SET #result = #companyxml.value('(/Home/companyName/text())[1]','varchar(50)')
SELECT #result
Take for example the following XML:
Initial Data
<computer_book>
<title>Selecting XML Nodes the Fun and Easy Way</title>
<isbn>9999999999999</isbn>
<pages>500</pages>
<backing>paperback</backing>
</computer_book>
and:
<cooking_book>
<title>50 Quick and Easy XML Dishes</title>
<isbn>5555555555555</isbn>
<pages>275</pages>
<backing>paperback</backing>
</cooking_book>
I have something similar in a single xml-typed column of a SQL Server 2008 database. Using SQL Server XQuery, would it be possible to get results such as this:
Resulting Data
<computer_book>
<title>Selecting XML Nodes the Fun and Easy Way</title>
<pages>500</pages>
</computer_book>
and:
<cooking_book>
<title>50 Quick and Easy XML Dishes</title>
<isbn>5555555555555</isbn>
</cooking_book>
Please note that I am not referring to selecting both examples in one query; rather I am selecting each via its primary key (which is in another column). In each case, I am essentially trying to select the root and an arbitrary subset of children. The roots can be different, as seen above, so I do not believe I can hard-code the root node name into a "for xml" clause.
I have a feeling SQL Server's XQuery capabilities will not allow this, and that is fine if it is the case. If I can accomplish this, however, I would greatly appreciate an example.
Here is the test data I used in the queries below:
declare #T table (XMLCol xml)
insert into #T values
('<computer_book>
<title>Selecting XML Nodes the Fun and Easy Way</title>
<isbn>9999999999999</isbn>
<pages>500</pages>
<backing>paperback</backing>
</computer_book>'),
('<cooking_book>
<title>50 Quick and Easy XML Dishes</title>
<isbn>5555555555555</isbn>
<pages>275</pages>
<backing>paperback</backing>
</cooking_book>')
You can filter the nodes under to root node like this using local-name() and a list of the node names you want:
select XMLCol.query('/*/*[local-name()=("isbn","pages")]')
from #T
Result:
<isbn>9999999999999</isbn><pages>500</pages>
<isbn>5555555555555</isbn><pages>275</pages>
If I understand you correctly the problem with this is that you don't get the root node back.
This query will give you an empty root node:
select cast('<'+XMLCol.value('local-name(/*[1])', 'varchar(100)')+'/>' as xml)
from #T
Result:
<computer_book />
<cooking_book />
From this I have found two solutions for you.
Solution 1
Get the nodes from your table to a table variable and then modify the XML to look like you want.
-- Table variable to hold the node(s) you want
declare #T2 table (RootNode xml, ChildNodes xml)
-- Fetch the xml from your table
insert into #T2
select cast('<'+XMLCol.value('local-name(/*[1])', 'varchar(100)')+'/>' as xml),
XMLCol.query('/*/*[local-name()=("isbn","pages")]')
from #T
-- Add the child nodes to the root node
update #T2 set
RootNode.modify('insert sql:column("ChildNodes") into (/*)[1]')
-- Fetch the modified XML
select RootNode
from #T2
Result:
RootNode
<computer_book><isbn>9999999999999</isbn><pages>500</pages></computer_book>
<cooking_book><isbn>5555555555555</isbn><pages>275</pages></cooking_book>
The sad part with this solution is that it does not work with SQL Server 2005.
Solution 2
Get the parts, build the XML as a string and cast it back to XML.
select cast('<'+XMLCol.value('local-name(/*[1])', 'varchar(100)')+'>'+
cast(XMLCol.query('/*/*[local-name()=("isbn","pages")]') as varchar(max))+
'</'+XMLCol.value('local-name(/*[1])', 'varchar(100)')+'>' as xml)
from #T
Result:
<computer_book><isbn>9999999999999</isbn><pages>500</pages></computer_book>
<cooking_book><isbn>5555555555555</isbn><pages>275</pages></cooking_book>
Making the nodes parameterized
In the queries above the nodes you get as child nodes is hard coded in the query. You can use sql:varaible() to do this instead. I have not found a way of making the number of nodes dynamic but you can add as many as you think you need and have null as value for the nodes you don't need.
declare #N1 varchar(10)
declare #N2 varchar(10)
declare #N3 varchar(10)
declare #N4 varchar(10)
set #N1 = 'isbn'
set #N2 = 'pages'
set #N3 = 'backing'
set #N4 = null
select cast('<'+XMLCol.value('local-name(/*[1])', 'varchar(100)')+'>'+
cast(XMLCol.query('/*/*[local-name()=(sql:variable("#N1"),
sql:variable("#N2"),
sql:variable("#N3"),
sql:variable("#N4"))]') as varchar(max))+
'</'+XMLCol.value('local-name(/*[1])', 'varchar(100)')+'>' as xml)
from #T
Result:
<computer_book><isbn>9999999999999</isbn><pages>500</pages><backing>paperback</backing></computer_book>
<cooking_book><isbn>5555555555555</isbn><pages>275</pages><backing>paperback</backing></cooking_book>