I need to extract and split data from a membership table.
I want to split the range to get one line per year.
DateFrom and dateTo can be any day of the year but when dates are split, we assume that a row ends on december 31 and a new row start on january 1st
Here's a look of the data
membershipId - groupId - ClientId - DateFrom - DateTo
2707 20008 1579 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000
20989 20008 1579 1999-01-01 00:00:00.000 2004-12-31 00:00:00.000
39874 20298 1579 2005-01-01 00:00:00.000 2008-12-31 00:00:00.000
50295 21661 1579 2009-01-01 00:00:00.000 2009-12-31 00:00:00.000
50988 20399 1579 2010-01-01 00:00:00.000 2010-12-31 00:00:00.000
52378 21661 1579 2011-01-01 00:00:00.000 2013-12-31 00:00:00.000
57274 21660 1579 2014-01-01 00:00:00.000 3000-01-01 00:00:00.000
The expected result is : (every range split)
2707 20008 1579 1997-01-01 00:00:00.000 1997-12-31 00:00:00.000
20989 20008 1579 1999-01-01 00:00:00.000 1999-12-31 00:00:00.000
20989 20008 1579 2000-01-01 00:00:00.000 2000-12-31 00:00:00.000
20989 20008 1579 2001-01-01 00:00:00.000 2001-12-31 00:00:00.000
20989 20008 1579 2002-01-01 00:00:00.000 2002-12-31 00:00:00.000
20989 20008 1579 2003-01-01 00:00:00.000 2003-12-31 00:00:00.000
20989 20008 1579 2004-01-01 00:00:00.000 2004-12-31 00:00:00.000
50295 21661 1579 2009-01-01 00:00:00.000 2009-12-31 00:00:00.000
50988 20399 1579 2010-01-01 00:00:00.000 2010-12-31 00:00:00.000
52378 21661 1579 2011-01-01 00:00:00.000 2011-12-31 00:00:00.000
52378 21661 1579 2012-01-01 00:00:00.000 2012-12-31 00:00:00.000
52378 21661 1579 2013-01-01 00:00:00.000 2013-12-31 00:00:00.000
57274 21660 1579 2014-01-01 00:00:00.000 3000-01-01 00:00:00.000
I tried to use recursive CTE based on this :
Possible recursive CTE query using date ranges
But I cannot achieve the desired result.
I made this query :
WITH splitDates(startDate,endDate, newDate,client, groupingId ) as
(
SELECT m.datefrom as startDate, m.dateTo
, CASE
when year(m.dateFrom) <> year(m.dateto) then CAST(CAST(year(m.dateFrom) AS varchar) + '-' + CAST(12 AS varchar) + '-' + CAST(31 AS varchar) AS DATETIME)
else m.dateTo
end
, m.legalEntityId, m.groupingId
from adesse.dbo.membership m
UNION ALL
SELECT DATEADD(year, 1, startDate),
CAST(CAST(year(startDate)+1 AS varchar) + '-' + CAST(12 AS varchar) + '-' + CAST(31 AS varchar) AS DATETIME)
,CAST(CAST(year(startDate)+1 AS varchar) + '-' + CAST(12 AS varchar) + '- ' + CAST(31 AS varchar) AS DATETIME)
,client, groupingId
FROM splitDates
WHERE year(startDate) <> year(endDate)
)
SELECT *
FROM splitDates
where client = 1579
order by startDate
But the result is incomplete :(
startDate endDate newDate client groupingId
1997-01-01 00:00:00.000 1997-12-31 00:00:00.000 1997-12-31 00:00:00.000 1579 20008
1999-01-01 00:00:00.000 2004-12-31 00:00:00.000 1999-12-31 00:00:00.000 1579 20008
2000-01-01 00:00:00.000 2000-12-31 00:00:00.000 2000-12-31 00:00:00.000 1579 20008
2005-01-01 00:00:00.000 2008-12-31 00:00:00.000 2005-12-31 00:00:00.000 1579 20298
2006-01-01 00:00:00.000 2006-12-31 00:00:00.000 2006-12-31 00:00:00.000 1579 20298
2009-01-01 00:00:00.000 2009-12-31 00:00:00.000 2009-12-31 00:00:00.000 1579 21661
2010-01-01 00:00:00.000 2010-12-31 00:00:00.000 2010-12-31 00:00:00.000 1579 20399
2011-01-01 00:00:00.000 2013-12-31 00:00:00.000 2011-12-31 00:00:00.000 1579 21661
2012-01-01 00:00:00.000 2012-12-31 00:00:00.000 2012-12-31 00:00:00.000 1579 21661
2014-01-01 00:00:00.000 3000-01-01 00:00:00.000 2014-12-31 00:00:00.000 1579 21660
2015-01-01 00:00:00.000 2015-12-31 00:00:00.000 2015-12-31 00:00:00.000 1579 21660
Thx for the help
I'm not sure if your last date is suppose to be 3000-01-01 but this should work
CREATE TABLE members (membershipId INT, groupId INT, clientId INT, dateFrom DATETIME, dateTo DATETIME)
INSERT INTO members VALUES
(2707, 20008, 1579, '1997-01-01 00:00:00.000', '1997-12-31 00:00:00.000'),
(20989, 20008, 1579, '1999-01-01 00:00:00.000', '2004-12-31 00:00:00.000'),
(39874, 20298, 1579, '2005-01-01 00:00:00.000', '2008-12-31 00:00:00.000'),
(50295, 21661, 1579, '2009-01-01 00:00:00.000', '2009-12-31 00:00:00.000'),
(50988, 20399, 1579, '2010-01-01 00:00:00.000', '2010-12-31 00:00:00.000'),
(52378, 21661, 1579, '2011-01-01 00:00:00.000', '2013-12-31 00:00:00.000'),
(57274, 21660, 1579, '2014-01-01 00:00:00.000', '3000-01-01 00:00:00.000')
;
WITH cte AS
(
SELECT
membershipId,
groupId,
clientId,
dateFrom,
DATEADD(day, -1, DATEADD(YEAR,1,dateFrom)) newDateTo,
dateTo
FROM
members
UNION ALL
SELECT
m.membershipId,
m.groupId,
m.clientId,
DATEADD(YEAR,1,c.dateFrom),
DATEADD(day, -1, DATEADD(YEAR,2,c.dateFrom)),
c.dateto
FROM
members m
JOIN cte c ON c.membershipId = m.membershipId
AND DATEADD(YEAR,1,c.dateFrom) < m.dateTo
)
SELECT
membershipId,
groupId,
clientId,
dateFrom,
newDateTo dateTo
FROM
cte
ORDER BY
membershipId, dateFrom
OPTION (MAXRECURSION 0);
DROP TABLE members
SQL Fiddle
Related
I have 2 tables that I am trying to marry together to end up with a result, which tells me the standard cost of the item that is still on hand (based on a FIFO costing method). The first table is inventory receipts , which tells me the parts left to consume and the transaction dates of those receipts. The second is a standard cost view which tells me the cost history of the item (rev = revision number which increases by 1 each time the standard cost of the part gets updated).
I currently have a solution which works using TOP 1 and ordering by DESC on effective date of cost, however, when I run this for the entire inventory list of the company , it takes over 16 minutes due to the TOP 1 sub-query inefficiency and cost.
Sample data (inventory receipts on hand):
partID warehouse transDate seqn orderID qtytoconsume
-------------------------------------------------------------
P0003 W01 2019-01-24 00:00:00.000 1 ORD0187 2
P0003 W01 2018-06-24 00:00:00.000 1 ORD0099 3
P0003 W01 2018-11-24 00:00:00.000 1 ORD0165 1
P0003 W04 2018-12-14 00:00:00.000 1 ORD0175 1
P0002 W02 2019-01-14 00:00:00.000 1 ORD0184 4
P0002 W02 2019-03-24 00:00:00.000 1 ORD0199 1
P0002 W03 2018-05-27 00:00:00.000 1 ORD0093 1
P0002 W03 2018-12-06 00:00:00.000 1 ORD0171 2
P0001 W04 2018-09-09 00:00:00.000 1 ORD0146 5
P0001 W02 2019-04-22 00:00:00.000 1 ORD0200 4
P0001 W03 2019-03-29 00:00:00.000 1 ORD0200 2
P0001 W02 2018-02-14 00:00:00.000 1 ORD0061 1
and standard cost view:
partID document effdate rev costamt
-----------------------------------------------------
P0001 IV0001 2018-01-28 00:00:00.000 1 1000.00
P0001 IV0023 2018-06-30 00:00:00.000 2 1200.00
P0001 IV0045 2019-01-01 00:00:00.000 3 1300.00
P0002 IV0001 2018-01-28 00:00:00.000 1 45.00
P0002 IV0013 2018-04-10 00:00:00.000 2 42.00
P0002 IV0045 2019-01-01 00:00:00.000 3 56.00
P0003 IV0001 2018-01-28 00:00:00.000 1 23400.00
P0003 IV0003 2018-02-20 00:00:00.000 2 11200.00
P0003 IV0045 2019-01-01 00:00:00.000 3 15000.00
P0003 IV0047 2019-02-27 00:00:00.000 4 13400.00
P0003 IV0078 2019-05-03 00:00:00.000 5 14670.00
And my result (which equals my expected result), but for large row sets is less than ideal.
partID warehouse transDate seqn orderID qty costamt
-------------------------------------------------------------
P0003 W01 2019-01-24 00:00:00.000 1 ORD0187 2 15000.00
P0003 W01 2018-06-24 00:00:00.000 1 ORD0099 3 11200.00
P0003 W01 2018-11-24 00:00:00.000 1 ORD0165 1 11200.00
P0003 W04 2018-12-14 00:00:00.000 1 ORD0175 1 11200.00
P0002 W02 2019-01-14 00:00:00.000 1 ORD0184 4 56.00
P0002 W02 2019-03-24 00:00:00.000 1 ORD0199 1 56.00
P0002 W03 2018-05-27 00:00:00.000 1 ORD0093 1 42.00
P0002 W03 2018-12-06 00:00:00.000 1 ORD0171 2 42.00
P0001 W04 2018-09-09 00:00:00.000 1 ORD0146 5 1200.00
P0001 W02 2019-04-22 00:00:00.000 1 ORD0200 4 1300.00
P0001 W03 2019-03-29 00:00:00.000 1 ORD0200 2 1300.00
P0001 W02 2018-02-14 00:00:00.000 1 ORD0061 1 1000.00
My query is:
SELECT
ioh.*, sc.costamt, sc.effdate
FROM
inventoryonHand ioh
LEFT JOIN
standardcosts sc ON sc.partID = ioh.partID
AND sc.effdate = (SELECT TOP 1 sc2.effDate
FROM standardcosts sc2
WHERE sc2.partID = sc.partID
AND sc2.effDate < ioh.transDate
ORDER BY sc2.partID ASC, sc2.effDate DESC);
Thanks so much guys!
You can try it (if your consider partID and transdate can be unique into your inventoryonHand table, otherwhise use partition by on his key) :
select * from (
select f1.*,
f2.effdate, f2.costamt, f2.rev,
row_number() over(partition by f1.partid, f1.transdate order by f2.effdate desc, f2.rev desc) as lasteffDaterank
from inventoryonHand f1
left outer join standardcosts f2 on f1.partid=f2.partid and f2.effDate < f1.transDate
) tmp
where lasteffDaterank=1
You could try to simplify the subquery using max().
(SELECT max(sc1.effdate)
FROM standardcosts sc2
WHERE sc2.partid = sc.partid
AND sc2.effdate < ioh.transdate)
For performance try an index on standardcosts (partid ASC, effdate DESC).
You can ty this too, not really sur its better ;)
select f1.*, f3.*
from inventoryonHand f1
outer apply
(
select top 1 f2.costamt from standardcosts f2
where f1.partid=f2.partid and f2.effDate < f1.transDate
order by f2.effdate desc, f2.rev desc
) f3
I want records in descending order of DATE and continue with the same set of group i.e. here the MAX date is 2018-10-25 00:00:00.000 then the next 3 records should be of REC = 5
REC DATE
===========================
1 2018-01-02 00:00:00.000
1 2018-01-03 00:00:00.000
1 2018-01-04 00:00:00.000
2 2018-06-01 00:00:00.000
2 2018-06-02 00:00:00.000
3 2018-03-01 00:00:00.000
3 2018-05-02 00:00:00.000
3 2018-01-03 00:00:00.000
3 2018-08-04 00:00:00.000
3 2018-10-05 00:00:00.000
4 2018-10-06 00:00:00.000
5 2018-10-25 00:00:00.000
5 2018-05-03 00:00:00.000
5 2018-09-09 00:00:00.000
This is what I have tried but no success.
SELECT t1.REC, t1.DATE
FROM TEMP AS t1
INNER JOIN (SELECT REC, MAX(DATE) AS MaxDate
FROM TEMP
GROUP BY REC) AS t2
ON (t1.REC = t2.REC AND t1.DATE = t2.MaxDate)
Expected result should be something like this:
REC DATE
===============================
5 2018-10-25 00:00:00.000
..........{Remaining dates of `REC` 5}
4 2018-10-06 00:00:00.000
..........{Remaining dates of `REC` 4}
3 2018-10-05 00:00:00.000
..........{Remaining dates of `REC` 3}
2 2018-06-02 00:00:00.000
..........{Remaining dates of `REC` 2}
1 2018-01-04 00:00:00.000
..........{Remaining dates of `REC` 1}
max_date is maximum date per REC
SELECT *, max_date = MAX(DATE) OVER (PARTITION BY REC)
FROM yourtable
ORDER BY max_date DESC, DATE DESC
I have a data like this
RID Region StartDate EndDate
944 Canada 2016-01-09 00:00:00.000 2016-01-16 23:59:59.000
955 Canada 2016-01-17 00:00:00.000 2016-01-24 23:59:59.000
981 Canada 2016-02-01 00:00:00.000 2016-02-08 23:59:59.000
996 Canada 2016-02-09 00:00:00.000 2016-02-16 23:59:59.000
1006 Canada 2016-01-25 00:00:00.000 2016-01-31 23:59:59.000
1020 Canada 2016-02-17 00:00:00.000 2016-02-24 23:59:59.000
1030 Canada 2016-02-25 00:00:00.000 2016-02-29 23:59:59.000
1041 Canada 2016-03-01 00:00:00.000 2016-03-08 23:59:59.000
1046 Canada 2016-03-09 00:00:00.000 2016-03-16 23:59:59.000
1062 Canada 2016-03-17 00:00:00.000 2016-03-24 23:59:59.000
1073 Canada 2016-03-24 00:00:00.000 2016-03-31 23:59:59.000
1083 Canada 2016-04-01 00:00:00.000 2016-04-08 23:59:59.000
1105 Canada 2016-04-09 00:00:00.000 2016-04-16 23:59:59.000
1118 Canada 2016-04-17 00:00:00.000 2016-04-24 23:59:59.000
1128 Canada 2016-04-25 00:00:00.000 2016-04-30 23:59:59.000
1164 Canada 2016-05-01 00:00:00.000 2016-05-08 23:59:59.000
now i try to select data like this
select * from tab1 where Region='Canada'
and StartDate ='2016-01-09 00:00:00.000'
and EndDate ='2016-01-24 23:59:59.000'
desired result is
RID Region StartDate EndDate
944 Canada 2016-01-09 00:00:00.000 2016-01-16 23:59:59.000
955 Canada 2016-01-17 00:00:00.000 2016-01-24 23:59:59.000
but when i execute this query data is empty
any solution?
I think you were intending to restrict to a date range, but you actually restricted to two points in time instead. Try this query:
SELECT *
FROM tab1
WHERE Region = 'Canada' AND
StartDate >= '2016-01-09 00:00:00.000' AND
EndDate <= '2016-01-24 23:59:59.000'
Try this.
SELECT *
FROM tab1
WHERE Region = 'Canada'
AND StartDate >='2016-01-09 00:00:00.000'
AND EndDate <='2016-01-24 23:59:59.000'
The 'between' must work. I tried this. If in case it is not working, try convert function for those datetime columns.
SELECT *
FROM tab1
WHERE Region = 'Canada' AND
StartDate >= convert(datetime,'2016-01-09 00:00:00.000') AND
EndDate <= convert(datetime,'2016-01-24 23:59:59.000')
I have an insurance_end column in my table, which is a datetime value.
So with today's date being: 2015-02-20, I want to retrieve items that are due to end in the next 7 days.
Sample Data:
insurance_end
=======================
2017-02-13 00:00:00.000
2016-02-13 00:00:00.000
2015-02-13 00:00:00.000
2015-02-14 00:00:00.000
2015-02-20 00:00:00.000
2015-02-28 00:00:00.000
2015-02-28 00:00:00.000
2015-02-04 00:00:00.000
2015-02-13 00:00:00.000
2015-02-01 00:00:00.000
2015-02-10 00:00:00.000
2013-02-09 00:00:00.000
Desired output would be:
insurance_end
=======================
2015-02-14 00:00:00.000
2015-02-20 00:00:00.000
2015-02-13 00:00:00.000
Here's what I tried:
SELECT*
FROM customer_profile
WHERE DATEADD(dd, -7, insurance_end) <= CAST(insurance_end AS DATETIME)
As I understand it, you want to show records where the insurance is ending within the next 7 days.
Just use GETDATE() to get today's date and subtract 7 days to get the date of 7 days prior. CONVERT to DATE to take off the time portion.
SELECT CONVERT(DATE, GETDATE()) AS TodaysDate,
CONVERT(DATE, GETDATE() - 7) AS TodayMinus7
This will give you:
TodaysDate TodayMinus7
==========================
2015-02-20 2015-02-13
You can then compare this value to your insurance_end values:
SQL Fiddle Demo
MS SQL Server Schema Setup:
CREATE TABLE customer_profile
([insurance_end] datetime)
;
INSERT INTO customer_profile
([insurance_end])
VALUES
('2015-02-13 00:00:00'),
('2015-02-14 00:00:00'),
('2015-02-20 00:00:00'),
('2015-02-28 00:00:00'),
('2015-02-28 00:00:00'),
('2015-02-04 00:00:00'),
('2015-02-13 00:00:00'),
('2015-02-01 00:00:00'),
('2015-02-10 00:00:00'),
('2013-02-09 00:00:00')
;
Query To Get Desired Output:
SELECT *
FROM customer_profile
WHERE CONVERT(DATE, GETDATE() -7) <= insurance_end
AND insurance_end <= CONVERT(DATE, GETDATE())
You could also change the WHERE clause to use BETWEEN:
WHERE insurance_end BETWEEN
CONVERT(DATE, GETDATE() -7) AND CONVERT(DATE, GETDATE())
Results:
| INSURANCE_END |
|---------------------------------|
| February, 13 2015 00:00:00+0000 |
| February, 14 2015 00:00:00+0000 |
| February, 20 2015 00:00:00+0000 |
| February, 13 2015 00:00:00+0000 |
I hope this is what you are looking for.
Query
SELECT *
FROM insurance
WHERE
DATEDIFF(day,GETDATE(),insurance_end)=-7;
Fiddle demo for reference
I have a table where I have several cust_id duplicates. I would like to keep the row where prendate_next is nearest to the current date and delete the rest of the duplicates. Please help me how. I am new to this
cust_id prendate_next
1000105737 2014-11-30 00:00:00.000
1000105836 2014-11-20 00:00:00.000
1000143646 2014-11-10 00:00:00.000
1000143646 2015-03-09 00:00:00.000
1000179487 2014-12-05 00:00:00.000
1000182253 2015-01-01 00:00:00.000
1000192740 2014-10-02 00:00:00.000
1000192740 2015-01-10 00:00:00.000
1000199419 2015-09-30 00:00:00.000
1000170578 2014-12-26 00:00:00.000
1000188890 2015-06-23 00:00:00.000
1000189075 2015-03-01 00:00:00.000
1000189075 2015-03-01 00:00:00.000
1000189144 2015-04-04 00:00:00.000
;WITH cte AS (
SELECT cust_id, prendate_next,
ROW_NUMBER() OVER (PARTITION BY cust_id ORDER BY ABS(DATEDIFF(DAY,prendate_next,GETDATE()))) AS RowNumber
FROM MyTable
)
DELETE MyTable
FROM MyTable
INNER JOIN cte ON MyTable.cust_id = cte.cust_id
AND MyTable.prendate_next = cte.prendate_next
WHERE cte.RowNumber != 1
ABS(DATEDIFF(DAY,prendate_next,GETDATE())) counts how many days prendate_next is from today.