Cluskitt
asked on
Tricky T-SQL query
This relates to this question: https://www.experts-exchange.com/questions/27941861/Tricky-query-for-both-T-SQL-and-Access.html
So, to explain this better and to use real table/field names:
I have this table that has a composite ID and two date fields which compose a range:
tblTrabalho(FK_ID_intEmpre sa int,FK_ID_intFuncionario int,FK_ID_intTipoTrabalho uniqueidentifier,datHoraEn tradaTraba lho smalldatetime,datHoraSaida Trabalho smalldatetime)
If necessary, I also have a Calendar table which has all days for 2000-2025, in case joining is necessary.
So, what I need is a list of each FK_ID_intEmpresa,FK_ID_int Funcionari o that has a 30 day (really 30 days, not a month) period regardless of FK_ID_intTipoTrabalho. However, I need to have start and end dates (datHoraEntradaTrabalho and datHoraSaidaTrabalho) for each FK_ID_intTipoTrabalho in said range. A few examples can be found on the link, but I'm posting a real data sample and expected result.
Data:
So, exactly what is supposed to happen?
1- The query should pick up any uninterrupted 30 day period for each FK_ID_intEmpresa,FK_ID_int Funcionari o, no matter which FK_ID_intTipoTrabalho it is.
2- Once this period is found, it has to display it, grouping by FK_ID_intTipoTrabalho but respecting the calendar. That is, if you have, for a particular FK_ID_intEmpresa,FK_ID_int Funcionari o:
A 2012-01-01 2012-01-31
B 2012-02-01 2012-02-29
A 2012-03-01 2012-03-02
Then this is exactly what it has to show. Even though the last one is only 2 days long, the overall is still within the range. I call your attention to the case for FK_ID_intFuncionario=542, which illustrates this case. I only used this example to show that you can't just group all rows of the same type because the order must be maintained.
If you have any further questions, I'll be happy to explain.
Thanks in advance for the effort.
So, to explain this better and to use real table/field names:
I have this table that has a composite ID and two date fields which compose a range:
tblTrabalho(FK_ID_intEmpre
If necessary, I also have a Calendar table which has all days for 2000-2025, in case joining is necessary.
So, what I need is a list of each FK_ID_intEmpresa,FK_ID_int
Data:
fk_id_intempresa	fk_id_intfuncionario	fk_id_inttipotrabalho	dathoraentradatrabalho	dathorasaidatrabalho
41	177	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-11-09 00:00:00	2010-11-12 00:00:00
41	177	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-16 00:00:00	2011-05-22 00:00:00
41	177	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-09-12 00:00:00	2012-09-14 00:00:00
41	177	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-09-15 00:00:00	2012-09-18 00:00:00
41	275	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-08-31 00:00:00	2011-09-30 00:00:00
41	275	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-10-01 00:00:00	2011-10-30 00:00:00
41	275	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-10-31 00:00:00	2011-11-29 00:00:00
41	275	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-11-30 00:00:00	2011-12-29 00:00:00
41	275	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-12-30 00:00:00	2012-01-28 00:00:00
41	275	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-01-29 00:00:00	2012-02-27 00:00:00
41	294	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-12-01 00:00:00	2011-12-30 00:00:00
41	294	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-12-31 00:00:00	2012-01-29 00:00:00
41	294	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-01-30 00:00:00	2012-02-29 00:00:00
41	294	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-03-01 00:00:00	2012-03-29 00:00:00
41	542	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-02-02 00:00:00	2010-02-21 00:00:00
41	542	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2010-02-22 00:00:00	2010-03-10 00:00:00
41	542	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-07-07 00:00:00	2010-07-13 00:00:00
41	542	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-10-18 00:00:00	2010-11-26 00:00:00
41	542	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2010-12-22 00:00:00	2010-12-31 00:00:00
41	542	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2011-01-01 00:00:00	2011-04-06 00:00:00
41	542	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-05 00:00:00	2011-12-05 00:00:00
41	542	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-23 00:00:00	2012-01-23 00:00:00
41	542	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-04-28 00:00:00	2012-04-29 00:00:00
41	609	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-09-18 00:00:00	2010-09-20 00:00:00
41	609	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-10-15 00:00:00	2010-10-31 00:00:00
41	609	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-01-01 00:00:00	2011-01-03 00:00:00
41	609	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-08 00:00:00	2011-02-15 00:00:00
41	609	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-07-25 00:00:00	2011-07-31 00:00:00
41	609	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-21 00:00:00	2011-11-21 00:00:00
41	609	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-28 00:00:00	2011-11-28 00:00:00
41	625	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-09 00:00:00	2011-12-09 00:00:00
41	625	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-05 00:00:00	2012-01-05 00:00:00
41	636	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-04-12 00:00:00	2011-04-27 00:00:00
41	636	18187308-A0CD-4A06-B5D1-1E7CF2911120	2011-07-04 00:00:00	2011-07-30 00:00:00
41	646	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-01-14 00:00:00	2010-01-25 00:00:00
41	646	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-03-19 00:00:00	2010-03-23 00:00:00
41	646	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-05-08 00:00:00	2010-05-16 00:00:00
41	646	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-06-15 00:00:00	2011-07-03 00:00:00
41	646	18187308-A0CD-4A06-B5D1-1E7CF2911120	2011-11-05 00:00:00	2011-11-30 00:00:00
41	646	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-07 00:00:00	2011-12-07 00:00:00
41	646	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-16 00:00:00	2011-12-16 00:00:00
41	646	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-23 00:00:00	2011-12-23 00:00:00
41	646	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-29 00:00:00	2011-12-29 00:00:00
41	646	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-05 00:00:00	2012-01-05 00:00:00
41	646	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-28 00:00:00	2012-01-28 00:00:00
41	646	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-02-17 00:00:00	2012-02-22 00:00:00
41	646	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-02-23 00:00:00	2012-02-26 00:00:00
41	824	3A1F0A86-34E5-4BB8-98A3-11DA752484E3	2012-09-10 00:00:00	2012-09-24 00:00:00
41	879	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-26 00:00:00	2012-01-26 00:00:00
41	879	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-01-27 00:00:00	2012-01-29 00:00:00
41	903	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-09-06 00:00:00	2010-09-13 00:00:00
41	903	C5DD9F42-300B-45AD-AFCC-B9815D1D7AEF	2011-03-09 00:00:00	2011-03-11 00:00:00
41	903	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-12-30 00:00:00	2012-01-10 00:00:00
41	903	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-24 00:00:00	2012-01-24 00:00:00
41	903	C5DD9F42-300B-45AD-AFCC-B9815D1D7AEF	2012-04-15 00:00:00	2012-04-17 00:00:00
41	919	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-10-28 00:00:00	2010-11-07 00:00:00
41	919	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-06-18 00:00:00	2012-06-29 00:00:00
41	919	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-06-30 00:00:00	2012-07-26 00:00:00
41	919	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-07-27 00:00:00	2012-07-29 00:00:00
41	919	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-07-30 00:00:00	2012-08-29 00:00:00
41	919	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-08-30 00:00:00	2012-09-29 00:00:00
41	919	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-09-30 00:00:00	2012-10-29 00:00:00
41	919	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-10-30 00:00:00	2012-11-26 00:00:00
41	926	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-02-03 00:00:00	2010-02-10 00:00:00
41	939	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-06-23 00:00:00	2011-06-30 00:00:00
41	939	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-03-08 00:00:00	2012-03-13 00:00:00
41	939	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-08-17 00:00:00	2012-08-19 00:00:00
41	999	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-16 00:00:00	2012-01-16 00:00:00
41	1047	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-03-01 00:00:00	2011-03-08 00:00:00
41	1055	B4FB2460-330E-4C62-B7DF-73710F85D462	2010-12-18 00:00:00	2010-12-25 00:00:00
41	1055	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-01-04 00:00:00	2011-01-05 00:00:00
41	1055	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-01-07 00:00:00	2011-01-07 00:00:00
41	1055	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-01-10 00:00:00	2011-01-10 00:00:00
41	1055	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-01-18 00:00:00	2011-01-18 00:00:00
41	1060	B4FB2460-330E-4C62-B7DF-73710F85D462	2010-12-29 00:00:00	2010-12-31 00:00:00
41	1060	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-01-01 00:00:00	2011-01-11 00:00:00
41	1060	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-26 00:00:00	2011-11-26 00:00:00
41	1060	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-03 00:00:00	2011-12-03 00:00:00
41	1060	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-10 00:00:00	2011-12-10 00:00:00
41	1060	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-17 00:00:00	2011-12-17 00:00:00
41	1071	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-06-10 00:00:00	2010-06-18 00:00:00
41	1071	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-10-06 00:00:00	2011-10-27 00:00:00
41	1103	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-11-10 00:00:00	2010-11-21 00:00:00
41	1103	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-24 00:00:00	2011-03-08 00:00:00
41	1103	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-06-20 00:00:00	2011-06-24 00:00:00
41	1103	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-02-08 00:00:00	2012-02-19 00:00:00
41	1103	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-02-20 00:00:00	2012-02-24 00:00:00
41	1169	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-21 00:00:00	2011-12-21 00:00:00
41	1214	B4FB2460-330E-4C62-B7DF-73710F85D462	2010-03-29 00:00:00	2010-04-02 00:00:00
41	1229	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-01-01 00:00:00	2010-01-01 00:00:00
41	1229	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-09-20 00:00:00	2012-09-30 00:00:00
41	1229	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-10-01 00:00:00	2012-10-03 00:00:00
41	1229	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-11-05 00:00:00	2012-11-11 00:00:00
41	1229	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-11-19 00:00:00	2012-11-25 00:00:00
41	1240	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-05-24 00:00:00	2012-05-25 00:00:00
41	1240	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-05-28 00:00:00	2012-05-30 00:00:00
41	1260	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-21 00:00:00	2011-11-21 00:00:00
41	1260	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-03 00:00:00	2011-12-03 00:00:00
41	1260	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-31 00:00:00	2011-12-31 00:00:00
41	1260	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-25 00:00:00	2012-01-25 00:00:00
41	1261	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-07-08 00:00:00	2010-07-11 00:00:00
41	1261	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-01-26 00:00:00	2011-01-31 00:00:00
41	1261	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-05 00:00:00	2011-02-11 00:00:00
41	1261	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-15 00:00:00	2011-02-20 00:00:00
41	1264	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-07-29 00:00:00	2010-08-06 00:00:00
41	1265	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-05-26 00:00:00	2010-06-06 00:00:00
41	1265	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-31 00:00:00	2011-12-31 00:00:00
41	1265	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-01-31 00:00:00	2012-02-07 00:00:00
41	1269	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-04-05 00:00:00	2010-04-09 00:00:00
41	1269	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-07-29 00:00:00	2010-08-09 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-21 00:00:00	2011-11-21 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-22 00:00:00	2011-11-22 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-19 00:00:00	2011-12-19 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-27 00:00:00	2011-12-27 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-03 00:00:00	2012-01-03 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-24 00:00:00	2012-01-24 00:00:00
41	1275	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-29 00:00:00	2012-01-29 00:00:00
41	1275	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-05-25 00:00:00	2012-05-31 00:00:00
41	1276	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-10-18 00:00:00	2010-10-18 00:00:00
41	1276	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-12-20 00:00:00	2010-12-24 00:00:00
41	1282	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-27 00:00:00	2012-01-27 00:00:00
41	1282	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-28 00:00:00	2012-01-28 00:00:00
41	1282	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-09-24 00:00:00	2012-09-28 00:00:00
41	1287	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-11-06 00:00:00	2010-11-12 00:00:00
41	1287	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-12-10 00:00:00	2010-12-14 00:00:00
41	1287	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-01-03 00:00:00	2011-01-10 00:00:00
41	1303	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-07-04 00:00:00	2010-07-08 00:00:00
41	1311	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2011-07-12 00:00:00	2011-07-18 00:00:00
41	1311	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-12 00:00:00	2011-12-12 00:00:00
41	1311	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-03-20 00:00:00	2012-03-21 00:00:00
41	1314	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-08-01 00:00:00	2011-08-12 00:00:00
41	1314	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-03 00:00:00	2011-12-03 00:00:00
41	1314	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-23 00:00:00	2011-12-23 00:00:00
41	1320	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-16 00:00:00	2011-02-27 00:00:00
41	1322	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-03 00:00:00	2012-01-03 00:00:00
41	1322	C3B87B60-0205-43D2-9356-ADE88304A9C4	2012-01-06 00:00:00	2012-01-06 00:00:00
41	1322	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-07 00:00:00	2012-01-07 00:00:00
41	1322	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-08 00:00:00	2012-01-08 00:00:00
41	1326	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-03-20 00:00:00	2011-03-25 00:00:00
41	1327	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-09-19 00:00:00	2011-09-23 00:00:00
41	1327	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-21 00:00:00	2011-11-21 00:00:00
41	1327	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-02 00:00:00	2011-12-02 00:00:00
41	1327	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-27 00:00:00	2011-12-27 00:00:00
41	1327	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-04 00:00:00	2012-01-04 00:00:00
41	1330	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2011-04-01 00:00:00	2011-04-06 00:00:00
41	1332	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-12-17 00:00:00	2010-12-19 00:00:00
41	1341	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-09-13 00:00:00	2010-09-18 00:00:00
41	1350	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-01-20 00:00:00	2011-01-25 00:00:00
41	1351	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-11-10 00:00:00	2010-12-07 00:00:00
41	1351	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2010-12-08 00:00:00	2010-12-21 00:00:00
41	1355	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-04-04 00:00:00	2011-04-09 00:00:00
41	1356	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-05-01 00:00:00	2011-05-12 00:00:00
41	1356	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-10-01 00:00:00	2011-10-05 00:00:00
41	1357	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-27 00:00:00	2011-02-28 00:00:00
41	1357	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-03-24 00:00:00	2011-03-30 00:00:00
41	1357	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-04-16 00:00:00	2011-04-22 00:00:00
41	1362	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-16 00:00:00	2012-01-16 00:00:00
41	1363	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-02 00:00:00	2012-01-02 00:00:00
41	1367	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-15 00:00:00	2011-12-15 00:00:00
41	1374	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-16 00:00:00	2012-01-16 00:00:00
41	1374	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-23 00:00:00	2012-01-23 00:00:00
41	1375	C5DD9F42-300B-45AD-AFCC-B9815D1D7AEF	2011-03-01 00:00:00	2011-03-03 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-04-26 00:00:00	2011-05-01 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-11-21 00:00:00	2011-12-19 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-12-20 00:00:00	2012-01-18 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-01-19 00:00:00	2012-01-20 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-01-21 00:00:00	2012-02-09 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-02-10 00:00:00	2012-02-18 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-02-19 00:00:00	2012-03-10 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-03-11 00:00:00	2012-03-19 00:00:00
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-03-20 00:00:00	2012-03-28 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-03-29 00:00:00	2012-03-30 00:00:00
41	1375	7A375D2F-5471-4446-8E00-B32B7EAC9839	2012-04-01 00:00:00	2012-04-05 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-04-06 00:00:00	2012-04-18 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-04-19 00:00:00	2012-05-18 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-05-19 00:00:00	2012-06-17 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-06-18 00:00:00	2012-07-17 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-07-18 00:00:00	2012-08-16 00:00:00
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-08-17 00:00:00	2012-09-01 00:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-15 14:45:00	2012-10-15 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-16 14:45:00	2012-10-16 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-18 14:45:00	2012-10-18 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-20 14:45:00	2012-10-20 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-22 14:45:00	2012-10-22 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-23 14:45:00	2012-10-23 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-25 14:45:00	2012-10-25 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-26 14:45:00	2012-10-26 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-29 14:45:00	2012-10-29 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-10-30 14:45:00	2012-10-30 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-01 14:49:00	2012-11-01 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-02 14:46:00	2012-11-02 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-03 14:47:00	2012-11-03 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-05 14:45:00	2012-11-05 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-06 14:46:00	2012-11-06 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-08 14:45:00	2012-11-08 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-09 14:50:00	2012-11-09 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-10 14:45:00	2012-11-10 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-12 14:45:00	2012-11-12 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-13 14:53:00	2012-11-13 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-14 14:47:00	2012-11-14 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-15 14:47:00	2012-11-15 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-16 14:45:00	2012-11-16 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-19 14:45:00	2012-11-19 16:00:00
41	1375	9B36C78F-CAAF-44FB-9E41-7C10994E5C39	2012-11-20 14:45:00	2012-11-20 16:00:00
41	1381	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-12 00:00:00	2011-12-12 00:00:00
41	1381	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-16 00:00:00	2011-12-16 00:00:00
41	1381	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-29 00:00:00	2011-12-29 00:00:00
41	1382	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-12-13 00:00:00	2011-12-13 00:00:00
41	1382	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-24 00:00:00	2012-01-24 00:00:00
41	1382	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-05-18 00:00:00	2012-05-25 00:00:00
41	1382	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-05-26 00:00:00	2012-05-27 00:00:00
41	1382	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-07-11 00:00:00	2012-07-18 00:00:00
41	1382	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-08-17 00:00:00	2012-08-19 00:00:00
41	1385	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2011-11-30 00:00:00	2011-11-30 00:00:00
41	1385	5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C	2012-01-24 00:00:00	2012-01-24 00:00:00
41	1387	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-08-19 00:00:00	2011-08-21 00:00:00
41	1391	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-08-20 00:00:00	2011-08-27 00:00:00
Expected resultsFK_ID_intEmpresa	FK_ID_intFuncionario	FK_ID_intTipoTrabalho	datHoraEntradaTrabalho	datHoraSaidaTrabalho	Total
41	177	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-02-16 00:00:00	2011-05-22 00:00:00	96
41	275	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-08-31 00:00:00	2011-09-30 00:00:00	31
41	275	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-10-01 00:00:00	2012-02-27 00:00:00	150
41	294	B4FB2460-330E-4C62-B7DF-73710F85D462	2011-12-01 00:00:00	2012-03-29 00:00:00	120
41	542	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-02-02 00:00:00	2010-02-21 00:00:00	20
41	542	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2010-02-22 00:00:00	2010-03-10 00:00:00	17
41	542	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2010-12-22 00:00:00	2011-04-06 00:00:00	106
41	919	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2012-06-18 00:00:00	2012-07-26 00:00:00	39
41	919	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-07-27 00:00:00	2012-11-26 00:00:00	123
41	1351	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2010-11-10 00:00:00	2010-12-07 00:00:00	28
41	1351	8E5E8121-5CC7-42BD-A57F-B20DDD334B24	2010-12-08 00:00:00	2010-12-21 00:00:00	14
41	1375	0FC911AD-29E7-4F15-A2A5-AD4D629F30FF	2011-11-21 00:00:00	2012-03-30 00:00:00	131
41	1375	B4FB2460-330E-4C62-B7DF-73710F85D462	2012-04-06 00:00:00	2012-09-01 00:00:00	149
So, exactly what is supposed to happen?
1- The query should pick up any uninterrupted 30 day period for each FK_ID_intEmpresa,FK_ID_int
2- Once this period is found, it has to display it, grouping by FK_ID_intTipoTrabalho but respecting the calendar. That is, if you have, for a particular FK_ID_intEmpresa,FK_ID_int
A 2012-01-01 2012-01-31
B 2012-02-01 2012-02-29
A 2012-03-01 2012-03-02
Then this is exactly what it has to show. Even though the last one is only 2 days long, the overall is still within the range. I call your attention to the case for FK_ID_intFuncionario=542, which illustrates this case. I only used this example to show that you can't just group all rows of the same type because the order must be maintained.
If you have any further questions, I'll be happy to explain.
Thanks in advance for the effort.
ASKER
I need ranges that are AT LEAST 30 days long. Shouldn't be much of a problem to adapt, but I can't quite see how to apply this to my problem, so it checks for valid ranges for each FK_ID_intEmpresa,FK_ID_int Funcionari o and then presents the grouped results as explained above. I suppose you could adapt this so you'd include the IDs in the CTE, but how to present them? That, to me, is the biggest problem.
Using the calendar table (field name is CalendarDate, btw), I can see any running 30 days or over range. But each range may have multiple FK_ID_intTipoTrabalho, which needs to be returned.
Using the calendar table (field name is CalendarDate, btw), I can see any running 30 days or over range. But each range may have multiple FK_ID_intTipoTrabalho, which needs to be returned.
I'm confused by '..regardless of FK_ID_intTipoTrabalho'
so you want to find any run of 30 days or more, for all FK_ID_intTipoTrabalho combined, but then in that run, you want all of the FK_ID_intTipoTrabalho that are in it?
so once you've made the CTE with
0
0
1
1
.
.
.
1
1
1
1
0
you can work out the dif's between successive days
then where you have a 1 (a run starts), you can find the next -1 (a run ends) and check if it is over 30. If it is over the 30, then you have a start date and an end date of the run, so you can find and IDs that are in that run
so you want to find any run of 30 days or more, for all FK_ID_intTipoTrabalho combined, but then in that run, you want all of the FK_ID_intTipoTrabalho that are in it?
so once you've made the CTE with
0
0
1
1
.
.
.
1
1
1
1
0
you can work out the dif's between successive days
then where you have a 1 (a run starts), you can find the next -1 (a run ends) and check if it is over 30. If it is over the 30, then you have a start date and an end date of the run, so you can find and IDs that are in that run
ASKER
Yes. But my problem is also grouping them, as explained above. That is, if I have, for a specific ID COLUMNS (FK_ID_intTipoTrabalho, datHoraEntradaTrabalho, datHoraSaidaTrabalho)
A 2012-01-01 2012-01-10
B 2012-01-11 2012-01-20
B 2012-01-21 2012-02-10
A 2012-02-11 2012-02-25
A 2012-02-26 2012-02-29
I can identify the run as starting at 2012-01-01 and ending at 2012-02-29. But what I want returned is:
A 2012-01-01 2012-01-10 10
B 2012-01-11 2012-02-10 31
A 2012-02-11 2012-02-29 19
A 2012-01-01 2012-01-10
B 2012-01-11 2012-01-20
B 2012-01-21 2012-02-10
A 2012-02-11 2012-02-25
A 2012-02-26 2012-02-29
I can identify the run as starting at 2012-01-01 and ending at 2012-02-29. But what I want returned is:
A 2012-01-01 2012-01-10 10
B 2012-01-11 2012-02-10 31
A 2012-02-11 2012-02-29 19
once you have a start or end date for each run over 30, you should be able to query each start and end time appearing between those dates, using a further CTE and exists.
ASKER
I don't think you're quite understanding. Whether I use your solution or whether I use an inner join with Calendar and check for counts of 30+ where not exists any calendardate in between, I can get the results. My main issue is getting the results grouped as in my last post. To get those 5 rows into those 3. I have many cases where there are entries of 1 day each running for a period of over 40 days. I don't want 40 rows returned. I want a single one if it's the same FK_ID_intTipoTrabalho with the full range, or break it down, not having more than one in a row.
so you can find
code start end
A 2012-01-01 2012-01-10
B 2012-01-11 2012-01-20
B 2012-01-21 2012-02-10
A 2012-02-11 2012-02-25
A 2012-02-26 2012-02-29
call it CTX
then you do
SELECT DQ.code, Min(DQ.Start), Max(DQ.end) FROM (SELECT code, start,end,
row_number() over(order by start) - row_number() over(partition by code order by start) AS X FROM CTEX
) DQ
GROUP BY DQ.Code, DQ.X
[edited this]
code start end
A 2012-01-01 2012-01-10
B 2012-01-11 2012-01-20
B 2012-01-21 2012-02-10
A 2012-02-11 2012-02-25
A 2012-02-26 2012-02-29
call it CTX
then you do
SELECT DQ.code, Min(DQ.Start), Max(DQ.end) FROM (SELECT code, start,end,
row_number() over(order by start) - row_number() over(partition by code order by start) AS X FROM CTEX
) DQ
GROUP BY DQ.Code, DQ.X
[edited this]
if you make a simple table
code start end
A 2012-01-01 2012-01-10
B 2012-01-11 2012-01-20
B 2012-01-21 2012-02-10
A 2012-02-11 2012-02-25
A 2012-02-26 2012-02-29
then run the
SELECT code, start,end,
row_number() over(order by start) - row_number() over(partition by code order by start) AS X FROM CTEX
you should see how it makes islands have unique code and X for each island
code start end
A 2012-01-01 2012-01-10
B 2012-01-11 2012-01-20
B 2012-01-21 2012-02-10
A 2012-02-11 2012-02-25
A 2012-02-26 2012-02-29
then run the
SELECT code, start,end,
row_number() over(order by start) - row_number() over(partition by code order by start) AS X FROM CTEX
you should see how it makes islands have unique code and X for each island
here
test.PNG
test.PNG
although you need to order by date at the end, the islands are there
The sample data would be vastly more useful as either INSERT statements or a spreadsheet -- as it is, I still have to do a lot of formatting just to get sample data loaded into a table for testing :-( .
ASKER
Sorry. I simply did a select and copy/pasted. I'll make it into an insert tomorrow when I get back to work.
ASKER
While I try to get the queries going, here is the sample data as inserts:
INSERT INTO tblTrabalho VALUES (41,824,'3A1F0A86-34E5-4BB8-98A3-11DA752484E3','20120910','20120924')
INSERT INTO tblTrabalho VALUES (41,636,'18187308-A0CD-4A06-B5D1-1E7CF2911120','20110704','20110730')
INSERT INTO tblTrabalho VALUES (41,646,'18187308-A0CD-4A06-B5D1-1E7CF2911120','20111105','20111130')
INSERT INTO tblTrabalho VALUES (41,542,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111205','20111205')
INSERT INTO tblTrabalho VALUES (41,542,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120123','20120123')
INSERT INTO tblTrabalho VALUES (41,542,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120428','20120429')
INSERT INTO tblTrabalho VALUES (41,609,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111121','20111121')
INSERT INTO tblTrabalho VALUES (41,609,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111128','20111128')
INSERT INTO tblTrabalho VALUES (41,625,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111209','20111209')
INSERT INTO tblTrabalho VALUES (41,625,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120105','20120105')
INSERT INTO tblTrabalho VALUES (41,646,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111207','20111207')
INSERT INTO tblTrabalho VALUES (41,646,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111216','20111216')
INSERT INTO tblTrabalho VALUES (41,646,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111223','20111223')
INSERT INTO tblTrabalho VALUES (41,646,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111229','20111229')
INSERT INTO tblTrabalho VALUES (41,646,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120105','20120105')
INSERT INTO tblTrabalho VALUES (41,646,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120128','20120128')
INSERT INTO tblTrabalho VALUES (41,879,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120126','20120126')
INSERT INTO tblTrabalho VALUES (41,903,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120124','20120124')
INSERT INTO tblTrabalho VALUES (41,999,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120116','20120116')
INSERT INTO tblTrabalho VALUES (41,1060,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111126','20111126')
INSERT INTO tblTrabalho VALUES (41,1060,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111203','20111203')
INSERT INTO tblTrabalho VALUES (41,1060,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111210','20111210')
INSERT INTO tblTrabalho VALUES (41,1060,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111217','20111217')
INSERT INTO tblTrabalho VALUES (41,1169,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111221','20111221')
INSERT INTO tblTrabalho VALUES (41,1260,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111121','20111121')
INSERT INTO tblTrabalho VALUES (41,1260,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111203','20111203')
INSERT INTO tblTrabalho VALUES (41,1260,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111231','20111231')
INSERT INTO tblTrabalho VALUES (41,1260,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120125','20120125')
INSERT INTO tblTrabalho VALUES (41,1265,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111231','20111231')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111121','20111121')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111122','20111122')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111219','20111219')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111227','20111227')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120103','20120103')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120124','20120124')
INSERT INTO tblTrabalho VALUES (41,1275,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120129','20120129')
INSERT INTO tblTrabalho VALUES (41,1282,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120127','20120127')
INSERT INTO tblTrabalho VALUES (41,1282,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120128','20120128')
INSERT INTO tblTrabalho VALUES (41,1311,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111212','20111212')
INSERT INTO tblTrabalho VALUES (41,1314,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111203','20111203')
INSERT INTO tblTrabalho VALUES (41,1314,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111223','20111223')
INSERT INTO tblTrabalho VALUES (41,1322,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120103','20120103')
INSERT INTO tblTrabalho VALUES (41,1322,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120107','20120107')
INSERT INTO tblTrabalho VALUES (41,1322,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120108','20120108')
INSERT INTO tblTrabalho VALUES (41,1327,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111121','20111121')
INSERT INTO tblTrabalho VALUES (41,1327,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111202','20111202')
INSERT INTO tblTrabalho VALUES (41,1327,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111227','20111227')
INSERT INTO tblTrabalho VALUES (41,1327,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120104','20120104')
INSERT INTO tblTrabalho VALUES (41,1362,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120116','20120116')
INSERT INTO tblTrabalho VALUES (41,1363,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120102','20120102')
INSERT INTO tblTrabalho VALUES (41,1367,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111215','20111215')
INSERT INTO tblTrabalho VALUES (41,1374,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120116','20120116')
INSERT INTO tblTrabalho VALUES (41,1374,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120123','20120123')
INSERT INTO tblTrabalho VALUES (41,1381,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111212','20111212')
INSERT INTO tblTrabalho VALUES (41,1381,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111216','20111216')
INSERT INTO tblTrabalho VALUES (41,1381,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111229','20111229')
INSERT INTO tblTrabalho VALUES (41,1382,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111213','20111213')
INSERT INTO tblTrabalho VALUES (41,1382,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120124','20120124')
INSERT INTO tblTrabalho VALUES (41,1385,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20111130','20111130')
INSERT INTO tblTrabalho VALUES (41,1385,'5DC1CD6D-9F7D-4473-9D3C-6BCEFF3FEF0C','20120124','20120124')
INSERT INTO tblTrabalho VALUES (41,275,'B4FB2460-330E-4C62-B7DF-73710F85D462','20111001','20111030')
INSERT INTO tblTrabalho VALUES (41,275,'B4FB2460-330E-4C62-B7DF-73710F85D462','20111031','20111129')
INSERT INTO tblTrabalho VALUES (41,275,'B4FB2460-330E-4C62-B7DF-73710F85D462','20111130','20111229')
INSERT INTO tblTrabalho VALUES (41,275,'B4FB2460-330E-4C62-B7DF-73710F85D462','20111230','20120128')
INSERT INTO tblTrabalho VALUES (41,275,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120129','20120227')
INSERT INTO tblTrabalho VALUES (41,294,'B4FB2460-330E-4C62-B7DF-73710F85D462','20111201','20111230')
INSERT INTO tblTrabalho VALUES (41,294,'B4FB2460-330E-4C62-B7DF-73710F85D462','20111231','20120129')
INSERT INTO tblTrabalho VALUES (41,294,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120130','20120229')
INSERT INTO tblTrabalho VALUES (41,294,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120301','20120329')
INSERT INTO tblTrabalho VALUES (41,919,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120727','20120729')
INSERT INTO tblTrabalho VALUES (41,919,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120730','20120829')
INSERT INTO tblTrabalho VALUES (41,919,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120830','20120929')
INSERT INTO tblTrabalho VALUES (41,919,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120930','20121029')
INSERT INTO tblTrabalho VALUES (41,919,'B4FB2460-330E-4C62-B7DF-73710F85D462','20121030','20121126')
INSERT INTO tblTrabalho VALUES (41,1055,'B4FB2460-330E-4C62-B7DF-73710F85D462','20101218','20101225')
INSERT INTO tblTrabalho VALUES (41,1055,'B4FB2460-330E-4C62-B7DF-73710F85D462','20110104','20110105')
INSERT INTO tblTrabalho VALUES (41,1055,'B4FB2460-330E-4C62-B7DF-73710F85D462','20110107','20110107')
INSERT INTO tblTrabalho VALUES (41,1055,'B4FB2460-330E-4C62-B7DF-73710F85D462','20110110','20110110')
INSERT INTO tblTrabalho VALUES (41,1055,'B4FB2460-330E-4C62-B7DF-73710F85D462','20110118','20110118')
INSERT INTO tblTrabalho VALUES (41,1060,'B4FB2460-330E-4C62-B7DF-73710F85D462','20101229','20101231')
INSERT INTO tblTrabalho VALUES (41,1060,'B4FB2460-330E-4C62-B7DF-73710F85D462','20110101','20110111')
INSERT INTO tblTrabalho VALUES (41,1214,'B4FB2460-330E-4C62-B7DF-73710F85D462','20100329','20100402')
INSERT INTO tblTrabalho VALUES (41,1229,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120920','20120930')
INSERT INTO tblTrabalho VALUES (41,1229,'B4FB2460-330E-4C62-B7DF-73710F85D462','20121001','20121003')
INSERT INTO tblTrabalho VALUES (41,1229,'B4FB2460-330E-4C62-B7DF-73710F85D462','20121105','20121111')
INSERT INTO tblTrabalho VALUES (41,1229,'B4FB2460-330E-4C62-B7DF-73710F85D462','20121119','20121125')
INSERT INTO tblTrabalho VALUES (41,1240,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120524','20120525')
INSERT INTO tblTrabalho VALUES (41,1240,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120528','20120530')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120329','20120330')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120406','20120418')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120419','20120518')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120519','20120617')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120618','20120717')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120718','20120816')
INSERT INTO tblTrabalho VALUES (41,1375,'B4FB2460-330E-4C62-B7DF-73710F85D462','20120817','20120901')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121015','20121015')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121016','20121016')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121018','20121018')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121020','20121020')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121022','20121022')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121023','20121023')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121025','20121025')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121026','20121026')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121029','20121029')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121030','20121030')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121101','20121101')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121102','20121102')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121103','20121103')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121105','20121105')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121106','20121106')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121108','20121108')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121109','20121109')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121110','20121110')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121112','20121112')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121113','20121113')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121114','20121114')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121115','20121115')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121116','20121116')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121119','20121119')
INSERT INTO tblTrabalho VALUES (41,1375,'9B36C78F-CAAF-44FB-9E41-7C10994E5C39','20121120','20121120')
INSERT INTO tblTrabalho VALUES (41,177,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101109','20101112')
INSERT INTO tblTrabalho VALUES (41,177,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110216','20110522')
INSERT INTO tblTrabalho VALUES (41,177,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120912','20120914')
INSERT INTO tblTrabalho VALUES (41,177,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120915','20120918')
INSERT INTO tblTrabalho VALUES (41,275,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110831','20110930')
INSERT INTO tblTrabalho VALUES (41,542,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100202','20100221')
INSERT INTO tblTrabalho VALUES (41,542,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100707','20100713')
INSERT INTO tblTrabalho VALUES (41,542,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101018','20101126')
INSERT INTO tblTrabalho VALUES (41,609,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100918','20100920')
INSERT INTO tblTrabalho VALUES (41,609,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101015','20101031')
INSERT INTO tblTrabalho VALUES (41,609,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110101','20110103')
INSERT INTO tblTrabalho VALUES (41,609,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110208','20110215')
INSERT INTO tblTrabalho VALUES (41,609,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110725','20110731')
INSERT INTO tblTrabalho VALUES (41,636,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110412','20110427')
INSERT INTO tblTrabalho VALUES (41,646,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100114','20100125')
INSERT INTO tblTrabalho VALUES (41,646,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100319','20100323')
INSERT INTO tblTrabalho VALUES (41,646,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100508','20100516')
INSERT INTO tblTrabalho VALUES (41,646,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110615','20110703')
INSERT INTO tblTrabalho VALUES (41,646,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120217','20120222')
INSERT INTO tblTrabalho VALUES (41,646,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120223','20120226')
INSERT INTO tblTrabalho VALUES (41,879,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120127','20120129')
INSERT INTO tblTrabalho VALUES (41,903,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100906','20100913')
INSERT INTO tblTrabalho VALUES (41,903,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20111230','20120110')
INSERT INTO tblTrabalho VALUES (41,919,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101028','20101107')
INSERT INTO tblTrabalho VALUES (41,919,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120618','20120629')
INSERT INTO tblTrabalho VALUES (41,919,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120630','20120726')
INSERT INTO tblTrabalho VALUES (41,926,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100203','20100210')
INSERT INTO tblTrabalho VALUES (41,939,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110623','20110630')
INSERT INTO tblTrabalho VALUES (41,939,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120308','20120313')
INSERT INTO tblTrabalho VALUES (41,939,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120817','20120819')
INSERT INTO tblTrabalho VALUES (41,1047,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110301','20110308')
INSERT INTO tblTrabalho VALUES (41,1071,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100610','20100618')
INSERT INTO tblTrabalho VALUES (41,1071,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20111006','20111027')
INSERT INTO tblTrabalho VALUES (41,1103,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101110','20101121')
INSERT INTO tblTrabalho VALUES (41,1103,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110224','20110308')
INSERT INTO tblTrabalho VALUES (41,1103,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110620','20110624')
INSERT INTO tblTrabalho VALUES (41,1103,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120208','20120219')
INSERT INTO tblTrabalho VALUES (41,1103,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120220','20120224')
INSERT INTO tblTrabalho VALUES (41,1229,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100101','20100101')
INSERT INTO tblTrabalho VALUES (41,1261,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100708','20100711')
INSERT INTO tblTrabalho VALUES (41,1261,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110126','20110131')
INSERT INTO tblTrabalho VALUES (41,1261,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110205','20110211')
INSERT INTO tblTrabalho VALUES (41,1261,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110215','20110220')
INSERT INTO tblTrabalho VALUES (41,1264,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100729','20100806')
INSERT INTO tblTrabalho VALUES (41,1265,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100526','20100606')
INSERT INTO tblTrabalho VALUES (41,1265,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120131','20120207')
INSERT INTO tblTrabalho VALUES (41,1269,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100405','20100409')
INSERT INTO tblTrabalho VALUES (41,1269,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100729','20100809')
INSERT INTO tblTrabalho VALUES (41,1275,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120525','20120531')
INSERT INTO tblTrabalho VALUES (41,1276,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101018','20101018')
INSERT INTO tblTrabalho VALUES (41,1276,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101220','20101224')
INSERT INTO tblTrabalho VALUES (41,1282,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120924','20120928')
INSERT INTO tblTrabalho VALUES (41,1287,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101106','20101112')
INSERT INTO tblTrabalho VALUES (41,1287,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101210','20101214')
INSERT INTO tblTrabalho VALUES (41,1287,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110103','20110110')
INSERT INTO tblTrabalho VALUES (41,1303,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100704','20100708')
INSERT INTO tblTrabalho VALUES (41,1311,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120320','20120321')
INSERT INTO tblTrabalho VALUES (41,1314,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110801','20110812')
INSERT INTO tblTrabalho VALUES (41,1320,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110216','20110227')
INSERT INTO tblTrabalho VALUES (41,1326,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110320','20110325')
INSERT INTO tblTrabalho VALUES (41,1327,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110919','20110923')
INSERT INTO tblTrabalho VALUES (41,1332,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101217','20101219')
INSERT INTO tblTrabalho VALUES (41,1341,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20100913','20100918')
INSERT INTO tblTrabalho VALUES (41,1350,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110120','20110125')
INSERT INTO tblTrabalho VALUES (41,1351,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20101110','20101207')
INSERT INTO tblTrabalho VALUES (41,1355,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110404','20110409')
INSERT INTO tblTrabalho VALUES (41,1356,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110501','20110512')
INSERT INTO tblTrabalho VALUES (41,1356,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20111001','20111005')
INSERT INTO tblTrabalho VALUES (41,1357,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110227','20110228')
INSERT INTO tblTrabalho VALUES (41,1357,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110324','20110330')
INSERT INTO tblTrabalho VALUES (41,1357,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110416','20110422')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110426','20110501')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20111121','20111219')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20111220','20120118')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120119','20120120')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120121','20120209')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120210','20120218')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120219','20120310')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120311','20120319')
INSERT INTO tblTrabalho VALUES (41,1375,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120320','20120328')
INSERT INTO tblTrabalho VALUES (41,1382,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120518','20120525')
INSERT INTO tblTrabalho VALUES (41,1382,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120526','20120527')
INSERT INTO tblTrabalho VALUES (41,1382,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120711','20120718')
INSERT INTO tblTrabalho VALUES (41,1382,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20120817','20120819')
INSERT INTO tblTrabalho VALUES (41,1387,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110819','20110821')
INSERT INTO tblTrabalho VALUES (41,1391,'0FC911AD-29E7-4F15-A2A5-AD4D629F30FF','20110820','20110827')
INSERT INTO tblTrabalho VALUES (41,1322,'C3B87B60-0205-43D2-9356-ADE88304A9C4','20120106','20120106')
INSERT INTO tblTrabalho VALUES (41,542,'8E5E8121-5CC7-42BD-A57F-B20DDD334B24','20100222','20100310')
INSERT INTO tblTrabalho VALUES (41,542,'8E5E8121-5CC7-42BD-A57F-B20DDD334B24','20101222','20101231')
INSERT INTO tblTrabalho VALUES (41,542,'8E5E8121-5CC7-42BD-A57F-B20DDD334B24','20110101','20110406')
INSERT INTO tblTrabalho VALUES (41,1311,'8E5E8121-5CC7-42BD-A57F-B20DDD334B24','20110712','20110718')
INSERT INTO tblTrabalho VALUES (41,1330,'8E5E8121-5CC7-42BD-A57F-B20DDD334B24','20110401','20110406')
INSERT INTO tblTrabalho VALUES (41,1351,'8E5E8121-5CC7-42BD-A57F-B20DDD334B24','20101208','20101221')
INSERT INTO tblTrabalho VALUES (41,1375,'7A375D2F-5471-4446-8E00-B32B7EAC9839','20120401','20120405')
INSERT INTO tblTrabalho VALUES (41,903,'C5DD9F42-300B-45AD-AFCC-B9815D1D7AEF','20110309','20110311')
INSERT INTO tblTrabalho VALUES (41,903,'C5DD9F42-300B-45AD-AFCC-B9815D1D7AEF','20120415','20120417')
INSERT INTO tblTrabalho VALUES (41,1375,'C5DD9F42-300B-45AD-AFCC-B9815D1D7AEF','20110301','20110303')
ASKER
It seems I'm failing to get all the values back. I used this query:
Funcionari o can have multiple islands and only a few will be 30+ days.
I have also failed to adapt the first code to this. I can see how easily it would work for one employee at a time, but the problem is that, even though there are no overlaps for each FK_ID_intEmpresa,FK_ID_int Funcionari o, there are many for each FK_ID_intEmpresa. A single day can have quite a few FK_ID_intFuncionario which have to be taken into account. I would need to generate a calendar for each employee and that would be too slow, even if I were to limit the years to, for example, 2010-2013.
WITH CTE AS (SELECT CONVERT(char(10),CalendarDate,105) Data,
CalendarDate,
FK_ID_intEmpresa Emp,
FK_ID_intFuncionario Num,
strTipoTrabalho Tipo,
CONVERT(char(10),datHoraEntradaTrabalho,105) Ent,
CONVERT(char(10),datHoraSaidaTrabalho,105) Sai
FROM Calendar
INNER JOIN tblTrabalho
ON CalendarDate BETWEEN datHoraEntradaTrabalho AND datHoraSaidaTrabalho
INNER JOIN tblTiposTrabalho
ON ID_intTipoTrabalho=FK_ID_intTipoTrabalho
WHERE strCategoria IN ('I','A')
AND strTipoTrabalho NOT LIKE '%Férias%'
AND FK_ID_intEmpresa=41
AND FK_ID_intFuncionario<=1391)
SELECT *
FROM CTE c1
INNER JOIN CTE c2
ON c1.Emp=c2.Emp
AND c1.Num=c2.Num
AND c2.CalendarDate=(SELECT MIN(CalendarDate) FROM CTE c4 WHERE c1.Emp=c4.Emp AND c1.Num=c4.Num AND c4.CalendarDate>c1.CalendarDate)
WHERE NOT EXISTS (SELECT 'a'
FROM Calendar c3
WHERE c1.CalendarDate<c3.CalendarDate
AND c3.CalendarDate<c2.CalendarDate)
But it took 2 minutes to get the results (1647 rows) and I still have to identify 30 day islands. Not sure how I'll do this when the same FK_ID_intEmpresa,FK_ID_intI have also failed to adapt the first code to this. I can see how easily it would work for one employee at a time, but the problem is that, even though there are no overlaps for each FK_ID_intEmpresa,FK_ID_int
ASKER
I've improved the query. It now takes under a second to run and returns one row per day (the previous didn't return the last day). Still have a problem with the 30 day ranges, though.
WITH CTE AS (SELECT CONVERT(char(10),CalendarDate,105) Data,
CalendarDate,
FK_ID_intEmpresa Emp,
FK_ID_intFuncionario Num,
strTipoTrabalho Tipo,
CONVERT(char(10),datHoraEntradaTrabalho,105) Ent,
CONVERT(char(10),datHoraSaidaTrabalho,105) Sai
FROM Calendar
INNER JOIN tblTrabalho
ON CalendarDate BETWEEN datHoraEntradaTrabalho AND datHoraSaidaTrabalho
INNER JOIN tblTiposTrabalho
ON ID_intTipoTrabalho=FK_ID_intTipoTrabalho
WHERE strCategoria IN ('I','A')
AND strTipoTrabalho NOT LIKE '%Férias%'
AND FK_ID_intEmpresa=41
AND FK_ID_intFuncionario<=1391)
SELECT *
FROM CTE c1
WHERE EXISTS (SELECT 'a'
FROM CTE c2
WHERE ABS(DATEDIFF(day,c1.CalendarDate,c2.CalendarDate))=1
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num)
ORDER BY 3,4,6,2
ASKER
Ok, combining my query with the above suggestions, I've managed to get it working.
I'm sure there's a more efficient way to do this.
DECLARE @Emp int
SET @Emp=41;
WITH CTE AS (SELECT CalendarDate,
FK_ID_intEmpresa Emp,
FK_ID_intFuncionario Num,
strTipoTrabalho Tipo
FROM Calendar
INNER JOIN tblTrabalho
ON CalendarDate BETWEEN datHoraEntradaTrabalho AND datHoraSaidaTrabalho
INNER JOIN tblTiposTrabalho
ON ID_intTipoTrabalho=FK_ID_intTipoTrabalho
WHERE strCategoria IN ('I','A')
AND strTipoTrabalho NOT LIKE '%Férias%'
AND FK_ID_intEmpresa=@Emp),
CT2 AS (SELECT c1.*,
CASE WHEN NOT EXISTS (SELECT 'a'
FROM CTE c3
WHERE c1.Emp=c3.Emp
AND c1.Num=c3.Num
AND c1.CalendarDate=DATEADD(day,-1,c3.CalendarDate)) THEN -1
WHEN NOT EXISTS (SELECT 'a'
FROM CTE c4
WHERE c1.Emp=c4.Emp
AND c1.Num=c4.Num
AND c1.CalendarDate=DATEADD(day,1,c4.CalendarDate)) THEN 1
ELSE 0 END ColCheck
FROM CTE c1
WHERE EXISTS (SELECT 'a'
FROM CTE c2
WHERE ABS(DATEDIFF(day,c1.CalendarDate,c2.CalendarDate))=1
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num)),
CT3 AS (SELECT c1.CalendarDate StartDate,
c1.Emp,
c1.Num,
(SELECT MIN(c2.CalendarDate)
FROM CT2 c2
WHERE c2.ColCheck=-1
AND c1.CalendarDate<c2.CalendarDate
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num) EndDate
FROM (SELECT *
FROM CT2
WHERE ColCheck=1) c1
WHERE DATEDIFF(day,c1.CalendarDate,(SELECT MIN(c2.CalendarDate)
FROM CT2 c2
WHERE c2.ColCheck=-1
AND c1.CalendarDate<c2.CalendarDate
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num))+1>=30),
CTF AS (SELECT FK_ID_intEmpresa Emp,
FK_ID_intFuncionario Num,
strTipoTrabalho Tipo,
datHoraEntradaTrabalho Ent,
datHoraSaidaTrabalho Sai,
ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_intFuncionario
ORDER BY datHoraEntradaTrabalho)-
ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_intFuncionario,strTipoTrabalho
ORDER BY datHoraEntradaTrabalho) X
FROM tblTrabalho
INNER JOIN tblTiposTrabalho
ON ID_intTipoTrabalho=FK_ID_intTipoTrabalho
INNER JOIN CT3
ON FK_ID_intEmpresa=Emp
AND FK_ID_intFuncionario=Num
AND datHoraEntradaTrabalho BETWEEN StartDate AND EndDate)
SELECT Emp,
Num,
Tipo,
MIN(Ent) Ent,
MAX(Sai) Sai,
DATEDIFF(day,MIN(Ent),MAX(Sai))+1 Dif
FROM CTF
GROUP BY Emp,
Num,
Tipo,
X
ORDER BY 1,2,4
However, this is quite slow, taking 2 minutes to run on the sample data provided and over 6 minutes without the FK_ID_intFuncionario filter in the initial query.I'm sure there's a more efficient way to do this.
ASKER
I'm attaching an excel file with the results for each CTE, in case they can help.
EDIT: Corrected the file (there was a step missing)
Temp.xlsx
EDIT: Corrected the file (there was a step missing)
Temp.xlsx
if it's taking 6 minutes on a few rows then I'd consider using a cursor to scroll through it in date order.
________________
Yeas I think you could use a cursor, calculate the start and end date of your dataset, iterate through your dates table from start to end date, finding the dates in your data table where sequences start and end, and drop those dates into a temp table, then select start and end of over 30 days in your temp table and iterate with another cursor to determine the details of the codes runs in the 30 days, then out put those to another temp table, then query the final temp table.
________________
Yeas I think you could use a cursor, calculate the start and end date of your dataset, iterate through your dates table from start to end date, finding the dates in your data table where sequences start and end, and drop those dates into a temp table, then select start and end of over 30 days in your temp table and iterate with another cursor to determine the details of the codes runs in the 30 days, then out put those to another temp table, then query the final temp table.
ASKER
I really have no idea how to use a cursor. I'm an experienced programmer, but only so-so on T-SQL. If I understand you correctly, you're saying I should replace CTE or CT2 with a cursor and work with that one?
I have a feeling that there's a more effective way of doing this. I'm going about in a loop (turn ranges into rows, group them, then go back to the original table to get the ranges and group them again). I think there's a better way to do this, but I seem to be stuck in this logic.
I have a feeling that there's a more effective way of doing this. I'm going about in a loop (turn ranges into rows, group them, then go back to the original table to get the ranges and group them again). I think there's a better way to do this, but I seem to be stuck in this logic.
I would LOVE to get involved in this one, but wont be able to until later today (after "work" which I am about to head out to do).
So, if still here when I return, then will sink my teeth into it :)
So, days need to be consecutive groups of 30 (or more) days shown more like a calendar for a given FK_ID_intEmpresa,FK_ID_int Funcionari o combo in claendar date sequence by FK_ID_intTipoTrabalho
So, if still here when I return, then will sink my teeth into it :)
So, days need to be consecutive groups of 30 (or more) days shown more like a calendar for a given FK_ID_intEmpresa,FK_ID_int
I read above (somewhere) that the sequence needs to be preserved. Does that mean we cannot sort into date sequence for FK_ID_intEmpresa,FK_ID_int Funcionari o ?
ASKER
The sequence for each FK_ID_intEmpresa,FK_ID_int Funcionari o is what must be preserved, no matter what FK_ID_intTipoTrabalho it has (or strTipoTrabalho on the linked version of the query). That means that a 30+ day period may contain many records of the same FK_ID_intTipoTrabalho, which have to be grouped, but they may also have some different ones in between, and these have to be listed as well.
If you check the last query I posted and the excel I've attached, you'll see the results for each step, as well as the final result. What I want, basically, is to turn the first sheet (CTE) into the last one (CTF Final).
My query already works. It just takes too long to do so. I'm sure there's a better way to do this, or to improve on my query.
If you check the last query I posted and the excel I've attached, you'll see the results for each step, as well as the final result. What I want, basically, is to turn the first sheet (CTE) into the last one (CTF Final).
My query already works. It just takes too long to do so. I'm sure there's a better way to do this, or to improve on my query.
To encourage more input, do the following:
Code | fromDate | toDate | noOfDaysInThisRecord
Code | fromDate | toDate |noOfDaysInThisRecord
List around 10 records
Code | fromDate | toDate | noOfDaysInThisRecord
Then list required output.
Code | fromDate | toDate |noOfDaysInThisRecord
ASKER
Actually, I had already done that. I posted data in the OQ and later I posted the same data as INSERT statements. Afterwards, when I got the query working, I posted the data in the excel file.
I'm attaching a new excel file with the same steps but for a larger set of data. I'm also including the original table without linking to Calendar table, in case a solution arises which doesn't use it.
If you want to work with smaller subsets, just pick a couple results from the last sheet and filter those in the previous sheets.
Basically, given the data in the first sheet, I need the last one returned.
This is the query I used:
Any other data you need, let me know.
EDIT: Added the file, which I forgot to attach
Temp.xlsx
I'm attaching a new excel file with the same steps but for a larger set of data. I'm also including the original table without linking to Calendar table, in case a solution arises which doesn't use it.
If you want to work with smaller subsets, just pick a couple results from the last sheet and filter those in the previous sheets.
Basically, given the data in the first sheet, I need the last one returned.
This is the query I used:
--DECLARE @Emp int,@iAno int
--SET @Emp=41
--SET @iAno=2012;
WITH CTE AS (SELECT CalendarDate,
FK_ID_intEmpresa Emp,
FK_ID_intFuncionario Num,
strTipoTrabalho Tipo
FROM Calendar
INNER JOIN tblTrabalho
ON CalendarDate BETWEEN datHoraEntradaTrabalho AND datHoraSaidaTrabalho
INNER JOIN tblTiposTrabalho
ON ID_intTipoTrabalho=FK_ID_intTipoTrabalho
WHERE strCategoria IN ('I','A','F')
AND strLegenda IN ('AF','BAT','BD','D','LSV','SD','SM')
AND CONVERT(char(5),datHoraEntradaTrabalho,108)='00:00'
AND CONVERT(char(5),datHoraSaidaTrabalho,108)='00:00'
AND FK_ID_intEmpresa IN (41,42,43,63,75,104)),
--AND CalendarYear=@iAno),
CT2 AS (SELECT c1.*,
CASE WHEN NOT EXISTS (SELECT 'a'
FROM CTE c3
WHERE c1.Emp=c3.Emp
AND c1.Num=c3.Num
AND c1.CalendarDate=DATEADD(day,-1,c3.CalendarDate)) THEN -1
WHEN NOT EXISTS (SELECT 'a'
FROM CTE c4
WHERE c1.Emp=c4.Emp
AND c1.Num=c4.Num
AND c1.CalendarDate=DATEADD(day,1,c4.CalendarDate)) THEN 1
ELSE 0 END ColCheck
FROM CTE c1
WHERE EXISTS (SELECT 'a'
FROM CTE c2
WHERE ABS(DATEDIFF(day,c1.CalendarDate,c2.CalendarDate))=1
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num)),
CT3 AS (SELECT c1.CalendarDate StartDate,
c1.Emp,
c1.Num,
(SELECT MIN(c2.CalendarDate)
FROM CT2 c2
WHERE c2.ColCheck=-1
AND c1.CalendarDate<c2.CalendarDate
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num) EndDate
FROM CT2 c1
WHERE ColCheck=1
AND DATEDIFF(day,c1.CalendarDate,(SELECT MIN(c2.CalendarDate)
FROM CT2 c2
WHERE c2.ColCheck=-1
AND c1.CalendarDate<c2.CalendarDate
AND c1.Emp=c2.Emp
AND c1.Num=c2.Num))+1>=30),
CTF AS (SELECT FK_ID_intEmpresa Emp,
FK_ID_intFuncionario Num,
strTipoTrabalho Tipo,
datHoraEntradaTrabalho Ent,
datHoraSaidaTrabalho Sai,
ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_intFuncionario
ORDER BY datHoraEntradaTrabalho)-
ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_intFuncionario,strTipoTrabalho
ORDER BY datHoraEntradaTrabalho) X
FROM tblTrabalho
INNER JOIN tblTiposTrabalho
ON ID_intTipoTrabalho=FK_ID_intTipoTrabalho
INNER JOIN CT3
ON FK_ID_intEmpresa=Emp
AND FK_ID_intFuncionario=Num
AND datHoraEntradaTrabalho BETWEEN StartDate AND EndDate)
SELECT Emp,
Num,
Tipo,
CONVERT(char(10),MIN(Ent),105) Ent,
CONVERT(char(10),MAX(Sai),105) Sai,
DATEDIFF(day,MIN(Ent),MAX(Sai))+1 Dif
FROM CTF
GROUP BY Emp,
Num,
Tipo,
X
ORDER BY Emp,
Num,
MIN(Ent)
This takes 26:32 to run, which is too much, obviously. There has to be a way of either speeding this query, or of getting the same results using a different approach that is faster.Any other data you need, let me know.
EDIT: Added the file, which I forgot to attach
Temp.xlsx
I received an invitation to help in this question.
So don't expect me to go through all the previous comments. Please just reply to my previous comment as requested. This helps me to understand the problem.
So don't expect me to go through all the previous comments. Please just reply to my previous comment as requested. This helps me to understand the problem.
ASKER
Sure. But as I said, you can use the above file and just select a few solutions. Either way, I'll post a few here:
Original:
Expected results:
It's more than 10 lines, but they relate to just two separate cases which cover most of the problems this question covers.
Original:
FK_ID_intEmpresa FK_ID_intFuncionario strTipoTrabalho datHoraEntradaTrabalho datHoraSaidaTrabalho
41 542 Baixa Por Doença 02-02-2010 21-02-2010
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010
41 542 Baixa Por Doença 07-07-2010 13-07-2010
41 542 Baixa Por Doença 18-10-2010 26-11-2010
41 542 Baixa Por Acidente de Trabalho 22-12-2010 31-12-2010
41 542 Baixa Por Acidente de Trabalho 01-01-2011 06-04-2011
41 542 Dispensa 05-12-2011 05-12-2011
41 542 Dispensa 23-01-2012 23-01-2012
41 542 Dispensa 28-04-2012 29-04-2012
42 589 Baixa Por Acidente de Trabalho 11-05-2010 26-05-2010
42 589 Baixa Por Acidente de Trabalho 27-05-2010 04-06-2010
42 589 Baixa Por Doença 10-05-2011 20-05-2011
42 589 Baixa Por Doença 10-08-2011 07-09-2011
42 589 Baixa Por Doença 20-12-2011 22-12-2011
42 589 Baixa Por Acidente de Trabalho 22-02-2012 16-03-2012
42 589 Baixa Por Acidente de Trabalho 17-03-2012 02-04-2012
42 589 Baixa Por Acidente de Trabalho 16-04-2012 28-04-2012
42 589 Baixa Por Acidente de Trabalho 29-04-2012 30-04-2012
42 589 Baixa Por Acidente de Trabalho 01-05-2012 07-05-2012
42 589 Baixa Por Acidente de Trabalho 08-05-2012 14-05-2012
42 589 Baixa Por Acidente de Trabalho 15-05-2012 28-05-2012
42 589 Baixa Por Acidente de Trabalho 29-05-2012 27-06-2012
42 589 Baixa Por Acidente de Trabalho 28-06-2012 28-06-2012
42 589 Baixa Por Doença 29-06-2012 05-07-2012
42 589 Baixa Por Doença 06-07-2012 16-07-2012
42 589 Baixa Por Acidente de Trabalho 17-07-2012 23-07-2012
42 589 Baixa Por Acidente de Trabalho 24-07-2012 10-08-2012
42 589 Dispensa 12-08-2012 12-08-2012
42 589 Baixa Por Acidente de Trabalho 28-08-2012 10-09-2012
42 589 Baixa Por Acidente de Trabalho 11-09-2012 25-09-2012
42 589 Baixa Por Acidente de Trabalho 26-09-2012 25-10-2012
42 589 Baixa Por Acidente de Trabalho 26-10-2012 23-11-2012
Expected results:
Emp Num Tipo Ent Sai Dif
41 542 Baixa Por Doença 02-02-2010 21-02-2010 20
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010 17
41 542 Baixa Por Doença 18-10-2010 26-11-2010 40
41 542 Baixa Por Acidente de Trabalho 22-12-2010 06-04-2011 106
42 589 Baixa Por Acidente de Trabalho 22-02-2012 28-06-2012 128
42 589 Baixa Por Doença 29-06-2012 16-07-2012 18
42 589 Baixa Por Acidente de Trabalho 17-07-2012 23-11-2012 130
It's more than 10 lines, but they relate to just two separate cases which cover most of the problems this question covers.
For not to drag in more comments, please supply the info for me to understand the problem.
code | other | fromDate | toDate | diff
41 x 02-02-2010 21-02-2010 fill
41 y 22-02-2010 10-03-2010 fill
41 x 07-07-2010 13-07-2010 fill
41 y 18-10-2010 26-11-2010 fill
42 x 02-02-2010 21-02-2010 fill
42 y 22-02-2010 10-03-2010 fill
42 x 07-07-2010 13-07-2010 fill
42 y 18-10-2010 26-11-2010 fill
Modify the above data and list down the expected output.
code | other | fromDate | toDate | diff
41 x 02-02-2010 21-02-2010 fill
41 y 22-02-2010 10-03-2010 fill
41 x 07-07-2010 13-07-2010 fill
41 y 18-10-2010 26-11-2010 fill
42 x 02-02-2010 21-02-2010 fill
42 y 22-02-2010 10-03-2010 fill
42 x 07-07-2010 13-07-2010 fill
42 y 18-10-2010 26-11-2010 fill
Modify the above data and list down the expected output.
ASKER
I don't think you quite understand. FK_ID_intEmpresa and FK_ID_intFuncionario are both part of the ID. Thus, 41/542 is one ID, 42/589 is another ID. Each of the columns can have multiple values, but only one pair is allowed, as a normal composite ID key.
Now, for each ID, you can have multiple codes (strTipoTrabalho) which was what was posted above.
The data you posted was from the expected results which already include everything, including the number of days.
I'll post the sample data with the date difference.
Now, remember that the first two columns are part of the ID, then comes the type (or code), then from and to dates, then diff.
Now, for each ID, you can have multiple codes (strTipoTrabalho) which was what was posted above.
The data you posted was from the expected results which already include everything, including the number of days.
I'll post the sample data with the date difference.
41 542 Baixa Por Doença 02-02-2010 21-02-2010 20
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010 17
41 542 Baixa Por Doença 07-07-2010 13-07-2010 7
41 542 Baixa Por Doença 18-10-2010 26-11-2010 40
41 542 Baixa Por Acidente de Trabalho 22-12-2010 31-12-2010 10
41 542 Baixa Por Acidente de Trabalho 01-01-2011 06-04-2011 96
41 542 Dispensa 05-12-2011 05-12-2011 1
41 542 Dispensa 23-01-2012 23-01-2012 1
41 542 Dispensa 28-04-2012 29-04-2012 2
42 589 Baixa Por Acidente de Trabalho 11-05-2010 26-05-2010 16
42 589 Baixa Por Acidente de Trabalho 27-05-2010 04-06-2010 9
42 589 Baixa Por Doença 10-05-2011 20-05-2011 11
42 589 Baixa Por Doença 10-08-2011 07-09-2011 29
42 589 Baixa Por Doença 20-12-2011 22-12-2011 3
42 589 Baixa Por Acidente de Trabalho 22-02-2012 16-03-2012 24
42 589 Baixa Por Acidente de Trabalho 17-03-2012 02-04-2012 17
42 589 Baixa Por Acidente de Trabalho 16-04-2012 28-04-2012 13
42 589 Baixa Por Acidente de Trabalho 29-04-2012 30-04-2012 2
42 589 Baixa Por Acidente de Trabalho 01-05-2012 07-05-2012 7
42 589 Baixa Por Acidente de Trabalho 08-05-2012 14-05-2012 7
42 589 Baixa Por Acidente de Trabalho 15-05-2012 28-05-2012 14
42 589 Baixa Por Acidente de Trabalho 29-05-2012 27-06-2012 30
42 589 Baixa Por Acidente de Trabalho 28-06-2012 28-06-2012 1
42 589 Baixa Por Doença 29-06-2012 05-07-2012 7
42 589 Baixa Por Doença 06-07-2012 16-07-2012 11
42 589 Baixa Por Acidente de Trabalho 17-07-2012 23-07-2012 7
42 589 Baixa Por Acidente de Trabalho 24-07-2012 10-08-2012 18
42 589 Dispensa 12-08-2012 12-08-2012 1
42 589 Baixa Por Acidente de Trabalho 28-08-2012 10-09-2012 14
42 589 Baixa Por Acidente de Trabalho 11-09-2012 25-09-2012 15
42 589 Baixa Por Acidente de Trabalho 26-09-2012 25-10-2012 30
42 589 Baixa Por Acidente de Trabalho 26-10-2012 23-11-2012 29
Now, remember that the first two columns are part of the ID, then comes the type (or code), then from and to dates, then diff.
Sorry, I can't understand the problem with such info.
If you need my help please complete the input data as I suggested in previous comment, and list the expected output.
There are many open questions and cannot be involved in the actual design of each case.
Instead of putting a long field name for example "datHoraEntradaTrabalho" , you may just call it x in , and once satisfied with a solution rename to required names.
If you need my help please complete the input data as I suggested in previous comment, and list the expected output.
There are many open questions and cannot be involved in the actual design of each case.
Instead of putting a long field name for example "datHoraEntradaTrabalho" , you may just call it x in , and once satisfied with a solution rename to required names.
ASKER
The names aren't important. I can't fill the data you suggested, because the data you suggested already IS the desired output.
To be honest, if you want to understand the problem, the best way is to download the excel file, pick a couple results from the last sheet and filter those results in all the previous sheets. The first sheet contains the original data, the other sheets contain the steps for each CTE in my query, so you can skip those if you like. You can rename all the fields to whatever you want and manipulate the data to whatever you want.
After all, I created the excel file to help other ee experts to understand both the problem and my query.
However, if you still find all those rows too complicated, I'll break it down for just a single result:
code1 code2 other from to diff
41 542 Baixa Por Doença 02-02-2010 21-02-2010 20
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010 17
41 542 Baixa Por Doença 07-07-2010 13-07-2010 7
41 542 Baixa Por Doença 18-10-2010 26-11-2010 40
41 542 Baixa Por Acidente de Trabalho 22-12-2010 31-12-2010 10
41 542 Baixa Por Acidente de Trabalho 01-01-2011 06-04-2011 96
41 542 Dispensa 05-12-2011 05-12-2011 1
41 542 Dispensa 23-01-2012 23-01-2012 1
41 542 Dispensa 28-04-2012 29-04-2012 2
expected:
code1 code2 other from to diff
41 542 Baixa Por Doença 02-02-2010 21-02-2010 20
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010 17
41 542 Baixa Por Doença 18-10-2010 26-11-2010 40
41 542 Baixa Por Acidente de Trabalho 22-12-2010 06-04-2011 106
The problem in itself is really simple. For each code1/code2 IDs, identify consecutive periods of 30 days (not 1 month) or more and then present such data in a compacted way, as seen by the last line of the result.
To be honest, if you want to understand the problem, the best way is to download the excel file, pick a couple results from the last sheet and filter those results in all the previous sheets. The first sheet contains the original data, the other sheets contain the steps for each CTE in my query, so you can skip those if you like. You can rename all the fields to whatever you want and manipulate the data to whatever you want.
After all, I created the excel file to help other ee experts to understand both the problem and my query.
However, if you still find all those rows too complicated, I'll break it down for just a single result:
code1 code2 other from to diff
41 542 Baixa Por Doença 02-02-2010 21-02-2010 20
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010 17
41 542 Baixa Por Doença 07-07-2010 13-07-2010 7
41 542 Baixa Por Doença 18-10-2010 26-11-2010 40
41 542 Baixa Por Acidente de Trabalho 22-12-2010 31-12-2010 10
41 542 Baixa Por Acidente de Trabalho 01-01-2011 06-04-2011 96
41 542 Dispensa 05-12-2011 05-12-2011 1
41 542 Dispensa 23-01-2012 23-01-2012 1
41 542 Dispensa 28-04-2012 29-04-2012 2
expected:
code1 code2 other from to diff
41 542 Baixa Por Doença 02-02-2010 21-02-2010 20
41 542 Baixa Por Acidente de Trabalho 22-02-2010 10-03-2010 17
41 542 Baixa Por Doença 18-10-2010 26-11-2010 40
41 542 Baixa Por Acidente de Trabalho 22-12-2010 06-04-2011 106
The problem in itself is really simple. For each code1/code2 IDs, identify consecutive periods of 30 days (not 1 month) or more and then present such data in a compacted way, as seen by the last line of the result.
OK, sorry about the longer than expected absence...
Was really good fun, enjoyed and found a couple of errors with either expected results, or, maybe stuffed up the inserts, or, simply got it wrong (but have worked through every single example and can explain).
So, the procedure below goes through every consecutive date by Empresa and Funcionario then getting the results for those periods broken out by individual (groups) of TipoTrabalho HoraEntrada HoraSaida.
There are a couple of additional columns at the end to reflect the period it belongs to ( to help with disgnosis) and can be removed.
We use recursive CTE's to carry forward the apprioriate end or start date.
To help make that happen, we first extracct the required data into a temp table and index it to make sure performance will be reasonable.
As the stored procedure, used Number of Days as a parameter - so - if you want 45 days or 60 (or whatever) simply change the days parameter.
Could also add more params to help minimise the select into the temp table (at the moment, just Empressa)
Now, I got an extra 542 and two extra 1375 and looking back, while the individual TipoTrabalho doesnt qulify, it does fall withn consecutive dates for the ID's
Was really good fun, enjoyed and found a couple of errors with either expected results, or, maybe stuffed up the inserts, or, simply got it wrong (but have worked through every single example and can explain).
So, the procedure below goes through every consecutive date by Empresa and Funcionario then getting the results for those periods broken out by individual (groups) of TipoTrabalho HoraEntrada HoraSaida.
There are a couple of additional columns at the end to reflect the period it belongs to ( to help with disgnosis) and can be removed.
We use recursive CTE's to carry forward the apprioriate end or start date.
To help make that happen, we first extracct the required data into a temp table and index it to make sure performance will be reasonable.
As the stored procedure, used Number of Days as a parameter - so - if you want 45 days or 60 (or whatever) simply change the days parameter.
Could also add more params to help minimise the select into the temp table (at the moment, just Empressa)
if object_id('usp_tblTrabalho_periods') is not null drop procedure usp_tblTrabalho_periods
go
create procedure usp_tblTrabalho_periods (@Empresa int, @days int = 30)
AS
Begin
if object_id('tempdb..#tmp_tblTrabalho','U') is not null drop table #tmp_tblTrabalho
;
select row_number() over (partition by FK_ID_intEmpresa,FK_ID_intFuncionario order by datHoraEntradaTrabalho desc) as DRN
, row_number() over (partition by FK_ID_intEmpresa,FK_ID_intFuncionario order by datHoraEntradaTrabalho ASC) as ARN
, * into #tmp_tblTrabalho
from tblTrabalho
where FK_ID_intEmpresa = @empresa
;
create index idx_tmp_tblTrabalho_drn on #tmp_tblTrabalho (drn,FK_ID_intEmpresa,FK_ID_intFuncionario)
;
create index idx_tmp_tblTrabalho_arn on #tmp_tblTrabalho (Arn,FK_ID_intEmpresa,FK_ID_intFuncionario)
;
; with cte_period_ends as
( select drn, arn, FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,datHoraEntradaTrabalho,datHoraSaidaTrabalho, datHoraSaidaTrabalho as nextend, datHoraEntradaTrabalho as priorstart
from #tmp_tblTrabalho
where DRN = 1
union all
select T.DRN, T.ARN, E.FK_ID_intEmpresa,T.FK_ID_intFuncionario,T.FK_ID_intTipoTrabalho,T.datHoraEntradaTrabalho,T.datHoraSaidaTrabalho,
case when datediff(day,T.datHoraSaidaTrabalho,E.datHoraEntradaTrabalho) < 2 then E.nextend else T.datHoraSaidaTrabalho end, T.datHoraEntradaTrabalho
from cte_period_ends E
inner join #tmp_tblTrabalho T on T.FK_ID_intEmpresa = E.FK_ID_intEmpresa and T.FK_ID_intFuncionario = E.FK_ID_intFuncionario and T.DRN = E.DRN + 1
)
, cte_period_commence as
( select DRN, ARN, FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,datHoraEntradaTrabalho,datHoraSaidaTrabalho, nextend, priorstart
from cte_period_ends
where ARN = 1
union all
select E.DRN, E.ARN, C.FK_ID_intEmpresa,E.FK_ID_intFuncionario,E.FK_ID_intTipoTrabalho,E.datHoraEntradaTrabalho,E.datHoraSaidaTrabalho, E.nextend,
case when datediff(day,c.datHoraSaidaTrabalho,E.datHoraEntradaTrabalho) < 2 then C.priorstart else E.datHoraEntradaTrabalho end
from cte_period_commence C
inner join cte_period_ends E on E.FK_ID_intEmpresa = c.FK_ID_intEmpresa and E.FK_ID_intFuncionario = c.FK_ID_intFuncionario and E.ARN = C.ARN + 1
)
select FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,min(datHoraEntradaTrabalho) as datHoraEntradaTrabalho,max(datHoraSaidaTrabalho) as datHoraSaidaTrabalho
, datediff(day,min(datHoraEntradaTrabalho),max(datHoraSaidaTrabalho)) + 1 as Total
, convert(char(10), priorstart,120) + ' to ' + convert(char(10), nextend,120) as Empresa_Funcionario_Period_Group -- remove later
, datediff(day,priorstart,nextend) + 1 as Total_For_Period_Group -- remove later
from cte_period_commence
where datediff(day,priorstart,nextend) >= @days
group by FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,priorstart,nextend
order by 1,2,4,5,3
;
if object_id('tempdb..#tmp_tblTrabalho','U') is not null drop table #tmp_tblTrabalho
;
END
GO
-- now run it :)
exec usp_tblTrabalho_periods 41,30
Now, I got an extra 542 and two extra 1375 and looking back, while the individual TipoTrabalho doesnt qulify, it does fall withn consecutive dates for the ID's
Oh, BTW, my examples and results reflect the original as posted in the question, not the follow up stuff. I will try some of the other examples in the meantime.
ASKER
There is no need to check my queries. Your query does everything right and takes 0 seconds. I had improved my query to 29 seconds, but some results weren't correct, apparently. Namely, if there were two different periods of the same type (I don't think the original sample had this case) it would present them as one. That is, your query shows 16-03-2012 to 17-04-2012 and 14-06-2012 to 26-10-2012, whereas mine would show 16-03-2012 to 26-10-2012, presumably because they are the same type. I wouldn't have noticed it either, if I weren't comparing both results.
Anyway, your query does what was requested and is really fast, so thanks.
Anyway, your query does what was requested and is really fast, so thanks.
Very pleased to have been able to help. I did enjoy it, so thank you for allowing us to help.
Cheers,
Mark Wills
Cheers,
Mark Wills
ASKER
Actually, it isn't quite right yet. Given this data:
FK_ID_intEmpresa FK_ID_intFuncionario FK_ID_intTipoTrabalho datHoraEntradaTrabalho datHoraSaidaTrabalho
42 589 Baixa Por Acidente de Trabalho 2012-02-22 00:00:00 2012-03-16 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-03-17 00:00:00 2012-04-02 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-04-16 00:00:00 2012-04-28 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-04-29 00:00:00 2012-04-30 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-05-01 00:00:00 2012-05-07 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-05-08 00:00:00 2012-05-14 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-05-15 00:00:00 2012-05-28 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-05-29 00:00:00 2012-06-27 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-06-28 00:00:00 2012-06-28 00:00:00
42 589 Baixa Por Doença 2012-06-29 00:00:00 2012-07-05 00:00:00
42 589 Baixa Por Doença 2012-07-06 00:00:00 2012-07-16 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-07-17 00:00:00 2012-07-23 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-07-24 00:00:00 2012-08-10 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-08-28 00:00:00 2012-09-10 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-09-11 00:00:00 2012-09-25 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-09-26 00:00:00 2012-10-25 00:00:00
42 589 Baixa Por Acidente de Trabalho 2012-10-26 00:00:00 2012-11-23 00:00:00
Your code returns (I've changed the column aliases for the output):Emp Num Tipo Ent Sai Dias Periodo DiasTotal
42 589 Baixa Por Acidente de Trabalho 22-02-2012 02-04-2012 41 2012-02-22 to 2012-04-02 41
42 589 Baixa Por Acidente de Trabalho 16-04-2012 10-08-2012 117 2012-04-16 to 2012-08-10 117
42 589 Baixa Por Doença 29-06-2012 16-07-2012 18 2012-04-16 to 2012-08-10 117
42 589 Baixa Por Acidente de Trabalho 28-08-2012 23-11-2012 88 2012-08-28 to 2012-11-23 88
And it should return:Emp Num Tipo Ent Sai Dias Periodo DiasTotal
42 589 Baixa Por Acidente de Trabalho 22-02-2012 02-04-2012 41 2012-02-22 to 2012-04-02 41
42 589 Baixa Por Acidente de Trabalho 16-04-2012 28-06-2012 74 2012-04-16 to 2012-08-10 117
42 589 Baixa Por Doença 29-06-2012 16-07-2012 18 2012-04-16 to 2012-08-10 117
42 589 Baixa Por Acidente de Trabalho 17-07-2012 10-08-2012 25 2012-04-16 to 2012-08-10 117
42 589 Baixa Por Acidente de Trabalho 28-08-2012 23-11-2012 88 2012-08-28 to 2012-11-23 88
ASKER
Checking the output from CTE_Period_Commence, I believe some sort of ROW_NUMBER() will have to be added, although I'm not sure how to adjust it. This is the output for this case:
I've tried a few ROW_NUMBER() variations, but I couldn't find one that would help me fix this.
DRN ARN FK_ID_intEmpresa FK_ID_intFuncionario FK_ID_intTipoTrabalho datHoraEntradaTrabalho datHoraSaidaTrabalho NextEnd PriorStart
16 3 42 589 Baixa Por Acidente de Trabalho 2012-04-16 00:00:00 2012-04-28 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
15 4 42 589 Baixa Por Acidente de Trabalho 2012-04-29 00:00:00 2012-04-30 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
14 5 42 589 Baixa Por Acidente de Trabalho 2012-05-01 00:00:00 2012-05-07 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
13 6 42 589 Baixa Por Acidente de Trabalho 2012-05-08 00:00:00 2012-05-14 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
12 7 42 589 Baixa Por Acidente de Trabalho 2012-05-15 00:00:00 2012-05-28 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
11 8 42 589 Baixa Por Acidente de Trabalho 2012-05-29 00:00:00 2012-06-27 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
10 9 42 589 Baixa Por Acidente de Trabalho 2012-06-28 00:00:00 2012-06-28 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
9 10 42 589 Baixa Por Doença 2012-06-29 00:00:00 2012-07-05 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
8 11 42 589 Baixa Por Doença 2012-07-06 00:00:00 2012-07-16 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
7 12 42 589 Baixa Por Acidente de Trabalho 2012-07-17 00:00:00 2012-07-23 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
6 13 42 589 Baixa Por Acidente de Trabalho 2012-07-24 00:00:00 2012-08-10 00:00:00 2012-08-10 00:00:00 2012-04-16 00:00:00
It would need another column which would have the value (for example) 1 for the first rows for "Baixa Por Acidente de Trabalho", 2 for the ones for "Baixa Por Doença" and 3 for the last ones.I've tried a few ROW_NUMBER() variations, but I couldn't find one that would help me fix this.
Yeah, it is an interesting relationship when they belong to the same "period group" but interrupted by a different Funcionario.
Will need to come up with some kind of rule to describe that data relationship / scenario to force a "break" in the group by part of the query.
I am thinking that we simply start with a 1 in a new column group_break and as we traverse (in the recursive part) we simply add 1 to group_break when Funcionario changes.
Downside of that is we need to check the aggregated days regardless of that group_break.
Which we can do using windows function e.g. sum() over ()
But I will have a play with that scenario and find a way.
So, first thing I'll do is add that relationship / scenario into the original test data as 589.
Will need to come up with some kind of rule to describe that data relationship / scenario to force a "break" in the group by part of the query.
I am thinking that we simply start with a 1 in a new column group_break and as we traverse (in the recursive part) we simply add 1 to group_break when Funcionario changes.
Downside of that is we need to check the aggregated days regardless of that group_break.
Which we can do using windows function e.g. sum() over ()
But I will have a play with that scenario and find a way.
So, first thing I'll do is add that relationship / scenario into the original test data as 589.
ASKER
I've been playing with different row_number scenarios. One that seems most promising is:
ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_int Funcionari o ORDER BY datHoraEntradaTrabalho) - ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_int Funcionari o,FK_ID_in tTipoTraba lho,NextEn d ORDER BY datHoraEntradaTrabalho)
This was inspired by one of the earlier posts by deighton. I would have to test more, but it seems that this would generate mostly unique values.
>> Yeah, it is an interesting relationship when they belong to the same "period group" but interrupted by a different Funcionario.
Not Funcionario. That is part of the composite ID. intTipoTrabalho is the one that interrupts the range. The examples I posted last are regarding a single FK_ID_intEmpresa/FK_ID_int Funcionari o id.
ROW_NUMBER() OVER (PARTITION BY FK_ID_intEmpresa,FK_ID_int
This was inspired by one of the earlier posts by deighton. I would have to test more, but it seems that this would generate mostly unique values.
>> Yeah, it is an interesting relationship when they belong to the same "period group" but interrupted by a different Funcionario.
Not Funcionario. That is part of the composite ID. intTipoTrabalho is the one that interrupts the range. The examples I posted last are regarding a single FK_ID_intEmpresa/FK_ID_int
Yep - my mistake - knew it was TipoTrabalho :)
And dont think row_number() is going to cut it. Something easier ;)
I'll be back (spoken in best Arnold Schwarzenager impersonation).
And dont think row_number() is going to cut it. Something easier ;)
I'll be back (spoken in best Arnold Schwarzenager impersonation).
ASKER
Yeah, I can't even find any reliable combination of row_number() that will be unique enough to group by.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I'm leaving work right now, but I'll test that tomorrow. Thanks for helping out, even though the points are already awarded.
No problems, I am here for the long haul if needed....
ASKER
At first glance, this seems to work. However, I'm going to look into a few more special cases before awarding the answer this time.
One small thing: How would this behave if the table had overlapping periods? On a different table (same structure) there are many ranges that overlap, like:
Code1 01-01-2012 to 31-01-2012
Code1 01-01-2012 to 29-02-2012
Code1 01-02-2012 to 31-05-2012
Code2 01-03-2012 to 31-03-2012
Code1 01-04-2012 to 30-06-2012
This is for a single Funcionario (for this table, Empresa is moot because there is only one, even though the field is still there).
Hopefully, the best expected output would be something like we've arranged except that it will repeat periods with different TipoTrabalho:
Code1 01-01-2012 to 30-06-2012
Code2 01-03-2012 to 31-03-2012
If (like it happens a lot) there are only partial overlaps, then it would show like:
Code1 01-01-2012 to 14-03-2012
Code2 01-03-2012 to 31-03-2012
Code1 30-03-2012 to 30-06-2012
One small thing: How would this behave if the table had overlapping periods? On a different table (same structure) there are many ranges that overlap, like:
Code1 01-01-2012 to 31-01-2012
Code1 01-01-2012 to 29-02-2012
Code1 01-02-2012 to 31-05-2012
Code2 01-03-2012 to 31-03-2012
Code1 01-04-2012 to 30-06-2012
This is for a single Funcionario (for this table, Empresa is moot because there is only one, even though the field is still there).
Hopefully, the best expected output would be something like we've arranged except that it will repeat periods with different TipoTrabalho:
Code1 01-01-2012 to 30-06-2012
Code2 01-03-2012 to 31-03-2012
If (like it happens a lot) there are only partial overlaps, then it would show like:
Code1 01-01-2012 to 14-03-2012
Code2 01-03-2012 to 31-03-2012
Code1 30-03-2012 to 30-06-2012
ASKER
One thing I didn't understand was why you would change the select. After all, it had no practical value. The way it was returned the same results, as long as you add the Group_Break to the GROUP BY list.
One small correction as well: You checking for datediff>=30, but you have to check for datediff+1>=30. I've spotted that quite early, but it wasn't really important, so I didn't bother to mention. But I almost made that mistake again when I pasted your code. :)
One small correction as well: You checking for datediff>=30, but you have to check for datediff+1>=30. I've spotted that quite early, but it wasn't really important, so I didn't bother to mention. But I almost made that mistake again when I pasted your code. :)
Well, a couple of reasons...
The thought was to minimise those rows that we want to group by.
Was using that when debugging the code to be able to simply comment out the outside query.
Yeah, and know about that + 1 (did it in the datediff above) and had intended to simply sub 1 from the parameter, and never got around to it. Could also simply remove the "=" sign from ">=". Preferably do not do date arithmetic like that with functions and arithmetic when it is so much easier to avoid, just that I forgot :)
Trouble with overlapping dates is the count - do we count different calendar days, or accumulate the differences between dates (yeah, and kinda know it is the latter, just trying to avoid that thought for a moment).
We do have recursive queries so should be easy enough to calculate an extra load, just a bit concerned about the aggregation of those differences (maybe), but havent really spent any time thinking about it (just off the top of my head comments).
The thought was to minimise those rows that we want to group by.
Was using that when debugging the code to be able to simply comment out the outside query.
Yeah, and know about that + 1 (did it in the datediff above) and had intended to simply sub 1 from the parameter, and never got around to it. Could also simply remove the "=" sign from ">=". Preferably do not do date arithmetic like that with functions and arithmetic when it is so much easier to avoid, just that I forgot :)
Trouble with overlapping dates is the count - do we count different calendar days, or accumulate the differences between dates (yeah, and kinda know it is the latter, just trying to avoid that thought for a moment).
We do have recursive queries so should be easy enough to calculate an extra load, just a bit concerned about the aggregation of those differences (maybe), but havent really spent any time thinking about it (just off the top of my head comments).
ASKER
Isn't
FROM Table WHERE Condition
the same as
FROM (SELECT * FROM Table WHERE Condition)?
I had the impression that the query optimizer (or whatever the name is) read the code in advance and ran both the same way.
In this specific case, there is no difference in performance, so either solution is good.
Without going through all cases one by one, this seems to be working perfectly. I've tested on a few of the more complicated cases and this is working fine.
As for the overlapping table, I've ran a preliminary test and it seems to work properly, at first glance. I'll do further tests later, but this is not the original question as posted, so I'm going to award the answer. If I require changes, I'll open a new related question for it (though I have yet to know how to do that. Previous efforts to create a related question have failed).
Thanks a lot for your help. Now that the solution works, I'll try to understand how the query itself works, because I love learning this kind of things. :)
FROM Table WHERE Condition
the same as
FROM (SELECT * FROM Table WHERE Condition)?
I had the impression that the query optimizer (or whatever the name is) read the code in advance and ran both the same way.
In this specific case, there is no difference in performance, so either solution is good.
Without going through all cases one by one, this seems to be working perfectly. I've tested on a few of the more complicated cases and this is working fine.
As for the overlapping table, I've ran a preliminary test and it seems to work properly, at first glance. I'll do further tests later, but this is not the original question as posted, so I'm going to award the answer. If I require changes, I'll open a new related question for it (though I have yet to know how to do that. Previous efforts to create a related question have failed).
Thanks a lot for your help. Now that the solution works, I'll try to understand how the query itself works, because I love learning this kind of things. :)
Yep, the query optimizer does do a good job, and it isnt really optimizing the code as such, it is really choosing the best query plan to use. The way the code is written can suggest different query plans (along with any query hints). It is a "cost based" optimizer and will not try every possible combination, so, we can help identify "costs".
But having said that, it often seems that the optimizer has a mind of its own basing its decisions on various stats, cached plans etc...
In this case you are likely to be correct - it makes no difference (other than the way I was writing it and wanting to easily debug by simply commenting out a few lines here and there, along with a potential aggregation within the subquery).
But that might not always be the case where a subquery can simply be incorporated into an outer query and the optimizer behaves the same.
If when reading the code, it logically gives no real advantage to have a subquery, then it is likely that the optimizer will react the same way in terms of query plan. In our case the "WHERE" predicate will probably result in a table scan (well, table spools and concatenations which happens with recursive queries), so doesnt make much difference.
But if I had "join", and more "where" and calculated columns, or differing groups bys, or other predicates (like "having"), then it doesnt always hold true that : "FROM Table WHERE Condition" is same as "FROM (SELECT * FROM Table WHERE Condition)" because of what is happening next with joins, evaluating predicates, or the final select list with respect to any more "where" conditions...
(but again, in this specific case it doesnt really make any difference)
What will always be true is (functionally) if you can comment out lines and still preserve the query, then it probably should be left with commented out lines. So, the query in question, could have been better written as you have suggested :
I have no doubts whatsoever that the query should work with overlapping dates - the datediff to check for contiguous days is simply check for < 2 so includes overlapping dates (which would go negative).
If you ever want the total days consumed within the period though (within priorstart and nextend), then that is when it currently only considers a datediff and that might not yield the correct results.
So, I did have considerable concern as to what we needed to measure - if contiguous days (as written) or consumed days.
But you will also notice that we removed those two "checking" total columns from the final result so that they no longer report potential conflicts from any overlapping dates. And there was a deliberate reason to exclude them from the last tests.
And time to come clean to explain why they were removed (and the invention of the "P" subquery)....
I did have some overlapping dates in my test, so was OK with the concept, but having tested with overlapping dates is also the reason why I removed those columns and hence my comment above "We do have recursive queries so should be easy enough to calculate an extra load, just a bit concerned about the aggregation of those differences..."
The concern comes in in a case where (showing datediff, not inclusive days the "plus 1") :
2012-01-01 to 2012-01-21 = 20 days
2012-01-02 to 2012-01-22 = 20 days
19 of those days are overlapping, but, looking at the "range" of days
2012-01-01 to 2021-01-22 = 21 days
And will not be reported because the range of different (contiguous) days is only 21.
So, we need to consider the extra "load" on days by including the (aggregation) of those overlapping days - the extra 19 days added to our range of 21 to give us the real total of 40 days being actually consumed (rather than 21 days being the measure of contiguous days).
That subquery was heading off into the wild blue yonder doing some of that calculating "load", just a slightly different basis for aggregation so we could sum() in that load to our date range... That different aggregation meant we needed to subquery to find the qualifying entries before we could start doing the reporting of them given the different basis of the reporting "group by".
But having said that, it often seems that the optimizer has a mind of its own basing its decisions on various stats, cached plans etc...
In this case you are likely to be correct - it makes no difference (other than the way I was writing it and wanting to easily debug by simply commenting out a few lines here and there, along with a potential aggregation within the subquery).
But that might not always be the case where a subquery can simply be incorporated into an outer query and the optimizer behaves the same.
If when reading the code, it logically gives no real advantage to have a subquery, then it is likely that the optimizer will react the same way in terms of query plan. In our case the "WHERE" predicate will probably result in a table scan (well, table spools and concatenations which happens with recursive queries), so doesnt make much difference.
But if I had "join", and more "where" and calculated columns, or differing groups bys, or other predicates (like "having"), then it doesnt always hold true that : "FROM Table WHERE Condition" is same as "FROM (SELECT * FROM Table WHERE Condition)" because of what is happening next with joins, evaluating predicates, or the final select list with respect to any more "where" conditions...
(but again, in this specific case it doesnt really make any difference)
What will always be true is (functionally) if you can comment out lines and still preserve the query, then it probably should be left with commented out lines. So, the query in question, could have been better written as you have suggested :
select FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,min(datHoraEntradaTrabalho) as datHoraEntradaTrabalho,max(datHoraSaidaTrabalho) as datHoraSaidaTrabalho
, datediff(day,min(datHoraEntradaTrabalho),max(datHoraSaidaTrabalho)) + 1 as Total
-- from (
-- select *
from cte_period_commence
where datediff(day,priorstart,nextend) > @days
-- ) P
group by FK_ID_intEmpresa,FK_ID_intFuncionario,group_break,FK_ID_intTipoTrabalho,priorstart,nextend
order by 1,2,4,5,3
I have no doubts whatsoever that the query should work with overlapping dates - the datediff to check for contiguous days is simply check for < 2 so includes overlapping dates (which would go negative).
If you ever want the total days consumed within the period though (within priorstart and nextend), then that is when it currently only considers a datediff and that might not yield the correct results.
So, I did have considerable concern as to what we needed to measure - if contiguous days (as written) or consumed days.
But you will also notice that we removed those two "checking" total columns from the final result so that they no longer report potential conflicts from any overlapping dates. And there was a deliberate reason to exclude them from the last tests.
And time to come clean to explain why they were removed (and the invention of the "P" subquery)....
I did have some overlapping dates in my test, so was OK with the concept, but having tested with overlapping dates is also the reason why I removed those columns and hence my comment above "We do have recursive queries so should be easy enough to calculate an extra load, just a bit concerned about the aggregation of those differences..."
The concern comes in in a case where (showing datediff, not inclusive days the "plus 1") :
2012-01-01 to 2012-01-21 = 20 days
2012-01-02 to 2012-01-22 = 20 days
19 of those days are overlapping, but, looking at the "range" of days
2012-01-01 to 2021-01-22 = 21 days
And will not be reported because the range of different (contiguous) days is only 21.
So, we need to consider the extra "load" on days by including the (aggregation) of those overlapping days - the extra 19 days added to our range of 21 to give us the real total of 40 days being actually consumed (rather than 21 days being the measure of contiguous days).
That subquery was heading off into the wild blue yonder doing some of that calculating "load", just a slightly different basis for aggregation so we could sum() in that load to our date range... That different aggregation meant we needed to subquery to find the qualifying entries before we could start doing the reporting of them given the different basis of the reporting "group by".
Oh, for for overlapping dates, the ARN and DRN row_number() needs to change just a little to make sure we get those row_numbers() into correct descending and ascending sequence.
Right now they just consider (an assumed unique) datHoraEntradaTrabalho for sequencing of dates.
Right now they just consider (an assumed unique) datHoraEntradaTrabalho for sequencing of dates.
ASKER
As for the syntax, thanks. I learned a lot with that.
As for the dates, your example shouldn't return anything. I really only want contiguous days, not aggregated.
I'm not sure if the query does need changes. It was a cursory glance, but the results seemed to be correct. I can't be sure until I examine them more closely, but that will only happen on monday. I'll let you know how it goes.
As for the dates, your example shouldn't return anything. I really only want contiguous days, not aggregated.
I'm not sure if the query does need changes. It was a cursory glance, but the results seemed to be correct. I can't be sure until I examine them more closely, but that will only happen on monday. I'll let you know how it goes.
ASKER
Ok, I noticed a small "bug". Not too important, but I'm not sure why it happens. Given this data:
FK_ID_intEmpresa FK_ID_intFuncionario FK_ID_intTipoTrabalho datHoraEntradaTrabalho datHoraSaidaTrabalho
32 14886 Lic. Parental 2012-08-16 00:00:00 2012-09-15 00:00:00
32 14886 Lic. Parental 2012-09-16 00:00:00 2012-10-15 00:00:00
32 14886 Doença 2011-07-26 00:00:00 2011-08-15 00:00:00
32 14886 Doença 2012-02-05 00:00:00 2012-02-11 00:00:00
32 14886 Doença 2012-02-16 00:00:00 2012-02-27 00:00:00
32 14886 Doença 2012-03-07 00:00:00 2012-03-15 00:00:00
32 14886 Doença 2012-03-16 00:00:00 2012-04-15 00:00:00
32 14886 Doença 2012-04-16 00:00:00 2012-05-15 00:00:00
32 14886 Doença 2012-05-16 00:00:00 2012-06-07 00:00:00
32 14886 Lic. Parental 2012-06-08 00:00:00 2012-06-15 00:00:00
32 14886 Lic. Parental 2012-06-08 00:00:00 2012-07-15 00:00:00
32 14886 Lic. Parental 2012-07-16 00:00:00 2012-08-15 00:00:00
The query returns:14886 Doença 07-03-2012 07-06-2012 93 07-03-2012 to 15-10-2012 223
14886 Lic. Parental 08-06-2012 15-07-2012 38 07-03-2012 to 15-10-2012 223
14886 Lic. Parental 16-07-2012 15-10-2012 92 16-07-2012 to 15-10-2012 92
Not sure why it's returning the last line, especially why it's with a different range. It's something that you can easily identify when looking at it, but it could be complicated for any code to identify and disregard.
ASKER
This one seems more strange:
FK_ID_intEmpresa FK_ID_intFuncionario FK_ID_intTipoTrabalho datHoraEntradaTrabalho datHoraSaidaTrabalho
32 14143 Doença 2012-09-13 00:00:00 2012-10-18 00:00:00
32 14143 Parto 2012-09-01 00:00:00 2012-09-14 00:00:00
32 14143 Parto 2012-08-01 00:00:00 2012-08-31 00:00:00
32 14143 Doença 2010-09-21 00:00:00 2010-10-15 00:00:00
32 14143 Doença 2010-10-16 00:00:00 2010-12-31 00:00:00
32 14143 Doença 2011-07-05 00:00:00 2011-07-17 00:00:00
32 14143 Doença 2011-07-05 00:00:00 2011-07-31 00:00:00
32 14143 Doença 2011-12-26 00:00:00 2012-01-18 00:00:00
32 14143 Doença 2012-01-01 00:00:00 2012-01-31 00:00:00
32 14143 Doença 2012-01-24 00:00:00 2012-02-12 00:00:00
32 14143 Doença 2012-02-13 00:00:00 2012-02-23 00:00:00
32 14143 Doença 2012-03-24 00:00:00 2012-03-12 00:00:00
32 14143 Doença 2012-02-24 00:00:00 2012-03-12 00:00:00
32 14143 Doença 2012-03-13 00:00:00 2012-04-11 00:00:00
32 14143 Doença 2012-04-01 00:00:00 2012-04-17 00:00:00
32 14143 Parto 2012-04-18 00:00:00 2012-04-30 00:00:00
32 14143 Parto 2012-05-01 00:00:00 2012-05-31 00:00:00
32 14143 Parto 2012-06-01 00:00:00 2012-06-30 00:00:00
32 14143 Parto 2012-07-01 00:00:00 2012-07-31 00:00:00
results:14143 Doença 01-01-2012 11-04-2012 102 01-01-2012 to 12-03-2012 72
14143 Doença 01-04-2012 17-04-2012 17 01-04-2012 to 18-10-2012 201
14143 Parto 18-04-2012 14-09-2012 150 01-04-2012 to 18-10-2012 201
14143 Doença 13-09-2012 18-10-2012 36 01-04-2012 to 18-10-2012 201
First and second lines should be part of the same. However, I detected that one record had a start date after the end date. When I removed it, it returned the desired results. If that is the only problem, then nothing need be done. I just need to change the query that fills the table to filter these invalid records.
>> one record had a start date after the end date
Yeah, think I assume that they will be all OK, so the sequences are probably mucked up and definitely not being checked for.
I will test both the above two scenarios and see what I can see...
Yeah, think I assume that they will be all OK, so the sequences are probably mucked up and definitely not being checked for.
I will test both the above two scenarios and see what I can see...
ASKER
As I said, if it was only that, then don't worry about it. I have set the query to ignore these when populating the table. They shouldn't exist in the first place anyway.
ASKER
One other small thing I noticed:
13053 Assist. Familia 01-01-2012 24-02-2012 55 01-01-2012 to 20-11-2012 325
13053 Doença 25-02-2012 25-03-2012 30 01-01-2012 to 20-11-2012 325
13053 Assist. Familia 26-03-2012 24-04-2012 30 01-01-2012 to 20-11-2012 325
13053 Doença 26-03-2012 24-04-2012 30 01-01-2012 to 20-11-2012 325
13053 Assist. Familia 25-04-2012 20-11-2012 210 01-01-2012 to 20-11-2012 325
The 3rd and 5th line should be grouped. This is probably because of the order and because both the 3rd and 4th lines start on the same date. Don't know if this is fixable, but if not, it's not too important, because the full period and total count are correct.
ASKER
The first case (14886), now returns:
One thing that should be noted is that I'm restricting records to 2012. If a record starts before 2012, I simply insert it as 01-01-2012. Likewise for after 2012 (31-12-2012). Shouldn't make much difference, but I thought you should know.
14886 Doença 07-03-2012 07-06-2012 93 07-03-2012 to 15-06-2012 101
14886 Lic. Parental 08-06-2012 15-07-2012 38 07-03-2012 to 15-06-2012 101
14886 Lic. Parental 16-07-2012 15-10-2012 92 07-03-2012 to 15-10-2012 223
No change was made, so I have no idea why it did this. Still not correct though.One thing that should be noted is that I'm restricting records to 2012. If a record starts before 2012, I simply insert it as 01-01-2012. Likewise for after 2012 (31-12-2012). Shouldn't make much difference, but I thought you should know.
Yeah, that one could get interesting... Same dates... and all of it fits within the same "group" period.
ASKER
If this is too much trouble, just let it go. The way it is now is good enough. I just like it to be as best as it possibly can, especially if I intend to automatize things in the future. But this is already great the way it is, especially because I had nothing like this before.
ASKER
Yet another strange case, probably because of all the rows that start with the same date. In this case, it's the total period that is incorrect:
FK_ID_intEmpresa FK_ID_intFuncionario FK_ID_intTipoTrabalho datHoraEntradaTrabalho datHoraSaidaTrabalho
32 9045 Doença 2012-01-01 00:00:00 2012-01-04 00:00:00
32 9045 Parto 2012-01-05 00:00:00 2012-02-29 00:00:00
32 9045 Lic. Parental 2012-01-05 00:00:00 2012-06-02 00:00:00
32 9045 Parto 2012-01-05 00:00:00 2012-01-31 00:00:00
32 9045 Parto 2012-02-01 00:00:00 2012-03-31 00:00:00
32 9045 Parto 2012-03-15 00:00:00 2012-04-16 00:00:00
results:9045 Parto 05-01-2012 29-02-2012 56 01-01-2012 to 16-04-2012 107
9045 Lic. Parental 05-01-2012 02-06-2012 150 01-01-2012 to 16-04-2012 107
9045 Parto 01-02-2012 16-04-2012 76 01-01-2012 to 16-04-2012 107
ASKER
Sorry, it actually results:
9045 Doença 01-01-2012 04-01-2012 4 01-01-2012 to 16-04-2012 107
9045 Parto 05-01-2012 29-02-2012 56 01-01-2012 to 16-04-2012 107
9045 Lic. Parental 05-01-2012 02-06-2012 150 01-01-2012 to 16-04-2012 107
9045 Parto 01-02-2012 16-04-2012 76 01-01-2012 to 16-04-2012 107
The first line wasn't pasted the first time.
ASKER
This last one is actually important. I mean, as long as the total period is correct, the exact way each individual one is presented isn't as important. But the total period must be assured to be correct. If you want, I'll open a new question, as this is a new problem not completely related to OQ.
Maybe... Can get back to checking code in a few hours. Can you wait a little before opening a new question ?
Seems to be with overlapping dates and have a few ideas (remember the ARN and DRN classification only used start date and expected them to be unique per row).
I'll post back here soonish...
Seems to be with overlapping dates and have a few ideas (remember the ARN and DRN classification only used start date and expected them to be unique per row).
I'll post back here soonish...
ASKER
I'm not in any hurry. This particular case will only be useful in a couple months, most likely.
ASKER
Well, did you advance anything or should I open a new question?
You will never guess what I am in the middle of :)
ASKER
:)
As I said, there is no rush. I just thought that, if it's giving you much trouble, I might open another question. After all, it's a different solution, so you should be awarded more points.
As I said, there is no rush. I just thought that, if it's giving you much trouble, I might open another question. After all, it's a different solution, so you should be awarded more points.
OK, with that last one, I am pretty sure it is the row_number() function - needs to take into account the end and start dates to make sure of the sequences.
But it is probably unfair of me to excercise your patience for so very long.
So, open up the new question - there are a lot of brilliant experts in SQL and I am sure that someone (hopefully me) will be able to assist you without you having to wait all this time just on me...
But it is probably unfair of me to excercise your patience for so very long.
So, open up the new question - there are a lot of brilliant experts in SQL and I am sure that someone (hopefully me) will be able to assist you without you having to wait all this time just on me...
declare @Empresa int = 32, @days int = 30
if object_id('tempdb..#tmp_tblTrabalho','U') is not null drop table #tmp_tblTrabalho
;
select row_number() over (partition by FK_ID_intEmpresa,FK_ID_intFuncionario order by datHoraSaidaTrabalho DESC, datHoraEntradaTrabalho DESC) as DRN
, row_number() over (partition by FK_ID_intEmpresa,FK_ID_intFuncionario order by datHoraEntradaTrabalho ASC,datHoraEntradaTrabalho ASC) as ARN
, * into #tmp_tblTrabalho
from tblTrabalho
where FK_ID_intEmpresa = @empresa
;
create index idx_tmp_tblTrabalho_drn on #tmp_tblTrabalho (drn,FK_ID_intEmpresa,FK_ID_intFuncionario)
;
create index idx_tmp_tblTrabalho_arn on #tmp_tblTrabalho (Arn,FK_ID_intEmpresa,FK_ID_intFuncionario)
;
; with cte_period_ends as
( select drn, arn, FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,datHoraEntradaTrabalho,datHoraSaidaTrabalho, datHoraSaidaTrabalho as nextend, datHoraEntradaTrabalho as priorstart
from #tmp_tblTrabalho
where DRN = 1
union all
select T.DRN, T.ARN, E.FK_ID_intEmpresa,T.FK_ID_intFuncionario,T.FK_ID_intTipoTrabalho,T.datHoraEntradaTrabalho,T.datHoraSaidaTrabalho,
case when datediff(day,T.datHoraSaidaTrabalho,E.datHoraEntradaTrabalho) < 2 then E.nextend else T.datHoraSaidaTrabalho end, T.datHoraEntradaTrabalho
from cte_period_ends E
inner join #tmp_tblTrabalho T on T.FK_ID_intEmpresa = E.FK_ID_intEmpresa and T.FK_ID_intFuncionario = E.FK_ID_intFuncionario and T.DRN = E.DRN + 1
)
, cte_period_commence as
( select DRN, ARN, FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,datHoraEntradaTrabalho,datHoraSaidaTrabalho, nextend, priorstart, 1 as group_break
from cte_period_ends
where ARN = 1
union all
select E.DRN, E.ARN, C.FK_ID_intEmpresa,E.FK_ID_intFuncionario,E.FK_ID_intTipoTrabalho,E.datHoraEntradaTrabalho,E.datHoraSaidaTrabalho, E.nextend,
case when datediff(day,c.datHoraSaidaTrabalho,E.datHoraEntradaTrabalho) < 2 then C.priorstart else E.datHoraEntradaTrabalho end,
case when C.FK_ID_intTipoTrabalho = E.FK_ID_intTipoTrabalho then c.group_break else c.group_break + 1 end
from cte_period_commence C
inner join cte_period_ends E on E.FK_ID_intEmpresa = c.FK_ID_intEmpresa and E.FK_ID_intFuncionario = c.FK_ID_intFuncionario and E.ARN = C.ARN + 1
)
select FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,min(datHoraEntradaTrabalho) as datHoraEntradaTrabalho,max(datHoraSaidaTrabalho) as datHoraSaidaTrabalho
, datediff(day,min(datHoraEntradaTrabalho),max(datHoraSaidaTrabalho)) + 1 as Total
from (
select *
from cte_period_commence
where datediff(day,priorstart,nextend) >= @days
) P
group by FK_ID_intEmpresa,FK_ID_intFuncionario,group_break,FK_ID_intTipoTrabalho,priorstart,nextend
order by 1,2,4,5,3
;
if object_id('tempdb..#tmp_tblTrabalho','U') is not null drop table #tmp_tblTrabalho
;
Right...
Made changes to the above, so ignore that.
Those overlapping dates are really a pain...
For "Lic. Parental" we have 150 days but a fair portion of those overlap with others... for example, Parto is wholly contained within "Lic Parental" dates, but because they are different TipoTrabalho then they show...
Anyway, check out the code below and please let me know any errors and the expected outcome (along with the input / raw as you have done above).
Made changes to the above, so ignore that.
Those overlapping dates are really a pain...
For "Lic. Parental" we have 150 days but a fair portion of those overlap with others... for example, Parto is wholly contained within "Lic Parental" dates, but because they are different TipoTrabalho then they show...
Anyway, check out the code below and please let me know any errors and the expected outcome (along with the input / raw as you have done above).
declare @Empresa int = 32, @days int = 30
if object_id('tempdb..#tmp_tblTrabalho','U') is not null drop table #tmp_tblTrabalho
;
select row_number() over (partition by FK_ID_intEmpresa,FK_ID_intFuncionario order by datHoraSaidaTrabalho DESC, datHoraEntradaTrabalho DESC) as DRN
, row_number() over (partition by FK_ID_intEmpresa,FK_ID_intFuncionario order by datHoraEntradaTrabalho ASC, datHoraSaidaTrabalho ASC) as ARN
, * into #tmp_tblTrabalho
from tblTrabalho T
where FK_ID_intEmpresa = @empresa
and datHoraSaidaTrabalho > datHoraEntradaTrabalho -- NEW CODE to exlcude erroneous dates
and not exists (select NULL from tblTrabalho T1 -- NEW CODE to exclude wholly contained dupe of Empressa+Funcionario+TipoTrabalho
where T.FK_ID_intEmpresa = T1.FK_ID_intEmpresa
and T.FK_ID_intFuncionario = T1.FK_ID_intFuncionario
and T.FK_ID_intTipoTrabalho = T1.FK_ID_intTipoTrabalho
and ((T.datHoraEntradaTrabalho >= T1.datHoraEntradaTrabalho and T.datHoraSaidaTrabalho < T1.datHoraSaidaTrabalho)
or (T.datHoraEntradaTrabalho > T1.datHoraEntradaTrabalho and T.datHoraSaidaTrabalho <= T1.datHoraSaidaTrabalho))
);
select * from #tmp_tblTrabalho order by 2,1
select * from #tmp_tblTrabalho order by 1,2
create index idx_tmp_tblTrabalho_drn on #tmp_tblTrabalho (drn,FK_ID_intEmpresa,FK_ID_intFuncionario)
;
create index idx_tmp_tblTrabalho_arn on #tmp_tblTrabalho (Arn,FK_ID_intEmpresa,FK_ID_intFuncionario)
;
; with cte_period_ends as
( select drn, arn, FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,datHoraEntradaTrabalho,datHoraSaidaTrabalho, datHoraSaidaTrabalho as nextend, datHoraEntradaTrabalho as priorstart
from #tmp_tblTrabalho
where DRN = 1
union all
select T.DRN, T.ARN, E.FK_ID_intEmpresa,T.FK_ID_intFuncionario,T.FK_ID_intTipoTrabalho,T.datHoraEntradaTrabalho,T.datHoraSaidaTrabalho,
case when datediff(day,T.datHoraSaidaTrabalho,E.datHoraEntradaTrabalho) < 2 then E.nextend else T.datHoraSaidaTrabalho end, T.datHoraEntradaTrabalho
from cte_period_ends E
inner join #tmp_tblTrabalho T on T.FK_ID_intEmpresa = E.FK_ID_intEmpresa and T.FK_ID_intFuncionario = E.FK_ID_intFuncionario and T.DRN = E.DRN + 1
)
, cte_period_commence as
( select DRN, ARN, FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,datHoraEntradaTrabalho,datHoraSaidaTrabalho, nextend, priorstart, 1 as group_break
from cte_period_ends
where ARN = 1
union all
select E.DRN, E.ARN, C.FK_ID_intEmpresa,E.FK_ID_intFuncionario,E.FK_ID_intTipoTrabalho,E.datHoraEntradaTrabalho,E.datHoraSaidaTrabalho, E.nextend,
case when datediff(day,c.datHoraSaidaTrabalho,E.datHoraEntradaTrabalho) < 2 then C.priorstart else E.datHoraEntradaTrabalho end,
case when C.FK_ID_intTipoTrabalho = E.FK_ID_intTipoTrabalho then c.group_break else c.group_break + 1 end
from cte_period_commence C
inner join cte_period_ends E on E.FK_ID_intEmpresa = c.FK_ID_intEmpresa and E.FK_ID_intFuncionario = c.FK_ID_intFuncionario and E.ARN = C.ARN + 1
)
-- select *
-- from cte_period_commence
-- where datediff(day,priorstart,nextend) >= @days
select FK_ID_intEmpresa,FK_ID_intFuncionario,FK_ID_intTipoTrabalho,min(datHoraEntradaTrabalho) as datHoraEntradaTrabalho,max(datHoraSaidaTrabalho) as datHoraSaidaTrabalho
, datediff(day,min(datHoraEntradaTrabalho),max(datHoraSaidaTrabalho)) + 1 as Total_TipoTrabalho_Days
, priorstart as Empressa_Funcionario_Period_Start, nextend as Empressa_Funcionario_Period_End, datediff(day, priorstart, nextend) + 1 as Total_Period_Days
from cte_period_commence
where datediff(day,priorstart,nextend) >= @days
group by FK_ID_intEmpresa,FK_ID_intFuncionario,group_break,FK_ID_intTipoTrabalho,priorstart,nextend
order by 1,2,4,5,3
;
if object_id('tempdb..#tmp_tblTrabalho','U') is not null drop table #tmp_tblTrabalho
;
ASKER
I won't really need this for at least another month. It might have some other uses, but those aren't important right now. So if you want a shot at it, I don't mind waiting.
Regarding your code above:
1- ARN has the same field twice. Which position is datHoraSaidaTrabalho supposed to be in?
2- DRN orders datHoraSaidaTrabalho before datHoraEntradaTrabalho. Is this how it should be? If so, why? Wouldn't you want to order by in before ordering by out?
Using
ORDER BY datHoraEntradaTrabalho ASC,datHoraSaidaTrabalho ASC) ARN
the total period isn't quite correct. Nor does it fully group the results. For example, given these values:
Regarding your code above:
1- ARN has the same field twice. Which position is datHoraSaidaTrabalho supposed to be in?
2- DRN orders datHoraSaidaTrabalho before datHoraEntradaTrabalho. Is this how it should be? If so, why? Wouldn't you want to order by in before ordering by out?
Using
ORDER BY datHoraEntradaTrabalho ASC,datHoraSaidaTrabalho ASC) ARN
the total period isn't quite correct. Nor does it fully group the results. For example, given these values:
32 6853 Doença 2012-06-21 00:00:00 2012-07-19 00:00:00
32 6853 Doença 2012-07-20 00:00:00 2012-08-19 00:00:00
32 6853 Doença 2012-08-20 00:00:00 2012-09-27 00:00:00
32 6853 Parto 2012-08-28 00:00:00 2012-09-15 00:00:00
32 6853 Parto 2012-09-16 00:00:00 2012-10-15 00:00:00
32 6853 Parto 2012-10-16 00:00:00 2012-11-15 00:00:00
32 6853 Parto 2012-11-16 00:00:00 2012-12-15 00:00:00
It returns:6853 Doença 21-06-2012 19-08-2012 60 21-06-2012 to 19-08-2012 60
6853 Doença 20-08-2012 27-09-2012 39 21-06-2012 to 15-12-2012 178
6853 Parto 28-08-2012 15-12-2012 110 21-06-2012 to 15-12-2012 178
Nah, you didnt use the latest code....
But DRN is meant to be picking up the "last" date in a sequence. ARN then goes down the First date in a sequence. If they are adjoing dates then we carry over the "last" (ie the biggest in DRN sequence) or carry over the "first" (ie the smallest in ARN sequence).
We cant simply do one sequence - we have to go both directions.
But DRN is meant to be picking up the "last" date in a sequence. ARN then goes down the First date in a sequence. If they are adjoing dates then we carry over the "last" (ie the biggest in DRN sequence) or carry over the "first" (ie the smallest in ARN sequence).
We cant simply do one sequence - we have to go both directions.
ASKER
Last post was made before I saw the new code. However, they return the same for this situation. Not sure why it's not grouping the total period. Probably for the same reason it's not grouping Doença as well.
You don't need to worry about inverted dates. Those are already filtered beforehand and cannot exist in the table anymore.
You don't need to worry about inverted dates. Those are already filtered beforehand and cannot exist in the table anymore.
The latest data sample wont group because of a date being wholly contained within another - so - the sequence is thrown out...
Doença 2012-08-20 00:00:00 2012-09-27 00:00:00
Parto 2012-08-28 00:00:00 2012-09-15 00:00:00
Here parto is wholly contained, so either which way it checks, it stumbles across something "out of sequence" in essence.
Doença 2012-08-20 00:00:00 2012-09-27 00:00:00
Parto 2012-08-28 00:00:00 2012-09-15 00:00:00
Here parto is wholly contained, so either which way it checks, it stumbles across something "out of sequence" in essence.
ASKER
So, with this approach you can't get the ranges right for these cases? Does it require a different approach (in which case I open a new question) or just some fiddling (in which case I wait a bit more)?
Well, no, not with the need to currently check for contiguous days, but then break up by TipoTrabalho - because while the dates overlap, they are different TipoTrabalho...
We could simply check contiguous days, then report any TipoTrabalho that falls with those days. At the moment it is kind of doing both at the same time, and while we might want sequence to follow a specific TipoTrabalho in some cases, we still need to follow dates by empresa and funcionario.
I would be inclined to report contiguous periods (just by empresa and funcionario ignoring TipoTrabalho), then from those dates, simply report the number of days that each TipoTrabahlo consumes (without trying to link up consecutive dates for the TipoTrabalho), or, show the details of each row that qualifies within the period as a detail item sorted into TipoTrabalho and then date sequence. The challenge we have is that the 30 days might be made up from different TipoTrabalho's which is what we are currently doing...
Maybe we can come up with some "pre-canned" scenarios and show what is required from each scenario with overlapping dates, contained dates, for multiple TipoTrabalho's.
And yes, think the scenario has changed with the overlapping periods to warrant a new question. The original scenario without overlapping dates is pretty much handled, and it might take on a new approach (will probably need to) for the new scenarios.
We could simply check contiguous days, then report any TipoTrabalho that falls with those days. At the moment it is kind of doing both at the same time, and while we might want sequence to follow a specific TipoTrabalho in some cases, we still need to follow dates by empresa and funcionario.
I would be inclined to report contiguous periods (just by empresa and funcionario ignoring TipoTrabalho), then from those dates, simply report the number of days that each TipoTrabahlo consumes (without trying to link up consecutive dates for the TipoTrabalho), or, show the details of each row that qualifies within the period as a detail item sorted into TipoTrabalho and then date sequence. The challenge we have is that the 30 days might be made up from different TipoTrabalho's which is what we are currently doing...
Maybe we can come up with some "pre-canned" scenarios and show what is required from each scenario with overlapping dates, contained dates, for multiple TipoTrabalho's.
And yes, think the scenario has changed with the overlapping periods to warrant a new question. The original scenario without overlapping dates is pretty much handled, and it might take on a new approach (will probably need to) for the new scenarios.
ASKER
I will open a new question tomorrow. It's only fair that you get credited (or have a shot at it) for the extra work. Thanks for your effort, even though the question was already closed. I really appreciate your help.
ASKER
select C.ADate,
CASE WHERE EXISTS(SELECT 0 FROM YourDataTable Y WHERE C.ADate Between Y.Start And Y.End ) THEN 1 ELSE 0 END AS FUNC
From Calendar C
so that gives you a series of records with 0 or 1 in runs
e.g
2012-01-01 0
2012-01-02 1
2012-01-03 1
2012-01-04 1
2012-01-05 1
2012-01-01 0
ok so imagine you wanted to find any run of 4 exactly, how does it help?
now get the difference in your calculated values between one day and the next (put the 1st query in a CTE for ease)
WITH CTE AS (
select C.ADate,
CASE WHERE EXISTS(SELECT 0 FROM YourDataTable Y WHERE C.ADate Between Y.Start And Y.End ) THEN 1 ELSE 0 END AS FUNC
From Calendar C)
SELECT C1.Adate, C1.FUNC- C2.FUNC AS Dif FROM CTE C1 JOIN CTE C2 ON (c1.Adate - 1) = C2.Adate
so that should give yoiu
2012-01-01 0
2012-01-02 1
2012-01-03 0
2012-01-04 0
2012-01-05 0
2012-01-01 -1
so then you have to find 1 and -1 that are separated by 30 days (with only zeroes between)
then you could do
WITH CTE AS (
select C.ADate,
CASE WHERE EXISTS(SELECT 0 FROM YourDataTable Y WHERE C.ADate Between Y.Start And Y.End ) THEN 1 ELSE 0 END AS FUNC
From Calendar C),
CTE_DIF AS
(SELECT C1.Adate, C1.FUNC- C2.FUNC AS Dif FROM CTE C1 JOIN CTE C2 ON (c1.Adate - 1) = C2.Adate)
SELECT CD.Adate FROM CTE_DIF CD WHERE CD.Dif = 1 AND CD.Adate - (SELECT MIN(CD2.ADate) FROM CTE_DID CD2 WHERE CD.ADate < CD2.ADate AND CD2.DIf = -1) = -30
that should then select any run of exactly 30
That's something I saw in a SQL book that they referred to as 'The Islands Problem'
this may help, I don't know
put some corrections in there