Good Day
I have a query that views and sorts the contents of my SQL. It's easy if you know what the xml file is but I am trying to create the xml file as a parameter because it's not always the same. How can I add the parameter to the path? I did try but it says it's incorrect.
This is the code in a view that works:
select
c3.value('#CtlgID','nvarchar(50)') AS 'ID',
c4.value('#label','nvarchar(50)') AS 'ID',
c5.value('#label','nvarchar(50)') AS 'ID'
from
(
select
cast(c1 as xml)
from
OPENROWSET (BULK 'C:\ISP\bin\EN\XML\Cataloghi\menuCat_756.xml',SINGLE_BLOB) as T1(c1)
)as T2(c2)
cross apply c2.nodes('/node') T3(c3)
cross apply c2.nodes('/node/node') T4(c4)
cross apply c2.nodes('/node/node/node') T5(c5)
I am trying to add this to a stored procedure:
PROCEDURE [dbo].[Update_ISP_Child]
-- Add the parameters for the stored procedure here
#p1 nvarchar(50) = 'menuCat_756.xml'
AS
BEGIN
select
c3.value('#CtlgID','nvarchar(50)') AS 'ID',
c4.value('#label','nvarchar(50)') AS 'ID',
c5.value('#label','nvarchar(50)') AS 'ID'
from
(
select
cast(c1 as xml)
from
OPENROWSET (BULK 'C:\ISP\bin\EN\XML\Cataloghi\' + #p1,SINGLE_BLOB) as T1(c1)
)as T2(c2)
cross apply c2.nodes('/node') T3(c3)
cross apply c2.nodes('/node/node') T4(c4)
cross apply c2.nodes('/node/node/node') T5(c5)
END
When I add my parameter as #p1 it doesn't work.
Thanks.
Ruan
You have to build the whole statement dynamically:
--the file's name
DECLARE #filename VARCHAR(250)='menuCat_756.xml';
--a tolerant staging table to help us get the result of EXEC
DECLARE #staging TABLE(TheXml NVARCHAR(MAX));
--a dynamically created command
DECLARE #cmd NVARCHAR(MAX)=
N'select c1
from OPENROWSET (BULK ''C:\ISP\bin\EN\XML\Cataloghi\' + #filename + ''',SINGLE_CLOB) as T1(c1)';
--This will shift the "result set" (which is one single XML) into our staging table
INSERT INTO #staging
EXEC(#cmd);
--Test it
SELECT * FROM #staging
Hint 1: I changed SINLGE_BLOB to SINLGE_CLOB
Hint 2: You must cast the result to XML before you use it as XML.
It is good practice to do casts after the import to avoid errors hardly to find...
Related
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)
So, I'm trying to create a XML file from a SQL table. I do know of the route of using...
Select * From dbo.[db_name]
FOR XML PATH
But the issue at hand is that the XML styling/formatting is quite odd...
<ID>170607A13</ID>
<MaterialActual>
<MaterialLotID>170607A13</MaterialLotID>
<MaterialActualProperty>
<ID>CreationDate</ID>
<Value>
<ValueString>2017-06-07T12:26:27.667-05:00</ValueString>
</Value>
</MaterialActualProperty>
Therefore, I decided I could go the route of concatenating it and inserting into the XML file. Like so...
DECLARE #NAME varchar(50)
DECLARE #LOCATION varchar(50)
DECLARE #SearchXML xml
SET #SearchXML = '<Root>
<CallerInformation>
<LastName>' + #LOCATION + '</LastName>
<FirstName>' + #NAME + '</FirstName>
</CallerInformation>
</Root>'
SELECT #SearchXML
But when doing this I get returned...
If I could get pointed in the right direction or even a example that would be great!
But the issue at hand is that the XML styling/formatting is quite odd...
What is odd there? The only thing odd I can see is the attempt to solve this on string level...
Your question is missing sample data and expected output. The simple select you provide tells us nothing, the XML you provide is an inclompete fragment and the actual example is something completely different...
Just some hints:
Do not concatenate XML on string level!
please read How to ask a good SQL question
and How to create a MCVE
Your simple example should be done like this:
DECLARE #NAME varchar(50)
DECLARE #LOCATION varchar(50)
DECLARE #SearchXML xml
SET #SearchXML =
(
SELECT #LOCATION AS LastName
,#NAME AS FirstName
FOR XML PATH('CallerInformation'),ROOT('Root'),TYPE
);
SELECT #SearchXML;
This will lead to an almost empty (but valid!) XML, put any value into the variables and you will see the XML filled.
UPDATE: Your odd XML...
Try something like this:
SET #xml=
(
SELECT '170607A13' AS ID
,'170607A13' AS [MaterialActual/MaterialLot]
,'CreationDate' AS [MaterialActual/MaterialActualProperty/ID]
,GETDATE() AS [MaterialActual/MaterialActualProperty/Value/ValueString]
FOR XML PATH('')
);
SELECT #xml
UPDATE 2: Very long XPath...
This is your error: name-length more then 128
DECLARE #xml XML;
--SET #xml=
--(
-- SELECT '170607A13' AS ID
-- ,'170607A13' AS [MaterialActual1234567890/MaterialLot1234567890]
-- ,'CreationDate' AS [MaterialActual1234567890/SomeMore1234567890/EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ID1234567890]
-- ,GETDATE() AS [MaterialActual1234567890/SomeMore1234567890/EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ValueString1234567890]
-- FOR XML PATH('')
--);
--SELECT #xml
--This is a solution: nested sub-select:
SET #xml=
(
SELECT '170607A13' AS ID
,'170607A13' AS [MaterialActual1234567890/MaterialLot1234567890]
,(
SELECT
'CreationDate' AS [EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ID1234567890]
,GETDATE() AS [EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ValueString1234567890]
FOR XML PATH('SomeMore1234567890'),TYPE
) AS [MaterialActual1234567890]
FOR XML PATH('')
);
SELECT #xml;
UPDATE 3: Your follow-up question in comment
HINT: Avoid follow-up questions. Next time please add a new question!
Both return the result requested:
SELECT 'yyyy-MM-dd''T''HH:mm:ss.SSSXXX' AS [PublishedDate/#format]
,GETDATE() AS PublishedDate
FOR XML PATH('')
SELECT 'yyyy-MM-dd''T''HH:mm:ss.SSSXXX' AS [#format]
,GETDATE() AS [*]
FOR XML PATH('PublishedDate');
In my eyes there's no need for the format. Within XML a datetime should be in this format (which is ISO8601) anyway. This is the standard format...
CREATE TABLE #T(I IMAGE)
INSERT INTO #T
VALUES(CAST(N'CREATE PROCEDURE SP1
#I IMAGE
AS
BEGIN
SELECT ''下些''
END' AS VARBINARY(MAX)))
DECLARE #s NVARCHAR(MAX)
SET #S = (SELECT TOP 1 CAST(CAST(I AS varbinary(MAX)) AS NVARCHAR(MAX))
FROM #T)
EXEC (#S)
DROP TABLE #T
I want to put stored procedure's SQL statements into an image column, then I want to get the text and execute them in database.
Is conversion and execution correct? That is, is there any thing I am missing?
Should I use sp_execute instead of EXEC? I noticed I do not have any params.
We are planning to change image type but for now, this is the option.
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
I need to write a query engine on a web app, what needs to be accomplish is that a user can enter any SELECT statement into a textbox and then the results should be created into a new table.
This is my function I have created but it only support SQL Server 2012 and I want similar to this function but only it should support SQL Server 2005 and above:
CREATE FUNCTION [dbo].[CustomQueryTableCreation]
(
#TableName varchar(max),
#sql NVARCHAR(MAX)
)
RETURNS
#TableBuilder TABLE
(
DS varchar(max)
)
BEGIN
INSERT INTO #TableBuilder
SELECT 'CREATE TABLE dbo.' + #TableName+'(';
INSERT INTO #TableBuilder
SELECT
CASE column_ordinal
WHEN 1 THEN '' ELSE ',' END
+ name + ' ' + system_type_name + CASE is_nullable
WHEN 0 THEN ' not null' ELSE '' END
FROM
sys.dm_exec_describe_first_result_set
(
#sql, NULL, 0
) AS f
ORDER BY
column_ordinal;
INSERT INTO #TableBuilder
SELECT ');';
RETURN
END
What I want to do now is that I want to search through my query and replace the FIRST FROM with INTO NewTable FROM.
The query can contain multiple joins.
Should I control this with SQL or C#?
I had a similar problem with the 2005 Environment. If you save the Select query to a table, and use the following built in procedure to execute the query:
EXECUTE sp_executesql #Query
Here is the MS docs:
http://msdn.microsoft.com/en-us/library/ms188001%28v=sql.90%29.aspx
Edit
Keeping this in mind, can take the SQL dumps and Create OpenRowset Queries to take the SQL and dump them into a TempTable, and from the Temp Table to a permanent table if required.
I created the following SP's to assist with getting the info to a permanent table.
First the procedure to execute the specific SQL Statement
CREATE PROCEDURE [dbo].[spExecuteRowset]
(
#Query NVARCHAR(MAX)
)
AS
BEGIN
--Execute SQL Statement
EXECUTE sp_executesql #Query
END
Then the OpenRowset SP:
CREATE PROCEDURE [dbo].[spCustomquery]
(
#ProQuery NVARCHAR(MAX),
#Tablename NVARCHAR(MAX)
)
AS
BEGIN
--Insert the info into a Specidied Table
DECLARE #Query NVARCHAR(max)
SET #Query = 'SELECT * INTO #MyTempTable FROM OPENROWSET(''SQLNCLI'', ''Server=localhost;Trusted_Connection=yes;'','' EXEC [YOUR DATABASE].dbo.spExecuteRowset' +''''+#ProQuery+''''') SELECT * INTO '+ #Tablename +' FROM #MyTempTable'
--FOR DEBUG ONLY!!!!
PRINT #Query
EXEC [YourDatabase].dbo.spExecuteRowset #Query
END
This takes it from the #tempTable to A Physical Table.
Here are some docs on OpenRowset.
You have no guarantee that the first from in a query will accept an into, because you can have a subselect in the select statement. In addition, you could have a field name like datefrom that throws things off too.
But, assuming you have "simple" SQL statements, you can do it as:
select stuff(#query, charindex('from ', #query), 0, 'into '+#Table+' ')
from t;
EDIT:
The following is what you really want to do:
select *
into #Table
from (#query) q;
Using the subquery solves the problem.
This is a well-known problem. String concatenation is usually a bad/limited solution.
The more recommended solution is to let some other mechanism to return you the result set (openquery etc.), and then insert it to a table.
For example:
SELECT *
INTO YourTable
FROM OPENQUERY([LinkedServer],your query...)