When I run the below query:
SELECT c.FirstName
FROM HumanResources.Employee e
INNER JOIN Person.Contact c
ON c.ContactID = e.ContactID
WHERE c.FirstName = 'Rob'
FOR XML RAW ('Employee');
I get the following result:
<Employee FirstName="Rob"/>
I'm wondering is there a way that I can format it like below:
<Employee>Rob<Employee/>
Use FOR XML PATH instead of FOR XML RAW reference
SELECT c.FirstName Employee
FROM (
VALUES ('Rob'), ('Bob')
) c (FirstName)
FOR XML PATH ('');
Returns:
Result
<Employee>Rob</Employee><Employee>Bob</Employee>
Related
I need to get a list columns used in select statment, join, where and order by in query from 'show execution plan xml' in SQL Server into a table.
Eg query:
Select a.id, a.name, a.gender, a.marks, b.address
From #temp a
Inner join #temp1 b
On a.id=b.id
Where id=1
Output should be:
Select- id, name, gender, marks(from #temp)
Address(from #temp1)
Join - id
Where- id
All together into a table.
As an example of code :
DECLARE #PLAN_XML XML;
--> put here the query you wanted to examine the plan
SELECT DISTINCT name, object_id, create_date
FROM sys.objects;
SELECT #PLAN_XML = query_plan
FROM sys.dm_exec_requests
OUTER APPLY sys.dm_exec_query_plan(plan_handle)
WHERE session_id = ##SPID;
WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' )
SELECT CONCAT(x.p.value('(#Schema)', 'sysname'), N'.',
x.p.value('(#Table)', 'sysname'), N'.',
x.p.value('(#Column)', 'sysname')) AS OUTPUT_COLUMN
FROM #PLAN_XML.nodes( 'ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple[1]/QueryPlan/RelOp/OutputList/*' ) x(p)
This will give you the result :
I'm creating a report in SSRS and want to have a multiple value parameter but allow blank values (''), and display all records when blank.
The gist of it is:
SELECT *
FROM Products p
JOIN ProductCategories c on c.ProductId = p.Id
WHERE (c.Name IN (#Categories) OR #Categories = '')
Which works when blank, and works with 1 category, but errors out with 2 categories. We got around this by using a temp table, but that solution seemed sort of hacky, so I wanted to see if there was a better way to resolve this.
The temp table workaround we built was this:
CREATE TABLE #temp (ProductId INT, Category NVARCHAR(MAX))
INSERT INTO #temp
SELECT p.Id, c.Name
FROM Products p
JOIN ProductCategories c on c.ProductId = p.Id
WHERE c.Name IN (#Categories)
IF ((SELECT COUNT(*) FROM #temp) = 0)
BEGIN
INSERT INTO #temp
SELECT p.Id, c.Name
FROM Products p
JOIN ProductCategories c on c.ProductId = p.Id
WHERE c.Name LIKE '%'
END
SELECT * FROM #temp
Thanks in advance!
If you don't have a split/parse function
Example
...
Where #Categories = ''
or
C.Name in (
Select RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(#Categories,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
)
Here is a dbFiddle ... You'll notice Poultry was excluded, then try it when #Categories=''
I have a query which is fetching values from multiple tables, it looks some thing close to the below query.
I have highlighted in bold the place where i need to pass the value returned from the same query.
select E.[EmployeeName] as EmployeeName
, (select City from tblEmployeeCities where C.EmployeeID = E.EmployeeID) as EmployeeCity
, (Select State from tblStates **where City = /i need to give the name of
the city returned by the above statement** ) as EmployeeState
from tblEmployees E
Use JOIN/LEFT JOIN:
SELECT E.EmployeeName, C.City, S.State
FROM tblEmployees E
LEFT JOIN tblEmployeeCities C ON C.EmployeeID=E.EmployeeID
LEFT JOIN tblStates S ON S.City=C.City
Maybe something like
select E.[EmployeeName] as EmployeeName
, c.City as EmployeeCity
, (Select State from tblStates where City = c.City ) as EmployeeState
from tblEmployees E
inner join tblEmployeeCities C on C.EmployeeID = E.EmployeeID
I think this can be achieved with a CASE WHEN ELSE END statment in the select part of your sql statment.
Look at example here for syntax or usage: https://www.w3schools.com/sql/func_mysql_case.asp
I need output something like this
<Employee EmpID="4">
<FirstName>Rob</FirstName>
<LastName>Walters</LastName>
</Employee>
<Employee EmpID="168">
<FirstName>Rob</FirstName>
<MiddleName>T</MiddleName>
<LastName>Caron</LastName>
</Employee>
But the SQL to do this:
SELECT e.EmployeeID AS "#EmpID",
c.FirstName,
c.MiddleName, c.LastName
FROM Employee AS e
INNER JOIN Contact AS c
ON c.ContactID = e.ContactID
WHERE c.FirstName = 'Ross'
FOR XML PATH (''), ROOT ('Employees');
Return this error:
SQL Server Database Error: Row tag omission (empty row tag name) cannot be used with attribute-centric FOR XML serialization.
See the SQLFiddle:
SQLFiddle
The best way to do is using the right code:
SELECT
e.EmployeeID AS "#EmpID",
c.FirstName,
c.MiddleName, c.LastName
FROM Employee AS e
INNER JOIN Contact AS c
ON c.ContactID = e.ContactID
WHERE c.FirstName = 'Ross'
FOR XML PATH ('Employee')
;
Like the right SQLFiddle: http://www.sqlfiddle.com/#!6/3a159/8/0
I've got a very large xml data set that is structured like the following:
<root>
<person>
<personid>HH3269732</personid>
<firstname>John</firstname>
<lastname>Smith</lastname>
<entertime>01/02/2008 10:15</entertime>
<leavetime>01/02/2008 11:45</leavetime>
<entertime>03/01/2008 08:00</entertime>
<leavetime>03/01/2008 10:00</leavetime>
...
// number of enter times and leave times vary from person to person
// there may not be a final leave time (ie, they haven't left yet)
</person>
...
</root>
The structure of the data is not under my control. This data is currently residing in a single xml column in a single row in MS SQL Server 2005. I am trying to construct a query which results in the following output:
HH3269732 John Smith 01/02/2008 10:15 01/02/2008 11:45
HH3269732 John Smith 03/01/2008 08:00 01/02/2008 10:00
HH3269735 Mark Pines 02/01/2008 09:00 NULL
HH3263562 James Frank NULL NULL
HH3264237 Harold White 04/18/2008 03:00 04/18/2008 05:00
...
My query currently looks like the following:
DECLARE #xml xml
SELECT #xml = XmlCol FROM Data
SELECT
[PersonId] = Persons.PersonCollection.value('(personid)[1]', 'NVARCHAR(50)')
,[First Name] = Persons.PersonCollection.value('(firstname)[1]', 'NVARCHAR(50)')
,[Last Name] = Persons.PersonCollection.value('(lastname)[1]', 'NVARCHAR(50)')
??????
FROM #xml.nodes('root\person') Persons(PersonCollection)
That query may not be 100% right as I'm pulling it from memory, but the problem I'm having is that I don't know how to include the entertime leavetime sequence elements in such a way as to get the desired rowset that I indicated above.
Thanks.
UPDATE:
I wanted to add that a given person record may have no entertime/leavetime sequence elements at all, but still needs to be returned in the rowset. I have updated the example of the desired output to reflect this.
with cte_entertime as (
SELECT
[PersonId] = t.c.value('(../personid)[1]', 'NVARCHAR(50)')
,[First Name] = t.c.value('(../firstname)[1]', 'NVARCHAR(50)')
,[Last Name] = t.c.value('(../lastname)[1]', 'NVARCHAR(50)')
,[Entertime] = t.c.value('.', 'NVARCHAR(50)')
,[entry_number] = ROW_NUMBER() OVER (ORDER BY t.c)
FROM #x.nodes('root/person/entertime') t(c))
, cte_leavetime as (
SELECT
[Leavetime] = t.c.value('.', 'NVARCHAR(50)')
,[entry_number] = ROW_NUMBER() OVER (ORDER BY t.c)
FROM #x.nodes('root/person/leavetime') t(c))
SELECT PersonID
, [First Name]
, [Last Name]
, [Entertime]
, [Leavetime]
FROM cte_entertime e
LEFT OUTER JOIN cte_leavetime l on e.entry_number = l.entry_number
I have accepted Remus's answer as it got me 95% to the solution. For informational purposes, here is the final query structure:
with cte_maindata as (
SELECT
[PersonId] = t.c.value('(personid)[1]', 'NVARCHAR(50)')
,[First Name] = t.c.value('(firstname)[1]', 'NVARCHAR(50)')
,[Last Name] = t.c.value('(lastname)[1]', 'NVARCHAR(50)')
FROM #x.nodes('root/person') t(c))
, cte_entertime as (
SELECT
[PersonId] = t.c.value('(../personid)[1]', 'NVARCHAR(50)')
,[Entertime] = t.c.value('.', 'NVARCHAR(50)')
FROM #x.nodes('root/person/entertime') t(c))
, cte_leavetime as (
SELECT
[PersonId] = t.c.value('(../personid)[1]', 'NVARCHAR(50)')
,[Leavetime] = t.c.value('.', 'NVARCHAR(50)')
FROM #x.nodes('root/person/leavetime') t(c))
SELECT
m.PersonID
,[First Name]
,[Last Name]
,[Entertime]
,[Leavetime]
FROM cte_maindata m
LEFT OUTER JOIN cte_entertime e on m.PersonId = e.PersonId
LEFT OUTER JOIN cte_leavetime l on m.PersonId = l.PersonId
Haven't realized you may have multiple persons in the document. My query would be incorrect in that case anyway. I thought maybe if you first shred out each person into its own XML fragment and ten extract the enter/leave times might perform better. I don't have 215k person XML to try, but here is an idea:
declare #x xml;
select #x = N'<root>
<person>
<personid>HH3269732</personid>
<firstname>John</firstname>
<lastname>Smith</lastname>
<entertime>01/02/2008 10:15</entertime>
<leavetime>01/02/2008 11:45</leavetime>
<entertime>03/01/2008 08:00</entertime>
<leavetime>03/01/2008 10:00</leavetime>
<entertime>04/01/2008 08:00</entertime>
</person>
<person>
<personid>HH3269733</personid>
<firstname>Jane</firstname>
<lastname>Doe</lastname>
<entertime>01/03/2008 10:15</entertime>
<leavetime>01/03/2008 11:45</leavetime>
<entertime>03/04/2008 08:00</entertime>
<leavetime>03/04/2008 10:00</leavetime>
<entertime>04/04/2008 08:00</entertime>
</person>
</root>';
with cte_person as (
select
t.c.value('(personid)[1]', 'NVARCHAR(50)') as personid
, t.c.value('(firstname)[1]', 'NVARCHAR(50)') as firstname
, t.c.value('(lastname)[1]', 'NVARCHAR(50)') as lastname
, t.c.query('entertime') as entertime
, t.c.query('leavetime') as leavetime
FROM #x.nodes('root/person') t(c))
, cte_cross_enter as (
select
p.personid
, p.firstname
, p.lastname
, x.c.value('.', 'datetime') as entertime
, row_number() over (partition by personid order by x.c) as row_enter
from cte_person p
cross apply p.entertime.nodes('/entertime') x(c))
, cte_cross_leave as (
select
p.personid
, x.c.value('.', 'datetime') as leavetime
, row_number() over (partition by personid order by x.c) as row_leave
from cte_person p
cross apply p.leavetime.nodes('/leavetime') x(c))
select e.personid
, e.firstname
, e.lastname
, e.entertime
, l.leavetime
from cte_cross_enter e
left outer join cte_cross_leave l
on e.personid = l.personid and
e.row_enter = l.row_leave