i have this following code:
;with cte as (
Select RegardingObjectId ,
DATEADD(mi, DATEDIFF(mi, getutcdate(), getdate()),CreatedON) as [Time First Response]
from dbo.Email
where DirectionCode = '1'
)
SELECT dbo.Incident.new_CaseID as [CASE ID],
cte.RegardingObjectId,
dbo.Incident.IncidentId,
dbo.Incident.Title as [SUBJECT],
dbo.Incident.StatusCode as [STATUS],
cte.[Time First Response]
from dbo.Incident
left Join cte on cte.RegardingObjectId = dbo.Incident.IncidentId
order by dbo.Incident.new_CaseID desc
this query will return a result like :
As you can see, the query returning multiple records with same CASE ID. What i want is, for every multiple records have same CASE ID, only one with oldest [Time First Response] is retrieved
You can wrap your query in another CTE and use ROW_NUMBER to prioritize and get the oldest record per [CASE ID]:
;with cte as (
Select RegardingObjectId ,
DATEADD(mi, DATEDIFF(mi, getutcdate(), getdate()),CreatedON)
as [Time First Response]
from dbo.Email
where DirectionCode = '1'
), cte2 as (
SELECT dbo.Incident.new_CaseID as [CASE ID],
cte.RegardingObjectId,
dbo.Incident.IncidentId,
dbo.Incident.Title as [SUBJECT],
dbo.Incident.StatusCode as [STATUS],
cte.[Time First Response],
ROW_NUMBER() OVER (PARTITION BY dbo.Incident.new_CaseID
ORDER BY cte.[Time First Response]) AS rn
from dbo.Incident
left Join cte on cte.RegardingObjectId = dbo.Incident.IncidentId
)
SELECT [CASE ID],
RegardingObjectId,
IncidentId,
[SUBJECT],
[STATUS],
[Time First Response]
FROM cte2
WHERE rn = 1
ORDER BY [CASE ID] desc
You can try using the MIN function
;with cte as (
Select RegardingObjectId ,
DATEADD(mi, DATEDIFF(mi, getutcdate(), getdate()),CreatedON) as [Time First Response]
from dbo.Email
where DirectionCode = '1'
)
SELECT dbo.Incident.new_CaseID as [CASE ID],
cte.RegardingObjectId,
dbo.Incident.IncidentId,
dbo.Incident.Title as [SUBJECT],
dbo.Incident.StatusCode as [STATUS],
cte.[Time First Response]
from dbo.Incident
left Join cte on cte.RegardingObjectId = dbo.Incident.IncidentId
AND cte.[Time First Response] IN (SELECT MIN(cte.[Time First Response])
FROM cte WHERE cte.RegardingObjectId = dbo.Incident.IncidentId)
order by dbo.Incident.new_CaseID desc
Related
Can someone please help me to find the average time between first and second purchase on a product level.
This is what I have written -
Select A.CustomerId,A.ProductId , A.OrderSequence, (Case WHEN OrderSequence = 1 THEN OrderDate END) AS First_Order_Date,
MAX(Case WHEN OrderSequence = 2 THEN OrderDate END) AS Second_Order_Date
From
(
Select t.CustomerId, t.ProductId, t.OrderDate,
Dense_RANK() OVER (PARTITION BY t.CustomerId, t.ProductId ORDER BY OrderDate Asc) as OrderSequence
From Transactions t (NOLOCK)
Where t.SiteKey = 01
Group by t.CustomerId, t.ProductId, t.OrderDate)
A
Where A.OrderSequence IN (1,2)
Group By A.Customer_Id, A.ProductId, A.OrderSequence, A.OrderDate
Sample Data:
It looks like row-numbering and LEAD should do the trick for you here.
Don't use NOLOCK unless you really know what you're doing
It's unclear if you want the results to be partitioned by CustomerId also. If not, you can remove it everywhere in the query
SELECT
A.CustomerId,
A.ProductId,
AVG(DATEDIFF(day, OrderDate, NextOrderDate))
FROM
(
SELECT
t.CustomerId,
t.ProductId,
t.OrderDate,
ROW_NUMBER() OVER (PARTITION BY t.CustomerId, t.ProductId ORDER BY OrderDate) AS rn,
LEAD(OrderDate) OVER (PARTITION BY t.CustomerId, t.ProductId ORDER BY OrderDate) AS NextOrderDate
FROM Transactions t
WHERE t.SiteKey = '01'
) t
WHERE t.rn = 1
GROUP BY
t.Customer_Id,
t.ProductId;
;with cte as (
select Domain_Id, Starting_Date, End_Date
from Que_Date
union all
select t.Domain_Id, cte.Starting_Date, t.End_Date
from cte
join Que_Date t on cte.Domain_Id = t.Domain_Id and cte.End_Date = t.Starting_Date),
cte2 as (
select *, rn = row_number() over (partition by Domain_Id, End_Date order by Domain_Id)
from cte
)
select DISTINCT Domain_Id, Starting_Date, max(End_Date) enddate
from cte2
where rn=1
group by Domain_Id, Starting_Date
order by Domain_Id, Starting_Date;
select * from Que_Date
This is the code that I have wrote but i am getting an extra row i.e 2nd row is extra, the expected output should have only 1st, 3rd and 4th row as output so please help me with it.
I have attached an image showing Input, Excepted Output, and the output that I am getting.
You've got so many results in your first cte. Your first cte has consisting domains. So you cannot filter domains based on your cte. So you query has unnecessary rows.
Try this solution. Cte ConsistentDomains has just consistent domains. So based on this cte, we can get not overlapped results.
Create and fill data:
CREATE TABLE FooTable
(
Domain_ID INT,
Starting_Date DATE,
End_Date Date
)
INSERT INTO dbo.FooTable
(
Domain_ID,
Starting_Date,
End_Date
)
VALUES
( 1, -- Domain_ID - int
CONVERT(datetime,'01-01-2011',103), -- Starting_Date - date
CONVERT(datetime,'05-01-2011',103) -- End_Date - date
)
, (1, CONVERT(datetime,'05-01-2011',103), CONVERT(datetime,'07-01-2011',103))
, (1, CONVERT(datetime,'07-01-2011',103), CONVERT(datetime,'15-01-2011',103))
, (2, CONVERT(datetime,'11-05-2011',103), CONVERT(datetime,'12-05-2011',103))
, (2, CONVERT(datetime,'13-05-2011',103), CONVERT(datetime,'14-05-2011',103))
Query to find not overlapping results:
DECLARE #startDate varchar(50) = '2011-01-01';
WITH ConsistentDomains AS
(
SELECT
f.Domain_ID
, f.Starting_Date
, f.End_Date
FROM FooTable f
WHERE f.Starting_Date = #startDate
UNION ALL
SELECT
s.Domain_ID
, s.Starting_Date
, s.End_Date
FROM FooTable s
INNER JOIN ConsistentDomains cd
ON s.Domain_ID = cd.Domain_ID
AND s.Starting_Date = cd.End_Date
), ConsistentDomainsRownumber AS
(
SELECT
cd.Domain_ID
, cd.Starting_Date
, cd.End_Date
, ROW_NUMBER() OVER (PARTITION BY cd.Domain_ID ORDER BY cd.Starting_Date,
cd.End_Date) RN
FROM ConsistentDomains cd
)
SELECT cd.Domain_ID
, convert(varchar, cd.Starting_Date, 105) Starting_Date
, convert(varchar, cd.End_Date, 105) End_Date
FROM ConsistentDomainsRownumber cd WHERE cd.RN = 1
UNION ALL
SELECT
ft.Domain_ID
, convert(varchar, ft.Starting_Date, 105) Starting_Date
, convert(varchar, ft.End_Date, 105) End_Date
FROM dbo.FooTable ft WHERE ft.Domain_ID NOT IN (SELECT cd.Domain_ID FROM
ConsistentDomainsRownumber cd)
Output:
I used the same table creating script as provided by #stepup, but you can also get your outcome in this way.
CREATE TABLE testtbl
(
Domain_ID INT,
Starting_Date DATE,
End_Date Date
)
INSERT INTO testtbl
VALUES
(1, convert(date, '01-01-2011' ,103), convert(date, '05-01-2011',103) )
,(1, convert(date, '05-01-2011' ,103), convert(date, '07-01-2011',103) )
,(1, convert(date, '07-01-2011' ,103), convert(date, '15-01-2011',103) )
,(2, convert(date, '11-05-2011' ,103), convert(date, '12-05-2011',103) )
,(2, convert(date, '13-05-2011' ,103), convert(date, '14-05-2011',103) )
You can make use of self join and Firs_value and last value within the group to make sure that you are comparing within the same ID and overlapping dates.
select distinct t.Domain_ID,
case when lag(t1.starting_date)over (partition by t.Domain_id order by
t.starting_date) is not null
then first_value(t.Starting_Date) over (partition by t.domain_id order by
t.starting_date)
else t.Starting_Date end StartingDate,
case when lead(t.domain_id) over (partition by t.domain_id order by t.starting_date) =
t1.Domain_ID then isnull(last_value(t.End_Date) over (partition by t.domain_id order by t.end_date rows between unbounded preceding and unbounded following),t.End_Date)
else t.End_Date end end_date
from testtbl t
left join testtbl t1 on t.Domain_ID = t1.Domain_ID
and t.End_Date = t1.Starting_Date
and t.Starting_Date < t1.Starting_Date
Output:
Domain_ID StartingDate end_date
1 2011-01-01 2011-01-15
2 2011-05-11 2011-05-12
2 2011-05-13 2011-05-14
How can I unpivot multiple columns in "one"?
Right now I have an unpivot for each column but this creates a lot of empty rows.
See the screenshot please.
At the top you see the input data. At the moment I'm at the table in the middle with this code:
SELECT [ID], [RowNumber], [Year], [Sales] FROM (
SELECT ID, RowNumber, [Sales 2013] as [2013], [Sales 2014] as [2014]
FROM mytable) p UNPIVOT (
[Sales] FOR [Year] IN ([2013], [2014]) )AS unpvt ;
But I think it would be much better to get to the bottom table structure since the actual data contains more columns and more years to deal with.
Here's a Fiddle with the sample data.
Hope you can show me a way to get there.
Thank you.
SELECT [ID],
[RowNumber],
[Year],
Sales,
Budget
FROM mytable
CROSS APPLY (VALUES (2013, [Sales 2013], [Budget 2013]),
(2014, [Sales 2014], [Budget 2014]) )
V([Year], Sales, Budget)
SQL Fiddle
One approach is to repivot after unpivoting - like so:
select [Id], [Year], [Sales], [Budget], [Actual] from
(SELECT [Id],
Left([Colhead], charindex(' ',[Colhead])-1) [Category],
Right([Colhead], len([Colhead])-charindex(' ',[Colhead])) [Year],
[Figures]
FROM (SELECT * FROM mytable) p
UNPIVOT ([Figures] FOR [Colhead] IN
([Sales 2013],[Sales 2014],[Budget 2013],[Budget 2014],[Actual 2013],[Actual 2014])
)
AS unpvt) as u
pivot
(max([Figures]) for [Category] in ([Sales], [Budget], [Actual])) as p
SQLFiddle here.
Ultimately I'd like my end result to look like the following:
ReportingDate FundCode FundName AssetClass Rank Percentage
-------------------------------------------------------------------------
30/11/2012 1 Fund1 Bond 1 50
30/11/2012 1 Fund1 Equity 2 30
30/11/2012 1 Fund1 Balanced 3 0
30/11/2012 1 Fund1 Other 4 20
30/11/2012 2 Fund2 Equity 1 60
30/11/2012 2 Fund2 Bond 2 20
.......
Basically if there is no data for say Balanced like in the above example I would still like this to be returned in the data but with a percentage of 0.
To get this I created a table called #AssetClass and RIGHT OUTER JOIN this to my work table so that I could get all the AssetClass's returned even without data.
My script looks like this:
;;WITH CTE AS
(
SELECT
CASE
WHEN ReportingDate IS NULL THEN MAX(ReportingDate) OVER (PARTITION BY (SELECT 1))
ELSE ReportingDate
END AS ReportingDate
, CASE
WHEN PortfolioID IS NULL THEN MAX(PortfolioID) OVER (PARTITION BY (SELECT 1))
ELSE PortfolioID
END AS PortfolioID
, CASE
WHEN PortfolioNme IS NULL THEN MAX(PortfolioNme) OVER (PARTITION BY (SELECT 1))
ELSE PortfolioNme
END AS PortfolioNme
, AC.AssetClass AS AssetClass
, CASE
WHEN AC.AssetClass = 'No Asset Class' THEN 3
WHEN AC.AssetClass = 'Other' THEN 2
ELSE 1
END AS [Rank]
, CAST(SUM(ISNULL(Percentage, 0)) AS DECIMAL(22,1)) AS [Weight]
FROM #Worktable as WT
RIGHT OUTER JOIN #AssetClass AS AC
ON RTRIM(WT.AssetClass) = RTRIM(AC.AssetClass)
GROUP BY WT.ReportingDate, WT.PortfolioID, WT.PortfolioNme, AC.AssetClass
)
SELECT
CONVERT(VARCHAR, ReportingDate, 103) AS ReportingDate
, PortfolioID AS FundCode
, PortfolioNme AS FundName
, AssetClass
, RANK() OVER ( PARTITION BY PortfolioID
ORDER BY [Rank], [Weight] DESC) AS [Rank]
, [Weight] AS Percentage
FROM CTE
ORDER BY ReportingDate, PortfolioID, [Rank], [Weight] DESC
My problem is, when I run this for one portfolio this works perfectly. When I run this for multiple portfolio's it seems to exclude in the final select anything where there is no data, so in the above example the Balanced row is not returned.
Is there an issue with my script or how I've right outer joined to #AssetClass? Is there something I'm missing or something I can improve upon in my script?
Possible this can help you
UPDATE 03.01.2013
;WITH CTE AS
(
SELECT DISTINCT WT.ReportingDate, WT.PortfolioID, WT.PortfolioNme,
AC.AssetClass,
CASE WHEN AC.AssetClass = 'No Asset Class' THEN 3
WHEN AC.AssetClass = 'Other' THEN 2
ELSE 1 END AS [Rank],
SUM(CASE WHEN AC.PortfolioID IS NULL THEN 0.00 ELSE WT.Percentage END)
OVER(PARTITION BY WT.ReportingDate, WT.PortfolioID, AC.AssetClass) AS [Weight]
FROM Worktable WT CROSS APPLY (
SELECT AC2.AssetClass, WT2.ReportingDate, WT2.PortfolioID,
WT2.AssetClass AS AssetClass2
FROM AssetClass AC2 LEFT JOIN Worktable WT2
ON RTRIM(AC2.AssetClass) = RTRIM(WT2.AssetClass)
AND WT2.PortfolioID = WT.PortfolioID
) AC
WHERE (WT.ReportingDate = AC.ReportingDate AND WT.PortfolioID = AC.PortfolioID AND WT.AssetClass = AC.AssetClass)
OR (AC.AssetClass2 IS NULL)
GROUP BY WT.ReportingDate, WT.PortfolioID, WT.PortfolioNme,
AC.AssetClass, AC.PortfolioID, WT.Percentage
)
SELECT CONVERT(VARCHAR, ReportingDate, 103) AS ReportingDate,
PortfolioID AS FundCode,
PortfolioNme AS FundName,
AssetClass,
RANK() OVER (PARTITION BY PortfolioID
ORDER BY [Rank], [Weight] DESC) AS [Rank],
[Weight] AS Percentage
FROM CTE
ORDER BY ReportingDate, PortfolioID, [Rank], [Weight] DESC
I'm trying to retrieve data for a Open-high-low-close (OHLC) chart directly from the database, it's the kind of chart you see of stocks. Is this possible, and if, how?
I have a table like this (simplified):
Date | Price | PriceType
A record is created for each day, I will report per month / year, not per day as used for stocks.
I would like to query something like this:
SELECT PriceType, MAX(Price) as High, MIN(Price) as Low, [Price of first item of month] as Open, [Price of last item of month] as Close GROUP BY PriceType, Year(Date), Month(Date)
To access the SQL Server I use LLBLGen, so an anwser based on that technology would be great, a generic SQL server will do too!
It's SQL 2005, but 2008 is also an option.
Thanks.
This appears to work. There may well be a less verbose way to do it.
--create test data
CREATE TABLE #t
(priceDate DATETIME
,price MONEY
,priceType CHAR(1)
)
INSERT #t
SELECT '20090101',100,'A'
UNION SELECT '20090102',500,'A'
UNION SELECT '20090103',20 ,'A'
UNION SELECT '20090104',25 ,'A'
UNION SELECT '20090105',28 ,'A'
UNION SELECT '20090131',150,'A'
UNION SELECT '20090201',501,'A'
UNION SELECT '20090203',21 ,'A'
UNION SELECT '20090204',26 ,'A'
UNION SELECT '20090205',29 ,'A'
UNION SELECT '20090228',151,'A'
UNION SELECT '20090101',100,'B'
UNION SELECT '20090102',500,'B'
UNION SELECT '20090103',20 ,'B'
UNION SELECT '20090104',25 ,'B'
UNION SELECT '20090105',28 ,'B'
UNION SELECT '20090131',150,'B'
UNION SELECT '20090201',501,'B'
UNION SELECT '20090203',21 ,'B'
UNION SELECT '20090204',26 ,'B'
UNION SELECT '20090205',29 ,'B'
UNION SELECT '20090228',151,'B'
--query
;WITH rangeCTE
AS
(
SELECT MIN(priceDate) minDate
,MAX(priceDate) maxDate
FROM #t
)
,datelistCTE
AS
(
SELECT CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME) AS monthStart
,DATEADD(mm,1,CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME)) -1 AS monthEnd
,1 AS monthID
FROM rangeCTE
UNION ALL
SELECT DATEADD(mm,1,monthStart)
,DATEADD(mm,2,monthStart) - 1
,monthID + 1
FROM datelistCTE
WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
)
,priceOrderCTE
AS
(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY priceDate
) AS rn1
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY priceDate DESC
) AS rn2
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY price DESC
) AS rn3
,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
ORDER BY price
) AS rn4
FROM datelistCTE AS d
JOIN #t AS t
ON t.priceDate BETWEEN d.monthStart AND d.monthEnd
WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
)
SELECT o.MonthStart
,o.priceType
,o.Price AS opening
,c.price AS closing
,h.price AS high
,l.price AS low
FROM priceOrderCTE AS o
JOIN priceOrderCTE AS c
ON c.priceType = o.PriceType
AND c.monthID = o.MonthID
JOIN priceOrderCTE AS h
ON h.priceType = o.PriceType
AND h.monthID = o.MonthID
JOIN priceOrderCTE AS l
ON l.priceType = o.PriceType
AND l.monthID = o.MonthID
WHERE o.rn1 = 1
AND c.rn2 = 1
AND h.rn3 = 1
AND l.rn4 = 1
This is a little query I wrote that seems to work nicely for one time span at a time. All you need to do is comment the select DATEPARTS in order to get to the timespan you are looking for. Or you could just make multiple views for different timespans. Also the underlying data table uses Bid Ask tick style data. If you are using mids or last prices you could eliminate the case statements from the selects.
Select
tmp.num,
rf.CurveName,
rf.Period as Period,
CASE WHEN (tmp2.Bid is null or tmp2.Ask is null) then isnull(tmp2.Bid,0)+isnull(tmp2.Ask,0) else (tmp2.Bid+tmp2.Ask)/2 end as [Open],
tmp.Hi,
tmp.Lo,
CASE WHEN (rf.Bid is null or Rf.Ask is null) then isnull(rf.Bid,0)+isnull(rf.Ask,0) else (rf.Bid+rf.Ask)/2 end as [Close],
tmp.OpenDate,
tmp.CloseDate,
tmp.yr,
tmp.mth,
tmp.wk,
tmp.dy,
tmp.hr
from BidAsk rf inner join
(SELECT count(CurveName)as num,CurveName,
Period,
max(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Hi,
min(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Lo,
max(CurveDateTime) as CloseDate, min(CurveDateTime) as OpenDate,
DATEPART(year, CurveDateTime) As yr,
DATEPART(month, CurveDateTime) As mth,
DATEPART(week, CurveDateTime) As wk,
DATEPART(Day, CurveDateTime) as dy,
DATEPART(Hour, CurveDateTime) as hr
--DATEPART(minute, CurveDateTime) as mnt
FROM
BidAsk
GROUP BY
CurveName,Period,
DATEPART(year, CurveDateTime),
DATEPART(month, CurveDateTime),
DATEPART(week, CurveDateTime),
DATEPART(Day, CurveDateTime) ,
DATEPART(Hour, CurveDateTime)
--DATEPART(minute, CurveDateTime)
) tmp on
tmp.CurveName=rf.CurveName and
tmp.CloseDate=rf.CurveDateTime and
tmp.Period=rf.Period
inner join BidAsk tmp2 on
tmp2.CurveName=rf.CurveName and
tmp2.CurveDateTime=tmp.Opendate and
tmp2.Period=rf.Period
ORDER BY
CurveName,Period,tmp.yr,tmp.mth
--DATEPART(year, CurveDateTime),
--DATEPART(month, CurveDateTime)
--DATEPART(day, CurveDateTime),
--DATEPART(Hour, CurveDateTime),
--DATEPART(minute, CurveDateTime) )