SQL Server 2012: Select xml with repeated and ungrouped set of elements - sql-server

For the XML below:
<Document>
<ID>01</ID>
<RaitingDate>2006-05-04T18:13:51.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner1</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:52.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner2</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:53.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner3</MinimumRatingPartner>
</Document>
I would like to generate the following table:
RatingDate MRP
----------------------- ---------------------
2006-05-04 18:13:51.000 MinimumRatingPartner1
2006-05-04 18:13:52.000 MinimumRatingPartner2
2006-05-04 18:13:53.000 MinimumRatingPartner3
Now I am getting:
RatingDate MRP
----------------------- ---------------------
2006-05-04 18:13:51.000 MinimumRatingPartner1
2006-05-04 18:13:52.000 MinimumRatingPartner1
2006-05-04 18:13:53.000 MinimumRatingPartner1
2006-05-04 18:13:51.000 MinimumRatingPartner2
2006-05-04 18:13:52.000 MinimumRatingPartner2
2006-05-04 18:13:53.000 MinimumRatingPartner2
2006-05-04 18:13:51.000 MinimumRatingPartner3
2006-05-04 18:13:52.000 MinimumRatingPartner3
2006-05-04 18:13:53.000 MinimumRatingPartner3
Using this query:
DECLARE #XML XML =
'<Document>
<ID>01</ID>
<RaitingDate>2006-05-04T18:13:51.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner1</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:52.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner2</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:53.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner3</MinimumRatingPartner>
</Document>'
SELECT
RatingDate = s.value('text()[1]', 'datetime')
,MRP =r.value('text()[1]', 'nvarchar(50)')
FROM
#XML.nodes('Document') as D(V)
cross apply
D.V.nodes('./RaitingDate') as Q(S)
cross apply
D.V.nodes('./MinimumRatingPartner') as M(R)
order by MRP, RatingDate
I have tried couple other queries, but without success.
Please note: XML structure cannot be changed.

