i have following table:
id insertDate
1 2015-01-01
22 2015-01-02
43 2015-01-03
46 2015-01-06
124 2015-01-07
In the end i want to have a possiblity to group the rows that differ exaclty in one day so in that case
id insertDate groups
1 2015-01-01 1
22 2015-01-02 1
43 2015-01-03 1
46 2015-01-06 2
124 2015-01-07 2
How is this possible? I bet it is some fancy window function usage
This is a "gaps and islands" problem.
One approach is below. This works on SQL Server 2005+. I have assumed that insertDate is unique as per your example data.
WITH CTE
AS (SELECT *,
DATEDIFF(DAY, 0, [insertDate]) - ROW_NUMBER() OVER (ORDER BY ID) AS Grp
FROM YourTable)
SELECT [id],
[insertDate],
DENSE_RANK() OVER (ORDER BY Grp) AS Grp
FROM CTE
Related
I have a table as below:
Department Date Budget
-----------------------------------
D1 2010-01-01 100
D2 2010-01-01 200
... ... ...
Is there a way to write an insert statement that autoincrements the month and budget for a particular department?
For instance, I want to insert data for 2010 from Jan to Dec for department D1 with increments of 10 each month. So the resultant table should look something like below
Department Date Budget
------------------------------------
D1 2010-01-01 100
D2 2010-01-01 200
D1 2010-02-01 110
D1 2010-03-01 120
D1 2010-04-01 130
... ... ...
I know this can be achieved through some scripting, but is there a way to achieve this through just insert and select statements ?
Using SQL Server (or) Postgres
For Postgres:
insert into the_table (department, "date", budget)
select d.department,
d.date + interval '1 month' * row_number() over (order by g.i),
d.budget + row_number() over (order by g.i) * 10
from the_table d, generate_series(1,11) as g(i)
where d.department = 'D1';
This assumes that at the time when this is run, only a single row exists for department D1
try something like
insert into Table values
('D1',Dateadd(month,1,
(select top 1 Date from Table order by Date Desc)),budget)
using recursive cte
;With cte(Department,[Date], Budget)
AS
(
SELECT 'D1','2010-01-01', 100 UNION ALL
SELECT 'D2','2010-01-01', 200
)
,cte2 AS
(
SELECT 0 AS val ,
0 AS val2
UNION ALL
SELECT val +1,
val2+10
FROM cte2
WHERE val<11 )
INSERT INTO the_table (department, [date], budget)
SELECT department,
[date],
CASE
WHEN rnk=0 THEN budget
ELSE budget+val2
END AS Budget
FROM (
SELECT department,
val2,
Dateadd(month,val,[date])AS [Date],
budget,
Row_number()OVER(PArtition by Department ORDER BY [Date])-1 AS Rnk
FROM Cte2 ,
Cte )dt
WHERE dt.department='D1'
Result
department Date Budget
-------------------------------------------
D1 2010-01-01 00:00:00.000 100
D1 2010-02-01 00:00:00.000 110
D1 2010-03-01 00:00:00.000 120
D1 2010-04-01 00:00:00.000 130
D1 2010-05-01 00:00:00.000 140
D1 2010-06-01 00:00:00.000 150
D1 2010-07-01 00:00:00.000 160
D1 2010-08-01 00:00:00.000 170
D1 2010-09-01 00:00:00.000 180
D1 2010-10-01 00:00:00.000 190
D1 2010-11-01 00:00:00.000 200
D1 2010-12-01 00:00:00.000 210
I'm trying to do this query, in sql server, but something is wrong. Need some help...
I have a table with item movements and another one with other movements (buy) where I find the cost of each item in each date when I buy it. So, I just need first table with last cost based on the date of movement finding the cost on second table on the last date.
In other words, only must search the records from the second table with date lower than the first table date for that item and return the cost of the most recent date.
Examples:
First Table
REF DATE
1 2015-10-15
1 2015-08-30
2 2015-09-11
3 2015-05-22
2 2015-03-08
2 2015-07-15
3 2015-11-14
1 2015-11-20
Second Table (Buy)
REF DATE COST
1 2015-08-20 150
1 2015-10-12 120
2 2015-04-04 270
2 2015-06-15 280
3 2015-03-01 75
3 2015-10-17 80
I need this result:
REF DATE Cost
1 2015-10-15 120
1 2015-08-30 150
2 2015-09-11 280
3 2015-05-22 75
2 2015-03-08 -
2 2015-07-15 280
3 2015-11-14 80
1 2015-11-20 120
Any help appreciated.
You can do it using OUTER APPLY:
SELECT [REF], [DATE], [COST]
FROM Table1 AS t1
OUTER APPLY (
SELECT TOP 1 COST
FROM Table2 AS t2
WHERE t1.REF = t2.REF AND t1.DATE >= t2.DATE
ORDER BY t2.DATE DESC) AS t3
Demo here
;WITH cte AS (
SELECT ft.*,
st.[Cost],
ROW_NUMBER() OVER (PARTITION BY ft.[Ref],ft.[Date] ORDER BY st.[Date] DESC) RN
FROM FirstTable ft
LEFT JOIN SecondTable st ON ft.[Ref] = st.[Ref]
AND ft.[Date] >= st.[Date]
)
SELECT Ref,
[Date],
[Cost]
FROM cte
WHERE RN = 1
or if you dont want to use a cte.
SELECT
Ref,
[Date],
[Cost]
FROM
(SELECT
ft.*,
st.[Cost],
ROW_NUMBER() OVER (PARTITION BY ft.[Ref],ft.[Date] ORDER BY st.[Date] DESC) RN
FROM
FirstTable ft
LEFT JOIN SecondTable st ON ft.[Ref] = st.[Ref]
AND ft.[Date] >= st.[Date]
) t
WHERE
t.RN = 1
EDIT: I am using SQL Server 2005
So here's a tricky one. For audit purposes, we need to make 3 attempts to contact a customer. We can make more than 3 attempts to go above and beyond, but audit purposes I need to retrieve the date of the third most recent attempt for each customer.
In most cases, you just need the most recent period, so you can do something like..
SELECT CustID,MAX(AttemptDate) FROM Attempts GROUP BY CustID
.. but that obviously won't work in this scenario.
Say I have a table of attempts that occur which are tied to a customer.
CustID AttemptDate
123 2014-01-02
123 2014-01-05
123 2014-01-06 * retrieve this one
123 2014-01-07
123 2014-01-10
555 2014-02-01
555 2014-02-03
555 2014-02-07 * retrieve this one
555 2014-02-12
555 2014-02-20
Output:
CustID AttemptDate
123 2014-01-06
555 2014-02-07
Any tips for pulling this off?
;WITH t AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY AttemptDate DESC) AS nth_most_recent
FROM MyTable
)
SELECT *
FROM t
WHERE nth_most_recent = 3
The ROW_NUMBER ranking function is your friend here:
WITH cte (CustId, AttemptDate, AttemptNumber) AS (
SELECT
CustId,
AttemptDate,
ROW_NUMBER() OVER (PARTITION BY CustID ORDER BY AttemptDate DESC) AS AttemptNumber
FROM Attempts
)
SELECT
CustId,
AttemptDate
FROM cte
WHERE AttemptNumber = 3
Alternatively, if the common table expression syntax is causing problems, you could use a subquery:
SELECT
CustId,
AttemptDate
FROM (
SELECT
CustId,
AttemptDate,
ROW_NUMBER() OVER (PARTITION BY CustID ORDER BY AttemptDate DESC) AS AttemptNumber
FROM Attempts
) sq
WHERE AttemptNumber = 3
I have a table PriceDate with two columns PriceId and PriceDate with 3-4 entries per month.
I want to retrieve last inserted PriceDate for each month.
This is my table
PriceDate PriceId
2012-01-07 00:00:00.000 1
2012-01-14 00:00:00.000 2
2012-01-21 00:00:00.000 3
2012-01-28 00:00:00.000 4
2012-02-04 00:00:00.000 5
2012-02-11 00:00:00.000 6
2012-02-18 00:00:00.000 7
2012-02-25 00:00:00.000 8
I need this output
PriceDate DateFormat PriceId
2012-01-28 00:00:00.000 Jan 2012 4
2012-02-25 00:00:00.000 Feb 2012 8
This seems to do the trick:
declare #t table (PriceDate datetime not null, PriceId int not null)
insert into #t(PriceDate,PriceId) values
('2012-01-07T00:00:00.000',1),
('2012-01-14T00:00:00.000',2),
('2012-01-21T00:00:00.000',3),
('2012-01-28T00:00:00.000',4),
('2012-02-04T00:00:00.000',5),
('2012-02-11T00:00:00.000',6),
('2012-02-18T00:00:00.000',7),
('2012-02-25T00:00:00.000',8)
;With Numbered as (
select *,
ROW_NUMBER() OVER (
PARTITION BY DATEADD(month,DATEDIFF(month,0,PriceDate),0)
ORDER BY PriceDate desc) as rn
from #t
)
select PriceDate,
RIGHT(CONVERT(varchar(20),PriceDate,106),8) [Dateformat],
PriceId
from Numbered where rn=1
The DATEADD/DATEDIFF trick is to basically round every date to the start of its respective month.
Result:
PriceDate Dateformat PriceId
----------------------- -------- -----------
2012-01-28 00:00:00.000 Jan 2012 4
2012-02-25 00:00:00.000 Feb 2012 8
Similar to #Damian_The_Unbeliever's but using the YEAR() and Month() functions
;WITH DateOrdered
AS
(
SELECT PriceDate, PriceId,
ROW_NUMBER() OVER (
PARTITION BY YEAR(PriceDate), MONTH(PriceDate)
ORDER BY PriceDate DESC) As Num
from PriceDate
)
SELECT PriceDate, RIGHT(CONVERT(varchar(20),PriceDate,106),8) [Dateformat], PriceId
FROM DateOrdered
WHERE Num = 1
My database record is as below:-
cartid orderid foodid qty
==============================
92 107 5 1
93 107 5 1
94 107 5 1
95 107 11 1
96 107 5 1
97 108 5 1
Can it be arrange into this form?
Assume that the max sum(qty)=3
foodid sum(qty)
=================
5 3
11 1
5 2
You look like you are trying to sum contiguous ranges (islands) of the same foodid ordered by cartid?
;with cart as
(
SELECT 92 AS cartid,107 AS orderid,5 AS foodid, 1 AS qty UNION ALL
SELECT 93,107,5, 1 UNION ALL
SELECT 94,107,5, 1 UNION ALL
SELECT 95,107,11,1 UNION ALL
SELECT 96,107,5, 1 UNION ALL
SELECT 97,108,5, 1
),
NumberedCart As
(
SELECT cartid,foodid,qty,
ROW_NUMBER() OVER (ORDER BY cartid)-
ROW_NUMBER() OVER (PARTITION BY foodid ORDER BY cartid) AS G
FROM cart
)
SELECT foodid, SUM(qty) AS [sum(qty)]
FROM NumberedCart
GROUP BY foodid,G
ORDER BY MIN(cartid)
Returns
foodid sum(qty)
----------- -----------
5 3
11 1
5 2
I'm not sure what you mean by Max Sum(qty)=3...
But here is some SQL to get you started:
SELECT foodid
, SUM(qty)
FROM YourTableName
GROUP BY foodid