Related
I have table like this. I want to get employee records to get their current Designation(whose effectiveto is null) and the date where they FIRST joined as Trainee(min(effectivefrom) where Designation= Trainee)
+----+-------------------+---------------+-------------+
| ID | Designation | EffectiveFrom | EffectiveTo |
+----+-------------------+---------------+-------------+
| 1 | Trainee | 01/01/2000 | 31/12/2000 |
| 1 | Assistant Manager | 01/01/2001 | 31/12/2004 |
| 1 | Suspended | 01/01/2005 | 01/02/2005 |
| 1 | Trainee | 02/03/2005 | 31/03/2005 |
| 1 | Manager | 01/04/2005 | NULL |
| 2 | Trainee | 01/01/2014 | 31/12/2014 |
| 2 | Developer | 01/01/2015 | 31/12/2016 |
| 2 | Architect | 01/01/2017 | NULL |
+----+-------------------+---------------+-------------+
How to get result like this
+----+---------------------+---------------------+
| ID | Current Designation | Date First Employed |
+----+---------------------+---------------------+
| 1 | Manager | 01/01/2000 |
| 2 | Architect | 01/01/2014 |
+----+---------------------+---------------------+
The date of first employment could be located using CROSS APPLY and SELECT TOP(1)
CREATE TABLE #table1(
ID int,
Designation varchar(17),
EffectiveFrom datetime,
EffectiveTo varchar(10));
INSERT INTO #table1
(ID, Designation, EffectiveFrom, EffectiveTo)
VALUES
(1, 'Trainee', '2000-01-01 01:00:00', '31/12/2000'),
(1, 'Assistant Manager', '2001-01-01 01:00:00', '31/12/2004'),
(1, 'Suspended', '2005-01-01 01:00:00', '01/02/2005'),
(1, 'Trainee', '2005-02-03 01:00:00', '31/03/2005'),
(1, 'Manager', '2005-01-04 01:00:00', NULL),
(2, 'Trainee', '2014-01-01 01:00:00', '31/12/2014'),
(2, 'Developer', '2015-01-01 01:00:00', '31/12/2016'),
(2, 'Architect', '2017-01-01 01:00:00', NULL);
select t.ID, t.Designation [Current Designation],
ef.EffectiveFrom [Date First Employed]
from #table1 t
cross apply (select top(1) cast(tt.EffectiveFrom as date) EffectiveFrom
from #table1 tt
where t.ID=tt.ID
and Designation='Trainee'
order by tt.EffectiveFrom) ef
where t.EffectiveTo is null;
ID Current Designation Date First Employed
1 Manager 2000-01-01
2 Architect 2014-01-01
One method is conditional aggregation. It is a bit unclear how you define "current", but assuming this is associated with EffectiveTo being NULL:
select id,
max(case when EffectiveTo is null then designation end) as current_designation,
min(effectivefrom) as start_ate
from t
group by id;
You can try below query:
select id,max(current_designation) current_designation,min(date_first_employee) date_first_employee from
(select id,
max(case when EffectiveTo is null then designation end) over (partition by id) as current_designation,
(case when Designation='Trainee' then EffectiveFrom end) Date_First_Employee
from desig) t
group by id
Output:
This is another possilbe solution
SQL Fiddle
MySQL 5.6 Schema Setup:
CREATE TABLE table1
(`ID` int, `Designation` varchar(17), `EffectiveFrom` datetime, `EffectiveTo` varchar(10))
;
INSERT INTO table1
(`ID`, `Designation`, `EffectiveFrom`, `EffectiveTo`)
VALUES
(1, 'Trainee', '2000-01-01 01:00:00', '31/12/2000'),
(1, 'Assistant Manager', '2001-01-01 01:00:00', '31/12/2004'),
(1, 'Suspended', '2005-01-01 01:00:00', '01/02/2005'),
(1, 'Trainee', '2005-02-03 01:00:00', '31/03/2005'),
(1, 'Manager', '2005-01-04 01:00:00', NULL),
(2, 'Trainee', '2014-01-01 01:00:00', '31/12/2014'),
(2, 'Developer', '2015-01-01 01:00:00', '31/12/2016'),
(2, 'Architect', '2017-01-01 01:00:00', NULL)
;
Query 1:
SELECT
ID,
(SELECT
`Designation`
FROM
table1
WHERE
`EffectiveFrom` = (SELECT
MAX(`EffectiveFrom`)
FROM
table1
WHERE
ID = t1.ID)) AS `Current Designation`
,DATE(MIN(`EffectiveFrom`)) AS `Date First Employed`
FROM
table1 t1
GROUP BY ID
Results:
| ID | Current Designation | Date First Employed |
|----|---------------------|---------------------|
| 1 | Trainee | 2000-01-01 |
| 2 | Architect | 2014-01-01 |
It's actually a rather simple self-join assuming that the EffectiveFrom and EffectiveTo columns are always filled in appropriately (i.e. there's always only one NULL value for EffectiveTo of a given ID). Since it's possible for someone to be a Trainee twice, you also need to use a window function like ROW_NUMBER() to filter out only the earliest Traininee EffectiveFrom date:
WITH CTE_Designations AS
(
SELECT T1.ID, T1.Designation AS CurrentDesignation, ISNULL(T2.EffectiveFrom, T1.EffectiveFrom) AS DateFirstEmployed -- If the join fails below then that means the earliest Designation is in T1 (e.g. that is the 'Trainee' record)
FROM DesignationsTable AS T1
LEFT JOIN DesignationsTable AS T2
ON T1.ID = T2.ID
AND T1.Designation <> T2.Designation
AND T2.Designation = 'Trainee'
WHERE T1.EffectiveTo IS NULL
),
CTE_Designations_FirstEmployedOnly AS
(
SELECT ID, CurrentDesignation, DateFirstEmployed, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY DateFirstEmployed) AS SortId -- Generates a unique ID per DateFirstEmployed row for each Designation.ID sorted by DateFirstEmployed
FROM CTE_Designations
)
SELECT ID, CurrentDesignation, DateFirstEmployed
FROM CTE_Designations_FirstEmployedOnly
WHERE SortId = 1
Results per your example data:
Results if you had an additional person who was still a Trainee:
This returns the result shown for the given data
Solves for "current Designation(whose effectiveto is null) and the date where they FIRST joined". Also handles terminated employees where EffectiveTo is not NULL as well as new employees with a single row. Replace "#t" with your table name.
SELECT a.Id, d.Designation, a.EffectiveFrom
FROM
(SELECT *, ROW_NUMBER() OVER ( PARTITION BY Id ORDER BY EffectiveFrom ASC ) r FROM #t) a
INNER JOIN
(SELECT *, ROW_NUMBER() OVER ( PARTITION BY Id ORDER BY EffectiveFrom DESC ) r FROM #t) d
ON a.Id = d.Id
WHERE a.r = 1 AND d.r = 1
Result:
Id Designation EffectiveFrom
1 Manager 2000-01-01
2 Architect 2014-01-01
I'm having a issue with dates. I have a table with given from and to dates for an employee. For an evaluation, I'd like to display each date of the month with corresponding values from the second sql table.
SQL Table:
EmpNr | datefrom | dateto | hours
0815 | 01.01.2019 | 03.01.2019 | 15
0815 | 05.01.2019 | 15.01.2019 | 15
0815 | 20.01.2019 | 31.12.9999 | 40
The given employee (0815) worked during 01.01.-15.01. 15 hours, and during 20.01.-31.01. 40 hours
I'd like to have the following result:
0815 | 01.01.2019 | 15
0815 | 02.01.2019 | 15
0815 | 03.01.2019 | 15
0815 | 04.01.2019 | NULL
0815 | 05.01.2019 | 15
...
0815 | 15.01.2019 | 15
0815 | 16.01.2019 | NULL
0815 | 17.01.2019 | NULL
0815 | 18.01.2019 | NULL
0815 | 19.01.2019 | NULL
0815 | 20.01.2019 | 40
0815 | 21.01.2019 | 40
...
0815 | 31.01.2019 | 40
as for the dates, we have:
declare #year int = 2019, #month int = 1;
WITH numbers
as
(
Select 1 as value
UNion ALL
Select value + 1 from numbers
where value + 1 <= Day(EOMONTH(datefromparts(#year,#month,1)))
)
SELECT b.empnr, b.hours, datefromparts(#year,#month,numbers.value) Datum FROM numbers left outer join
emptbl b on b.empnr = '0815' and (datefromparts(#year,#month,numbers.value) >= b.datefrom and datefromparts(#year,#month,numbers.value) <= case b.dateto )
which is working quite well, yet I have the odd issue, that this code is only shoes the dates between 01.01.2019 and 03.01.2019
thank you very much in advance!
Did you check, if datefrom and dateto is in correct range?
Minimum value of DateTime field is 1753-01-01 and maximum value is 9999-12-31.
Look at your source table to check initial values.
The recursive CTE needs to begin with MIN(datefrom) and MAX(dateto):
DECLARE #t TABLE (empnr INT, datefrom DATE, dateto DATE, hours INT);
INSERT INTO #t VALUES
(815, '2019-01-01', '2019-01-03', 15),
(815, '2019-01-05', '2019-01-15', 15),
(815, '2019-01-20', '9999-01-01', 40),
-- another employee
(999, '2018-01-01', '2018-01-31', 15),
(999, '2018-03-01', '2018-03-31', 15),
(999, '2018-12-01', '9999-01-01', 40);
WITH rcte AS (
SELECT empnr
, MIN(datefrom) AS refdate
, ISNULL(NULLIF(MAX(dateto), '9999-01-01'), CURRENT_TIMESTAMP) AS maxdate -- clamp year 9999 to today
FROM #t
GROUP BY empnr
UNION ALL
SELECT empnr
, DATEADD(DAY, 1, refdate)
, maxdate
FROM rcte
WHERE refdate < maxdate
)
SELECT rcte.empnr
, rcte.refdate
, t.hours
FROM rcte
LEFT JOIN #t AS t ON rcte.empnr = t.empnr AND rcte.refdate BETWEEN t.datefrom AND t.dateto
ORDER BY rcte.empnr, rcte.refdate
OPTION (MAXRECURSION 1000) -- approx 3 years
Demo on db<>fiddle
It could be in your select, try:
SELECT b.empnr, b.hours, datefromparts(#year,#month,numbers.value) Datum
FROM numbers
LEFT OUTER JOIN emptbl b ON b.empnr = '0815' AND
datefromparts(#year,#month,numbers.value) BETWEEN b.datefrom AND b.dateto
Your CTE produces only 31 number and therefore it is showing only January dates.
declare #year int = 2019, #month int = 1;
WITH numbers
as
(
Select 1 as value
UNion ALL
Select value + 1 from numbers
where value + 1 <= Day(EOMONTH(datefromparts(#year,#month,1)))
)
SELECT *
FROM numbers
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=a24e58ef4ce522d3ec914f90907a0a9e
You can try below code,
with t0 (i) as (select 0 union all select 0 union all select 0),
t1 (i) as (select a.i from t0 a ,t0 b ),
t2 (i) as (select a.i from t1 a ,t1 b ),
t3 (srno) as (select row_number()over(order by a.i) from t2 a ,t2 b ),
tbldt(dt) as (select dateadd(day,t3.srno-1,'01/01/2019') from t3)
select tbldt.dt
from tbldt
where tbldt.dt <= b.dateto -- put your condition here
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b16469908b323b8d1b98d77dd09bab3d
I have a dataset with id ,Status and date range of employees.
The input dataset given below are the details of one employee.
The date ranges in the records are continuous(in exact order) such that startdate of second row will be the next date of enddate of first row.
If an employee takes leave continuously for different months, then the table is storing the info with date range as separated for different months.
For example: In the input set, the employee has taken Sick leave from '16-10-2016' to '31-12-2016' and joined back on '1-1-2017'.
So there are 3 records for this item but the dates are continuous.
In the output I need this as one record as shown in the expected output dataset.
INPUT
Id Status StartDate EndDate
1 Active 1-9-2007 15-10-2016
1 Sick 16-10-2016 31-10-2016
1 Sick 1-11-2016 30-11-2016
1 Sick 1-12-2016 31-12-2016
1 Active 1-1-2017 4-2-2017
1 Unpaid 5-2-2017 9-2-2017
1 Active 10-2-2017 11-2-2017
1 Unpaid 12-2-2017 28-2-2017
1 Unpaid 1-3-2017 31-3-2017
1 Unpaid 1-4-2017 30-4-2017
1 Active 1-5-2017 13-10-2017
1 Sick 14-10-2017 11-11-2017
1 Active 12-11-2017 NULL
EXPECTED OUTPUT
Id Status StartDate EndDate
1 Active 1-9-2007 15-10-2016
1 Sick 16-10-2016 31-12-2016
1 Active 1-1-2017 4-2-2017
1 Unpaid 5-2-2017 9-2-2017
1 Active 10-2-2017 11-2-2017
1 Unpaid 12-2-2017 30-4-2017
1 Active 1-5-2017 13-10-2017
1 Sick 14-10-2017 11-11-2017
1 Active 12-11-2017 NULL
I can't take min(startdate) and max(EndDate) group by id,status because if the same employee has taken another Sick leave then that end date ('11-11-2017' in the example) will come as the End date.
can anyone help me with the query in SQL server 2014?
It suddenly hit me that this is basically a gaps and islands problem - so I've completely changed my solution.
For this solution to work, the dates does not have to be consecutive.
First, create and populate sample table (Please save us this step in your future questions):
DECLARE #T AS TABLE
(
Id int,
Status varchar(10),
StartDate date,
EndDate date
);
SET DATEFORMAT DMY; -- This is needed because how you specified your dates.
INSERT INTO #T (Id, Status, StartDate, EndDate) VALUES
(1, 'Active', '1-9-2007', '15-10-2016'),
(1, 'Sick', '16-10-2016', '31-10-2016'),
(1, 'Sick', '1-11-2016', '30-11-2016'),
(1, 'Sick', '1-12-2016', '31-12-2016'),
(1, 'Active', '1-1-2017', '4-2-2017'),
(1, 'Unpaid', '5-2-2017', '9-2-2017'),
(1, 'Active', '10-2-2017', '11-2-2017'),
(1, 'Unpaid', '12-2-2017', '28-2-2017'),
(1, 'Unpaid', '1-3-2017', '31-3-2017'),
(1, 'Unpaid', '1-4-2017', '30-4-2017'),
(1, 'Active', '1-5-2017', '13-10-2017'),
(1, 'Sick', '14-10-2017', '11-11-2017'),
(1, 'Active', '12-11-2017', NULL);
The (new) common table expression:
;WITH CTE AS
(
SELECT Id,
Status,
StartDate,
EndDate,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY StartDate)
- ROW_NUMBER() OVER(PARTITION BY Id, Status ORDER BY StartDate) As IslandId,
ROW_NUMBER() OVER(PARTITION BY Id ORDER BY StartDate DESC)
- ROW_NUMBER() OVER(PARTITION BY Id, Status ORDER BY StartDate DESC) As ReverseIslandId
FROM #T
)
The (new) query:
SELECT DISTINCT Id,
Status,
MIN(StartDate) OVER(PARTITION BY IslandId, ReverseIslandId) As StartDate,
NULLIF(MAX(ISNULL(EndDate, '9999-12-31')) OVER(PARTITION BY IslandId, ReverseIslandId), '9999-12-31') As EndDate
FROM CTE
ORDER BY StartDate
(new) Results:
Id Status StartDate EndDate
1 Active 01.09.2007 15.10.2016
1 Sick 16.10.2016 31.12.2016
1 Active 01.01.2017 04.02.2017
1 Unpaid 05.02.2017 09.02.2017
1 Active 10.02.2017 11.02.2017
1 Unpaid 12.02.2017 30.04.2017
1 Active 01.05.2017 13.10.2017
1 Sick 14.10.2017 11.11.2017
1 Active 12.11.2017 NULL
You can see a live demo on rextester.
Please note that string representation of dates in SQL should be acccording to ISO 8601 - meaning either yyyy-MM-dd or yyyyMMdd as it's unambiguous and will always be interpreted correctly by SQL Server.
It's an example of GROUPING AND WINDOW.
First you set a reset point for each Status
Sum to set a group
Then get max/min dates of each group.
;with x as
(
select Id, Status, StartDate, EndDate,
iif (lag(Status) over (order by Id, StartDate) = Status, null, 1) rst
from emp
), y as
(
select Id, Status, StartDate, EndDate,
sum(rst) over (order by Id, StartDate) grp
from x
)
select Id,
MIN(Status) as Status,
MIN(StartDate) StartDate,
MAX(EndDate) EndDate
from y
group by Id, grp
order by Id, grp
GO
Id | Status | StartDate | EndDate
-: | :----- | :------------------ | :------------------
1 | Active | 01/09/2007 00:00:00 | 15/10/2016 00:00:00
1 | Sick | 16/10/2016 00:00:00 | 31/12/2016 00:00:00
1 | Active | 01/01/2017 00:00:00 | 04/02/2017 00:00:00
1 | Unpaid | 05/02/2017 00:00:00 | 09/02/2017 00:00:00
1 | Active | 10/02/2017 00:00:00 | 11/02/2017 00:00:00
1 | Unpaid | 12/02/2017 00:00:00 | 30/04/2017 00:00:00
1 | Active | 01/05/2017 00:00:00 | 13/10/2017 00:00:00
1 | Sick | 14/10/2017 00:00:00 | 11/11/2017 00:00:00
1 | Active | 12/11/2017 00:00:00 | null
dbfiddle here
Here's an alternative answer that doesn't use LAG.
First I need to take a copy of your test data:
DECLARE #table TABLE (Id INT, [Status] VARCHAR(50), StartDate DATE, EndDate DATE);
INSERT INTO #table SELECT 1, 'Active', '20070901', '20161015';
INSERT INTO #table SELECT 1, 'Sick', '20161016', '20161031';
INSERT INTO #table SELECT 1, 'Sick', '20161101', '20161130';
INSERT INTO #table SELECT 1, 'Sick', '20161201', '20161231';
INSERT INTO #table SELECT 1, 'Active', '20170101', '20170204';
INSERT INTO #table SELECT 1, 'Unpaid', '20170205', '20170209';
INSERT INTO #table SELECT 1, 'Active', '20170210', '20170211';
INSERT INTO #table SELECT 1, 'Unpaid', '20170212', '20170228';
INSERT INTO #table SELECT 1, 'Unpaid', '20170301', '20170331';
INSERT INTO #table SELECT 1, 'Unpaid', '20170401', '20170430';
INSERT INTO #table SELECT 1, 'Active', '20170501', '20171013';
INSERT INTO #table SELECT 1, 'Sick', '20171014', '20171111';
INSERT INTO #table SELECT 1, 'Active', '20171112', NULL;
Then the query is:
WITH add_order AS (
SELECT
*,
ROW_NUMBER() OVER (ORDER BY StartDate) AS order_id
FROM
#table),
links AS (
SELECT
a1.Id,
a1.[Status],
a1.order_id,
MIN(a1.order_id) AS start_order_id,
MAX(ISNULL(a2.order_id, a1.order_id)) AS end_order_id,
MIN(a1.StartDate) AS StartDate,
MAX(ISNULL(a2.EndDate, a1.EndDate)) AS EndDate
FROM
add_order a1
LEFT JOIN add_order a2 ON a2.Id = a1.Id AND a2.[Status] = a1.[Status] AND a2.order_id = a1.order_id + 1 AND a2.StartDate = DATEADD(DAY, 1, a1.EndDate)
GROUP BY
a1.Id,
a1.[Status],
a1.order_id),
merged AS (
SELECT
l1.Id,
l1.[Status],
l1.[StartDate],
ISNULL(l2.EndDate, l1.EndDate) AS EndDate,
ROW_NUMBER() OVER (PARTITION BY l1.Id, l1.[Status], ISNULL(l2.EndDate, l1.EndDate) ORDER BY l1.order_id) AS link_id
FROM
links l1
LEFT JOIN links l2 ON l2.order_id = l1.end_order_id)
SELECT
Id,
[Status],
StartDate,
EndDate
FROM
merged
WHERE
link_id = 1
ORDER BY
StartDate;
Results are:
Id Status StartDate EndDate
1 Active 2007-09-01 2016-10-15
1 Sick 2016-10-16 2016-12-31
1 Active 2017-01-01 2017-02-04
1 Unpaid 2017-02-05 2017-02-09
1 Active 2017-02-10 2017-02-11
1 Unpaid 2017-02-12 2017-04-30
1 Active 2017-05-01 2017-10-13
1 Sick 2017-10-14 2017-11-11
1 Active 2017-11-12 NULL
How does it work? First I add a sequence number, to assist with merging contiguous rows together. Then I determine the rows that can be merged together, add a number to identify the first row in each set that can be merged, and finally pick the first rows out of the final CTE. Note that I also have to handle rows that can't be merged, hence the LEFT JOINs and ISNULL statements.
Just for interest, this is what the output from the final CTE looks like, before I filter out all but the rows with a link_id of 1:
Id Status StartDate EndDate link_id
1 Active 2007-09-01 2016-10-15 1
1 Sick 2016-10-16 2016-12-31 1
1 Sick 2016-11-01 2016-12-31 2
1 Sick 2016-12-01 2016-12-31 3
1 Active 2017-01-01 2017-02-04 1
1 Unpaid 2017-02-05 2017-02-09 1
1 Active 2017-02-10 2017-02-11 1
1 Unpaid 2017-02-12 2017-04-30 1
1 Unpaid 2017-03-01 2017-04-30 2
1 Unpaid 2017-04-01 2017-04-30 3
1 Active 2017-05-01 2017-10-13 1
1 Sick 2017-10-14 2017-11-11 1
1 Active 2017-11-12 NULL 1
You could use lag() and lead() function together to check the previous and next status
WITH CTE AS
(
select *,
COALESCE(LEAD(status) OVER(ORDER BY (select 1)), '0') Nstatus,
COALESCE(LAG(status) OVER(ORDER BY (select 1)), '0') Pstatus
from table
)
SELECT * FROM CTE
WHERE (status <> Nstatus AND status <> Pstatus) OR
(status <> Pstatus)
We have a table, lets call it "source-table", from where I retrieve these columns like this;
ANr, TNr, Type, IDate, EDate
1132173, 113615, Bogus, 2017-09-11 13:01:00, 2017-09-13 14:10:00
1132145, 184210, Triss, 2017-09-11 13:05:00, 2017-09-13 14:10:00
1131828, 259858, Bogus, 2017-09-11 13:11:00, 2017-09-13 14:10:00
1131844, 259858, Bogus, 2017-09-11 13:11:00, 2017-09-13 14:10:00
The above result is going to a new table called "export-table" and I then want to do a select from a third table, "info-table" but only with those just inserted in "export-table" and with a Count on how many duplicated entries if any (besides Anr which always is unique)
With the select mention above I want the following result:
Customernr, ANr, IDate, Type, Amount
703524, 1132173,2017-09-11 13:01:00, Bogus, 1
756899, 1132145,2017-09-11 13:05:00, Triss, 1
356658, 1131828,2017-09-11 13:11:00, Bogus, 2
Customernr comes from the "info-table", which has ANr as unique key.
As you can see the last two rows from "source-table" is identical besides Anr, but I need Anr later to get correct values from "info-table". It might work without Anr, if I can do a search on "info-table" with both Tnr and IDate, but I'll get duplicate entries there as well so not sure if that helps.
If someone wonder why the "export-table", then it is a kind of fail-safe so I wont export same stuff more than once.
I've been searching but since it is a bit complex question I haven't found a complete solution or any good hints.
how you did not put the customer, the best I can help you is
DECLARE #t table
(
ANr int
,TNr int
, Type varchar(10)
, IDate datetime
, EDate Datetime
)
insert #t (ANr, TNr, Type, IDate, EDate) values
(1132173, 113615, 'Bogus', '2017-09-11 13:01:00', '2017-09-13 14:10:00')
,(1132145, 184210, 'Triss', '2017-09-11 13:05:00', '2017-09-13 14:10:00')
,(1131828, 259858, 'Bogus', '2017-09-11 13:11:00', '2017-09-13 14:10:00')
,(1131844, 259858, 'Bogus', '2017-09-11 13:11:00', '2017-09-13 14:10:00')
Select Distinct
TNr
,IDate
,Type
,COUNT(1) OVER (PARTITION BY TNr, Type, IDATE)
from #t
Result
TNr IDate Type
----------- ----------------------- ---------- -----------
113615 2017-09-11 13:01:00.000 Bogus 1
184210 2017-09-11 13:05:00.000 Triss 1
259858 2017-09-11 13:11:00.000 Bogus 2
You can query as below:
Select top (1) with ties ANr, Idate, [Type], Count(*) over(partition by TNr, [Type], Idate) from
#sourcetable
order by row_number() over(partition by TNr, [Type], Idate order by Anr)
But not sure how you got Customernr
Output as below:
+---------+-------------------------+-------+--------+
| ANr | Idate | Type | Amount |
+---------+-------------------------+-------+--------+
| 1132173 | 2017-09-11 13:01:00.000 | Bogus | 1 |
| 1132145 | 2017-09-11 13:05:00.000 | Triss | 1 |
| 1131828 | 2017-09-11 13:11:00.000 | Bogus | 2 |
+---------+-------------------------+-------+--------+
You can use sub query for getting row_number as below
Select * from (
Select ANr, Idate, [Type], Amount = Count(*) over(partition by TNr, [Type], Idate)
,RowN = row_number() over(partition by TNr, [Type], Idate order by Anr)
from #sourcetable ) a
Where a.RowN = 1
DECLARE #t TABLE(ANr int, TNr int, Type NVARCHAR(100), IDate DATETIME, EDate DATETIME);
INSERT INTO #t VALUES
(1132173, 113615, 'Bogus', '2017-09-11 13:01:00', '2017-09-13 14:10:00')
,(1132145, 184210, 'Triss', '2017-09-11 13:05:00', '2017-09-13 14:10:00')
,(1131828, 259858, 'Bogus', '2017-09-11 13:11:00', '2017-09-13 14:10:00')
,(1131844, 259858, 'Bogus', '2017-09-11 13:11:00', '2017-09-13 14:10:00');
SELECT MIN(ANr) ANr, TNr, IDate, EDate, COUNT(*) AS Anz
FROM #t
GROUP BY TNr, IDate, EDate
I have a problem in writing a query.
I'd like to select the first row of each set of rows grouped
My table is Transactions:
userID | Date | StoreID
---------------------------
1 | 8-9-2013 | 10
1 | 9-9-2013 | 10
1 | 10-9-2013| 20
2 | 7-9-2013 | 30
2 | 8-9-2013 | 10
2 | 9-9-2013 | 20
1 | 11-9-2013| 10
2 | 10-9-2013| 20
and I try to this SQL statement:
Select
tr.userID , Min(tr.TransactionDate) FirstDate
From
Transactions tr
Group By
tr.userID
I get this output:
userID | Date
------------------
1 | 8-9-2013
2 | 7-9-2013
But I need the Store ID in every first transaction.
I need it to be like that
userID | Date | StoreID
-------------------------
1 | 8-9-2013 | 10
2 | 7-9-2013 | 30
Please any one can help me
You could use Row_Number().
select UserId, Date, StoreId from (select row_number() over(partition
by UserId order by date) as RowNumber, UserId, Date, StoreId from
Transactions ) as View1 where RowNumber = 1
http://sqlfiddle.com/#!6/e536a/7
You could use a sub-query
SELECT TR1.userID
,TR1.TransactionDate
,TR1.StoreID
FROM Transactions tr1
INNER JOIN
(
Select
tr.userID
,Min(tr.TransactionDate) AS FirstDate
From
Transactions tr
Group By
tr.userID
) SQ
ON TR1.userID = SQ.userID
AND TR1.TransactionDate = SQ.FirstDate
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Transactions
([userID] int, [Date] datetime, [StoreID] int)
;
INSERT INTO Transactions
([userID], [Date], [StoreID])
VALUES
(1, '2013-08-09 00:00:00', 10),
(1, '2013-09-09 00:00:00', 10),
(1, '2013-10-09 00:00:00', 20),
(2, '2013-07-09 00:00:00', 30),
(2, '2013-08-09 00:00:00', 10),
(2, '2013-09-09 00:00:00', 20),
(1, '2013-11-09 00:00:00', 10),
(2, '2013-10-09 00:00:00', 20)
;
Query 1:
SELECT
tr.userID , Min(tr.Date) FirstDate , tr2.storeid
FROM
Transactions tr
inner join Transactions tr2 on tr.userid = tr2.userid and
tr2.date = (select top 1 date
from transactions t
where t.userid = tr2.userid
order by date asc)
GROUP BY
tr.userID, tr2.storeid
Results:
| USERID | FIRSTDATE | STOREID |
|--------|-------------------------------|---------|
| 1 | August, 09 2013 00:00:00+0000 | 10 |
| 2 | July, 09 2013 00:00:00+0000 | 30 |
with user_cte (userid,date)
as(Select tr.userID , Min(tr.TransactionDate) FirstDate
From Transactions tr
Group By tr.userID
)
select b.userid,b.date,a.storeId from Transactions a join user_cte b on a.userID=b.userId and a.Date=b.Date
You can do this with a subquery. The basic principle is that the subquery identifies the min date for each one, and the wrapping query picks the row that matches the user and min date, also being able to return the store id.
It would look something like this:
SELECT
t.UserID,
t.Date,
t.StoreId
FROM
Transactions t JOIN
(
SELECT
tr.userID , Min(tr.Date) AS FirstDate
FROM
Transactions tr
GROUP BY
tr.userID
) u ON t.UserId = u.UserId AND t.Date = u.FirstDate
You can check this out yourself in SqlFiddle here.