Update a table row with XML (SQL Server) - sql-server

I have a xml file below generated using
SELECT * FROM case WHERE ticketNo=#ticketNo FOR XML RAW,
ELEMENTS
The XML looks like this:
<row>
<ticketNo>1</ticketNo>
<caller>name</caller>
<category>3</category>
<service>4</service>
<workgroup>5</workgroup>
</row>
And I update my table using this query with the same with some value changed
UPDATE case
set caller = xmldoc.caller
set category = xml.category
from OpenXml(#idoc, '/row')
with (ticketNo VARCHAR(50)'./ticketNo',
caller VARCHAR(50) './caller',
category VARCHAR(50) './category') xmldoc
where dbo.tb_itsc_case.ticketNo = xmldoc.ticketNo
Is it possible to update the table without specifying the individual column?

You can not do an update without specifying the columns and you can not get data from XML without specifying what nodes to get the data from.
If you can use the "new" XML data type that was introduced in SQL Server 2005 you can do like this instead.
declare #XML xml =
'<row>
<ticketNo>1</ticketNo>
<caller>name</caller>
<category>3</category>
<service>4</service>
<workgroup>5</workgroup>
</row>'
update [case] set
[caller] = #XML.value('(/row/caller)[1]', 'varchar(50)'),
category = #XML.value('(/row/category)[1]', 'varchar(50)')
where
ticketNo = #XML.value('(/row/ticketNo)[1]', 'varchar(50)')

I was able to use this to update 1 row in a table. It requires you to have all fields specified in the XML. It replaces the existing row with the one specified in the XML.
I wish I could figure out how to do it for only the columns that are in the XML. I work on projects where the fields in the table change frequently and it requires re-specifying all the procedures to list out the column names.
create procedure Update_TableName (#xml xml) as
DECLARE #handle INT
EXEC sp_xml_preparedocument #handle OUTPUT, #xml
DECLARE #ID varchar(255)
SELECT #ID = ID FROM OPENXML (#handle, '/data', 2) WITH TableName
if exists (select 1 from TableName where ID = #ID)
delete from TableName where ID = #ID
Insert into TableName
SELECT * FROM OPENXML (#handle, '/data', 2) WITH TableName
EXEC sp_xml_removedocument #handle
XML:
<data>
<ID>9999</ID>
<Column1>Data</Column1>
<Column2>Data</Column2>
<Column3>Data</Column3>
</data>

Related

Retrieve specific fields of the imported to SQL Server multiple XMLs

I have multiple XML files with the same structure, I have imported them to SQL Server 2017 with the following commands:
DDL:
CREATE DATABASE xmlFiles
GO
USE xmlFiles
CREATE TABLE tblXMLFiles (IntCol int, XmlData xml);
GO
DML:
USE xmlFiles
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\1.xml', SINGLE_BLOB) AS x;
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\2.xml', SINGLE_BLOB) AS x;
…
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\N.xml', SINGLE_BLOB) AS x;
Now I want to query the data:
USE xmlFiles
GO
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #XML = XmLData FROM tblXMLFiles
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT Surname , GivenNames
FROM OPENXML(#hDoc, 'article/ref-list/ref/mixed-citation')
WITH
(
Surname [varchar](100) 'string-name/surname',
GivenNames [varchar](100) 'string-name/given-names'
)
EXEC sp_xml_removedocument #hDoc
GO
The query is working, but the problem is that it returns the data only when there is only one row in a data source table — tblXMLFiles. If I add more than one row, I get empty result set.
Important:
The situation is changing if I add to the outer SELECT clause (SELECT #XML = XmLData…) the TOP statement, then it returns the queried data of the specific row number, according to the TOP value.
How can I retrieve the data not only when there is one line in the table, but many rows?
FROM OPENXML with the corresponding SPs to prepare and to remove a document is outdated and should not be used any more. Rather use the appropriate methods the XML data type provides.
Without an example of your XML it is quite difficult to offer a solution, but my magic crystal ball tells me, that it might be something like this:
SELECT f.IntCol
,mc.value('(string-name/surname)[1]','nvarchar(max)') AS Surname
,mc.value('(string-name/given-names)[1]','nvarchar(max)') AS GivenNames
FROM dbo.tblXMLFiles AS f
OUTER APPLY f.XmlData.nodes('article/ref-list/ref/mixed-citation') AS A(mc)

Openrowset bulk insert on a specific row

I am new to SQL, but am trying to learn its logic, I am assuming bulk insert will insert on all rows in this case a blob. (pdf file) below is my code but what I am trying to accomplish is, inserting a pdf file that I have put on SQL server in a row that has a matching Primary Key that I specify. So far I am missing the where clause to specify the PK
Declare #sql varchar(max)
Declare #filePath varchar(max)
Set #filePath = 'C:\iphone.pdf'
Set #sql='INSERT INTO HDData.dbo.PurchasedCellPhoneInfo(Receipt) SELECT * FROM OPENROWSET(BULK '''+ #filePath+''', SINGLE_BLOB) AS BLOB'
exec(#sql)
May I use an update t-SQL query instead of insert? and how would I drop the where to specify a specific row I want to insert this blob in?
Any help would be appreciated.
I also have tried this, following #misterPositive's suggestion for update query:
Declare #criteria varchar(50)
SET #criteria ='352014075399147'
UPDATE HDData.dbo.PurchasedCellPhoneInfo SET Receipt =
(SELECT Receipt FROM OPENROWSET (BULK 'C:\352014075399147.pdf, SINGLE_BLOB') a)
WHERE(IMEI = #criteria)
i do recieve this message:
Either a format file or one of the three options SINGLE_BLOB, SINGLE_CLOB, or SINGLE_NCLOB must be specified. i like this update query as it seems to fit what im trying to do.
You can do this to UPDATE:
UPDATE MyTable
SET blobField =
(SELECT BulkColumn FROM OPENROWSET (BULK 'C:\Test\Test1.pdf', SINGLE_BLOB) a)
WHERE (CriteriaField = #criteria)
Here is another way for PK
CREATE VIEW [dbo].[VWWorkDataLoad]
AS
SELECT RecordLine
FROM [dbo].[WorkDataLoad];
Now BULK INSERT should then look like:
BULK INSERT [dbo].[VWWorkDataLoad] FROM 'D:\NPfiles\TS082114.trn'
WITH (FIRSTROW = 2,FIELDTERMINATOR = ',' , ROWTERMINATOR = '\n');
If you want to insert new records then you could have an identity column for your PK and not have to worry about it. I have also seen functions used when a table is designed without identity on PK. Something like GetTableNamePK() in the select list.
If you want to update an existing record then you will want a where clause as you mentioned. This worked for me in testing:
Update TestBlob Set BinaryData = (SELECT * FROM OPENROWSET(BULK 'c:\temp\test.pdf', SINGLE_BLOB) AS BLOB)
Where ID = 2
If you do not want to use the Identity or Function this worked where ID is a primary key and I want to insert the BLOB with PK of 3:
INSERT INTO TestBlob2 (ID, BinaryData) SELECT 3, * FROM OPENROWSET(BULK 'c:\temp\test.pdf', SINGLE_BLOB) AS BLOB

SSIS : how to convert the source column from ID to Value

I'm creating a SSIS package to load data from a CSV file to SQL table. The sample CSV file is
EMP_ID,EMP_NAME,DEPT_ID,MANAGER_ID,SALARY
1801,SCOTT,20,1221,3000
1802,ALLEN,30,1221,3400
I need to load data into a SQL Server table, but while loading I need to load Department Name and Manager Name instead of their IDs. So I need to convert the CSV source to
1801,SCOTT,FINANCE,JOHNSON,3000
1802,ALLEN,HR,JOHNSON,3400
The values for Department Name and Manager name come from the SQL Server database only. But how do I query and convert ID to text values?
I'm new to SSIS, please suggest how can I achieve this.
Thanks
John
CREATE PROCEDURE [dbo].[BulkInsert]
(
-- Declare Parameters here for your CSV file
)
AS
BEGIN
SET NOCOUNT ON;
declare #query varchar(max)
CREATE TABLE #TEMP
(
[FieldName] [int] NOT NULL ,
[FieldName] int NOT NULL,
)
SET #query = 'BULK INSERT #TEMP FROM ''' + PathOfYourTextFile + ''' WITH ( FIELDTERMINATOR = '','',ROWTERMINATOR = ''\n'')'
--print #query
--return
execute(#query)
BEGIN TRAN;
MERGE TableName AS Target
-- Now here you can get the value Department Name and Manager Name by using Target.Id --in the table from where you mant to get the value of the Manager Name
USING (SELECT * FROM #TEMP) AS Source
ON (Target.YourTableId = Source.YourTextFileFieldId)
-- In the above line we are checking if the particular row exists in the table(Table1) then update the Table1 if not then insert the new row in Table-1.
WHEN MATCHED THEN
UPDATE SET
Target.SomeId= Source.SomeId
WHEN NOT MATCHED BY TARGET THEN
-- Insert statement
The above code is just an example for you by taking the help from this you can edit in your code. And one more important thing for you, Bulk Insert is one of the great way to save the CSV files. So try to use this..:)
In SSIS package from Data Flow tab use LOOKUP process from the Toolbox. You'll specify the table to get your string values from and which columns to use for the join and the column to substitue your IDs with.

Execute a DELETE command whilst iterating through an XML input parameter

I have a stored procedure that receives 2 parameters.
#username VARCHAR(8),
#xmlShiftDays XML
I want to delete multiple rows from the database while iterating through the XML.
I have managed to do something similar for an INSERT (see below)
INSERT INTO table(username, date)
SELECT
username = #username,
CONVERT(DATETIME,shiftDate.date.value('.','VARCHAR(10)'),103)
FROM
#xmlShiftDays.nodes('/shiftDates/date') as shiftDate(date)
This will successfully insert "x" amount of rows into my table.
I now want to re-engineer the query to DELETE "x" amount of rows. If anyone knows how or could point me in the right direction I would greatly appreciate it.
An example of what I want to achieve is:
DECLARE #username VARCHAR(8)
DECLARE #xmlShiftDays XML
SET #xmlShiftDays = '<shiftDates><date>21/01/2012</date></shiftDates>'
SET #username = 'A0123456'
DELETE FROM table
WHERE username = #username
AND date = "<b>loop through the nodes in the XML string</b>"
Assuming you're using SQL Server 2008 (or newer) for this so I can use the DATE datatype (unfortunately, you didn't specify in your question which version of SQL Server you're using).....
I would strongly recommend you use a language-independent, regional-settings-independent date format in your XML - use the ISO-8601 format of YYYYMMDD for best results.
So try something like this:
DECLARE #xmlShiftDays XML
SET #xmlShiftDays = '<shiftDates><date>20120122</date><date>20120227</date></shiftDates>'
;WITH DatesToDelete AS
(
SELECT
DeletionDate = DT.value('(.)[1]', 'date')
FROM #XmlShiftDays.nodes('/shiftDates/date') AS SD(DT)
)
SELECT * FROM DatesToDelete
This should give you the two dates combined into XML string - right?
Now, you can use this to do the deletion from your table:
DECLARE #username VARCHAR(8)
DECLARE #xmlShiftDays XML
SET #xmlShiftDays = '<shiftDates><date>20120122</date><date>20120227</date></shiftDates>'
SET #username = 'A0123456'
;WITH DatesToDelete AS
(
SELECT
DeletionDate = DT.value('(.)[1]', 'date')
FROM #XmlShiftDays.nodes('/shiftDates/date') AS SD(DT)
)
DELETE FROM dbo.Table
WHERE username = #username
AND date IN (SELECT DeletionDate FROM DatesToDelete)
Does that work for you?
You can select the date from the Xml in the same way you did for the Insert:
DELETE FROM table
WHERE username = #username
AND date IN (SELECT
CONVERT(DATETIME,shiftDate.date.value('.','VARCHAR(10)'),103)
FROM
#xmlShiftDays.nodes('/shiftDates/date') as shiftDate(date))

sql server 2005 xquery read xml type

I have declared a #xmldata as xml. How to read it? I tried
declare #xmldata as xml
set #xmldata = <root><row ename='abc' eid='1'/></root>
SELECT #XMLDATA
but it returned an error. I want to fetch eid column from the above xml type.
Try this:
declare #xmldata as xml
set #xmldata = '<root><row ename="abc" eid="1"/></root>'
SELECT
#xmldata.value('(/root/row/#eid)[1]', 'int') AS 'EID'
Update: if you need to select from your table and extract something from the XML column, use this approach:
SELECT
tbl.ID,
tbl.XmlColumn.value('(/root/row/#ename)[1]', 'varchar(25)') AS 'EName'
FROM
dbo.YourTable tbl
WHERE
(...some condition here...)

Resources