Your XML appears to depend on ordered pairs (first partner goes with first date, second partner goes with second date etc etc). Not only that, but both columns are listed within the same parent node. So you'll have to do something like this. Lucky for you xml is order sensitive.
DECLARE #XML XML =
'<Document>
<ID>01</ID>
<RaitingDate>2006-05-04T18:13:51.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner1</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:52.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner2</MinimumRatingPartner>
<RaitingDate>2006-05-04T18:13:53.0Z</RaitingDate>
<MinimumRatingPartner>MinimumRatingPartner3</MinimumRatingPartner>
</Document>'
SELECT MinimumRatingPartner, RatingDate FROM
(SELECT
D.V.value('text()[1]', 'datetime') AS RatingDate,
ROW_NUMBER() over (order by ##rowcount) AS RowNum
FROM #XML.nodes('Document/RaitingDate') as D(V)) Dates
INNER JOIN
(SELECT
D.V.value('text()[1]', 'nvarchar(50)') AS MinimumRatingPartner,
ROW_NUMBER() over (order by ##rowcount) AS RowNum
FROM #XML.nodes('Document/MinimumRatingPartner') as D(V)) Partners
ON Dates.RowNum = Partners.RowNum

Probably not the best solution, but works for the given xml
SELECT RaitingDate,MinimumRatingPartner
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY RaitingDate) AS Num
,RaitingDate
FROM
(
SELECT
Node.Data.value('(.)[1]','DATETIME') as RaitingDate
FROM #XML.nodes('/Document/RaitingDate') Node(Data)
) AS A
) AS DateTable
JOIN
(
SELECT ROW_NUMBER() OVER(ORDER BY MinimumRatingPartner) AS Num
,MinimumRatingPartner
FROM
(
SELECT
Node.Data.value('(.)[1]','VARCHAR(50)') as MinimumRatingPartner
FROM #XML.nodes('/Document/MinimumRatingPartner') Node(Data)
) AS B
) AS PartnerTable
ON DateTable.Num=PartnerTable.Num

Related

Display of online users on the system

I don't know exactly where I'm wrong, but I need a list of all the workers who are currently at work (for the current day), this is my sql query:
SELECT
zp.ID,
zp.USER_ID,
zp.Arrive,
zp.Deppart,
zp.DATUM
FROM time_recording as zp
INNER JOIN personal AS a on zp.USER_ID, = zp.USER_ID,
WHERE zp.Arrive IS NOT NULL
AND zp.Deppart IS NULL
AND zp.DATUM = convert(date, getdate())
ORDER BY zp.ID DESC
this is what the data looks like with my query:
For me the question is, how can I correct my query so that I only get the last Arrive time for the current day for each user?
In this case to get only these values:
Try this below script using ROW_NUMBER as below-
SELECT * FROM
(
SELECT zp.ID, zp.USER_ID, zp.Arrive, zp.Deppart, zp.DATUM,
ROW_NMBER() OVER(PARTITION BY zp.User_id ORDER BY zp.Arrive DESC) RN
FROM time_recording as zp
INNER JOIN personal AS a
on zp.USER_ID = zp.USER_ID
-- You need to adjust above join relation as both goes to same table
-- In addition, as you are selecting nothing from table personal, you can drop the total JOIN part
WHERE zp.Arrive IS NOT NULL
AND zp.Deppart IS NULL
AND zp.DATUM = convert(date, getdate())
)A
WHERE RN =1
you can try this:
SELECT DISTINCT
USER_ID,
LAR.LastArrive
FROM time_recording as tr
CROSS APPLY (
SELECT
MAX(Arrive) as LastArrive
FROM time_recording as ta
WHERE
tr.USER_ID = ta.USER_ID AND
ta.Arrive IS NOT NULL
) as LAR

Select with group by and max date

this probably is a duplicate question but I can't seem to figure out how to implement the previous suggestions.
my data looks like this for what matters:
drawing method Location thk_date
314C0010 UT 05.01 2016-05-24
314C0010 UT 05.01 2011-10-26
314C0010 UT 06.01 2016-05-24
314C0010 UT 07.01 2016-05-24
When my select executes for location 05.01 I only want the row with the latest thk_Date
Here is my statement which just gets all the records.
SELECT Distinct
t.[Id]
,t.[SurveyNumber]
,t.[TPLATFORM]
,t.[DRAWING]
,r.[Desc]
,t.[METHOD]
,t.[LOCATION]
,t.[THK_DATE]
,t.[THICK]
,t.[MEAS_THK]
,t.[COMMENTS]
,t.[EXCLUDE]
,t.[PAINT]
,t.[CF1]
,t.[CF2]
,t.[CF3]
,t.[NF1]
,t.[NF2]
,t.[Year]
,t.[Completed]
,t.Created
,t.CreatedBy
,t.ModifiedBy
,t.Modified
,YEAR(THK_DATE)
,t.Inservice
FROM Thk t
left JOIN ref r ON r.[DRAWING] = t.[DRAWING]
left JOIN eng e ON e.[DRAWING] = t.[DRAWING]
WHERE t.SurveyNumber = #SurveyNumber
AND t.[Year] = #Year
ORDER BY t.DRAWING, t.Method, t.[LOCATION], THK_DATE desc
How do I get only the rows with the max(thk_date)? I have tried to group and select top 1 but only get one record.
You can use ROW_NUMBER() for this.
Since you haven't given other tables' structure, here is an example.
declare #Drawings as
Table(drawing varchar(100),
method varchar(2),
Location varchar(10),
thk_date DateTime)
INSERT INTO #Drawings
VALUES
('314C0010', 'UT','05.01','2016-05-24'),
('314C0010', 'UT','05.01','2011-10-26'),
('314C0010', 'UT','06.01','2016-05-24'),
('314C0010', 'UT','07.01','2016-05-24')
;WITH CTE AS
(
select row_number() over(partition by Location order by thk_date desc) as rn,*
from #Drawings
)
select * from CTE where rn=1
Fiddle here

SSRS:How to return count of events per day for Month

I have a table with the following information
ID,DateTime,EventType
1,6/5/2013 9:35:00,B
1,6/5/2013 9:35:24,A
2,6/5/2013 9:35:36,B
3,6/5/2013 9:36:11,D
2,6/5/2013 9:39:16,A
3,6/5/2013 9:40:48,B
4,7/5/2013 9:35:19,B
4,7/5/2013 9:35:33,A
5,7/5/2013 9:35:53,B
5,7/5/2013 9:36:06,D
6,7/5/2013 9:39:39,A
7,7/5/2013 9:40:28,B
8,8/5/2013 9:35:02,A
7,8/5/2013 9:35:08,A
8,8/5/2013 9:35:29,B
6,8/5/2013 9:36:39,B
I need to count how many times each day an event changed state as long as the time between states was less than 30 seconds over the time period.
Basically I am looking for the following result set
6/5/2013 | 1
7/5/2013 | 2
8/5/2013 | 1
I've tried several different types of queries, but nothing works. I am using SQL Server Reporting Services 2008.
declare #t table (ID int,[DateTime] datetime ,EventType varchar);
insert #t values
(1,'6/5/2013 9:35:00','B'),
(1,'6/5/2013 9:35:24','A'),
(2,'6/5/2013 9:35:36','B'),
(3,'6/5/2013 9:36:11','D'),
(2,'6/5/2013 9:39:16','A'),
(3,'6/5/2013 9:40:48','B'),
(4,'7/5/2013 9:35:19','B'),
(4,'7/5/2013 9:35:33','A'),
(5,'7/5/2013 9:35:53','B'),
(5,'7/5/2013 9:36:06','D'),
(6,'7/5/2013 9:39:39','A'),
(7,'7/5/2013 9:40:28','B'),
(8,'8/5/2013 9:35:02','A'),
(7,'8/5/2013 9:35:08','A'),
(8,'8/5/2013 9:35:29','B'),
(6,'8/5/2013 9:36:39','B');
--select * from #t order by ID, DateTime;
with cte as (
select *, cast([DateTime] as date) the_date, row_number() over (partition by ID order by DateTime) row_num
from #t
)
select c1.the_date, count(1)
from cte c1
join cte c2
on c2.ID = c1.ID
and c2.row_num = c1.row_num + 1
where datediff(S,c1.DateTime, c2.DateTime) < 30
group by c1.the_date
order by c1.the_date;
Try this:
select CONVERT(VARCHAR(10), a.DateTime, 103) [Date], count(a.ID) Count from Table a
inner join Table b on a.ID = b.ID
where DATEDIFF(second,a.DateTime,b.DateTime) between 1 and 29 and a.ID = b.ID
and Cast(a.DateTime as Date) = Cast(b.DateTime as date)
group by CONVERT(VARCHAR(10), a.DateTime, 103)

sql tvp vs xml speed in stored procedure are the same??? Is my testing or logic flawed?

I'm an accidental DBA charged with speeding up all our sql servers. I've got a highly used query with a horrible average worker time. I noticed it uses XML to pass data to a stored procedure. Query plan tells me it spends most of its time converting XML. Everything I've read says XML is about 33% slower than TVP. I rewrote the SP using TVP and compared times using the method:
SELECT #StartTime=GETDATE()
exec GetTVPData3 #tvp --or XML method
SELECT #EndTime=GETDATE()
SELECT DATEDIFF(ms,#StartTime,#EndTime) AS [Duration in millisecs]
After many runs and averaging out the times.... TVP vs XML has XML winning by 5ms. ????? (550ms vs 545ms) Is my testing or logic flawed?
Both XML and TVP are populated before I get StartTime. I've run this on 2 different SQL test servers with similar results.
The particular code is used in a cross apply. The only difference in the SPs are:
**TVP**
CROSS APPLY (SELECT id AS ProductID, sortorder AS SortOrder FROM #Insert_tvp) Items
**XML**
CROSS APPLY (
SELECT f.id.value('#id', 'int') AS ProductID, f.id.value('#sortorder', 'int') AS SortOrder
FROM #ProductIDs.nodes('list/p')
AS f(id)
) Items
Everything in my head tells me we need to switch to using TVP and get rid of XML. But I can't convince coders without better results.
EDIT: Adding the whole XML SP:
ALTER PROCEDURE [dbo].[ExtendedDataXML]
#HostedSiteID INT,
#ProductIDs XML = NULL,
#ImageType VARCHAR(20) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT
Products.ID AS ItemID,
0 AS ItemType,
Products.SKU,
Products.Title,
HSP.Slug,
Products.Rank,
Products.Rank AS SalesRank,
Products.Status,
Products.LaunchDate,
Products.IsOnline,
Products.IsAutoOffline,
Products.IsSalableOnline,
Products.IsMarketableOnline,
Products.LeadIn, Products.LeadOut,
COALESCE(Products.CaseQuantity, 1) AS CaseQuantity,
COALESCE(Products.MinimumOrderQuantity, 1) AS MinimumOrderQuantity,
Products.QuantityOnHand,
Image.Filename, Image.Width, Image.Height, Image.Alt, Image.Title,
Pricing.Price, Pricing.SalePrice,
Products.TruckShipment,
HSP.NDescription
FROM Products
JOIN HostedSites_Products HSP ON Products.ID = HSP.ProductID
CROSS APPLY (
SELECT f.id.value('#id', 'int') AS ProductID, f.id.value('#sortorder', 'int') AS SortOrder
FROM #ProductIDs.nodes('list/p')
AS f(id)
) Items
OUTER APPLY (
SELECT TOP(1) Filename, Width, Height, Alt, Title
FROM Items_Images
JOIN Images ON Items_Images.ImageID = Images.ID
WHERE Items_Images.ItemID = Products.ID
AND Items_Images.ItemType = 0
AND Images.Type = COALESCE(#ImageType, '.4b')
) Image
OUTER APPLY (
SELECT TOP(1) Price, SalePrice, CurrentPrice
FROM ProductPrices
WHERE ProductPrices.ProductID = Products.ID
ORDER BY LoRange ASC
) Pricing
WHERE Products.ID = Items.ProductID
AND HSP.HostedSiteID = #HostedSiteID
AND HSP.Validated = 1
AND Products.IsMarketableOnline = 1
ORDER BY Items.SortOrder
END
CROSS APPLY means row wise execution! You are parsing your XML over and over...
Your ID-List is - as far as I understand - meant as a filter
Besides the fact, that this was much better done within an inlined TVF (syntax without BEGIN...END you might try this like this:
ALTER PROCEDURE [dbo].[ExtendedDataXML]
#HostedSiteID INT,
#ProductIDs XML = NULL,
#ImageType VARCHAR(20) = NULL
AS
BEGIN
SET NOCOUNT ON;
WITH IDList AS
(
SELECT f.id.value('#id', 'int') AS ProductID, f.id.value('#sortorder', 'int') AS SortOrder
FROM #ProductIDs.nodes('list/p') AS f(id)
)
SELECT
Products.ID AS ItemID,
0 AS ItemType,
Products.SKU,
Products.Title,
HSP.Slug,
Products.Rank,
Products.Rank AS SalesRank,
Products.Status,
Products.LaunchDate,
Products.IsOnline,
Products.IsAutoOffline,
Products.IsSalableOnline,
Products.IsMarketableOnline,
Products.LeadIn, Products.LeadOut,
COALESCE(Products.CaseQuantity, 1) AS CaseQuantity,
COALESCE(Products.MinimumOrderQuantity, 1) AS MinimumOrderQuantity,
Products.QuantityOnHand,
Image.Filename, Image.Width, Image.Height, Image.Alt, Image.Title,
Pricing.Price, Pricing.SalePrice,
Products.TruckShipment,
HSP.NDescription
FROM Products
JOIN HostedSites_Products HSP ON HSP.HostedSiteID = #HostedSiteID AND HSP.Validated = 1 AND Products.ID = HSP.ProductID
INNER JOIN IDList AS Items ON Items.ProductID=Products.ProductID
OUTER APPLY (
SELECT TOP(1) Filename, Width, Height, Alt, Title
FROM Items_Images
JOIN Images ON Items_Images.ImageID = Images.ID
WHERE Items_Images.ItemID = Products.ID
AND Items_Images.ItemType = 0
AND Images.Type = COALESCE(#ImageType, '.4b')
) Image
OUTER APPLY (
SELECT TOP(1) Price, SalePrice, CurrentPrice
FROM ProductPrices
WHERE ProductPrices.ProductID = Products.ID
ORDER BY LoRange ASC
) Pricing
WHERE Products.IsMarketableOnline = 1
ORDER BY Items.SortOrder
END

Sql server XML methods are not allowed in a GROUP BY clause

i just issue a group by where i specify xml data then i got error XML methods are not allowed in a GROUP BY clause.
here is my sql
SELECT HourSheetID,(MAX(RowID)+1) as "RowID",
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') as UpdatedBy,
XMLData.value('(Log/Options)[1]','varchar(max)') as Options,
logdate
FROM dbo.EditedHourSheetLog
GROUP BY HourSheetID,
XMLData.value('(Log/EntryDate)[1]','datetime'),
XMLData.value('(Log/SpecialistID)[1]','int'),
XMLData.value('(Log/HoursData)[1]','decimal(18,2)'),
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)'),
XMLData.value('(Log/Options)[1]','varchar(max)'),
logdate
if i can not specify xml data in group by cluase then what other option is available....please guide. thanks
This way i achieve my task
ALTER PROC sp_HourSheetLog
(
#StartDate VARCHAR(8),
#EndDate VARCHAR(8)
)
AS
SELECT B.ID
,A.RowID
,B.EntryDate
,B.Name
,B.HoursData
,B.UpdatedBy
,Options=(CASE B.Options
WHEN 'rdLeave' THEN 'Leave'
WHEN 'rdsick' THEN 'Sick'
WHEN 'rdSalvage' THEN 'Salvage'
WHEN 'rdCSRDuty' THEN 'CSR Duty'
WHEN 'rdShippingSales' THEN 'Shipping and Sales'
WHEN 'rdEOL' THEN 'EOL'
WHEN 'rdTraining' THEN 'Training'
WHEN 'rdOther' THEN 'Other'
END)
,B.ModDate
FROM (
(
SELECT HourSheetID,(MAX(RowID)+1) as "RowID"
FROM EditedHourSheetLog l,EditedHourSheet h
GROUP BY HourSheetID
) A
JOIN
(
SELECT h.ID
,s.Name
,h.EntryDate
,h.HoursData
,h.Options
,h.UpdatedBy
,h.ModDate from EditedHourSheet h
LEFT JOIN Specialists s
ON h.SpecialistID=s.SpecialistID
) B
ON A.HourSheetID=B.ID
)
WHERE Convert(Varchar,ModDate,112)>=#StartDate AND
Convert(Varchar,ModDate,112)<=#EndDate
UNION
(
Select HourSheetID as ID,RowID,
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
--XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
s.Name,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
CAST(XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') AS VARCHAR(MAX)) UpdatedBy,
Options=(CASE XMLData.value('(Log/Options)[1]','varchar(max)')
WHEN 'rdLeave' THEN 'Leave'
WHEN 'rdsick' THEN 'Sick'
WHEN 'rdSalvage' THEN 'Salvage'
WHEN 'rdCSRDuty' THEN 'CSR Duty'
WHEN 'rdShippingSales' THEN 'Shipping and Sales'
WHEN 'rdEOL' THEN 'EOL'
WHEN 'rdTraining' THEN 'Training'
WHEN 'rdOther' THEN 'Other'
END),
LogDate as ModDate
FROM EditedHourSheetLog h
LEFT JOIN Specialists s
ON h.XMLData.value('(Log/SpecialistID)[1]','int')=s.SpecialistID
WHERE Convert(Varchar,LogDate,112)>=#StartDate AND
Convert(Varchar,LogDate,112)<=#EndDate
)
ORDER BY ID,RowID DESC
--sp_HourSheetLog '20140101','20140326'
You can use a derived table and do the group by in the main query.
SELECT T.HourSheetID,
MAX(T.RowID)+1 as RowID,
T.EntryDate,
T.SpecialistID,
T.HoursData,
T.UpdatedBy,
T.Options,
T.logdate
FROM (
SELECT HourSheetID,
RowID,
XMLData.value('(Log/EntryDate)[1]','datetime') as EntryDate,
XMLData.value('(Log/SpecialistID)[1]','int') as SpecialistID,
XMLData.value('(Log/HoursData)[1]','decimal(18,2)') as HoursData,
XMLData.value('(Log/UpdatedBy)[1]','varchar(max)') as UpdatedBy,
XMLData.value('(Log/Options)[1]','varchar(max)') as Options,
logdate
FROM dbo.EditedHourSheetLog
) AS T
GROUP BY T.HourSheetID,
T.EntryDate,
T.SpecialistID,
T.HoursData,
T.UpdatedBy,
T.Options,
T.logdate

Resources