Combining multiple rows in TSQL query - sql

I have a table with data like this
Road Item Response added_on
1 82 Yes 7/11/16
1 83 Yes 7/11/16
1 84 Yes 7/11/16
2 82 Yes 8/11/16
2 83 No 8/11/16
2 85 Yes 8/11/16
This reflects an assessment of a road where 'item' is things being assessed.
Some items will always be done during an assessment (82, 83) where others are optional (84, 85).
I want to return something that combines all of the assessment results for a road/date, returning null if that item was not assessed. And also only returning last month's results. For example
Road 82 83 84 85 added_on
1 Yes Yes Yes 7/11/16
2 Yes No Yes 8/11/16
I have tried a multiple self joins like this but it's returning nothing.
FROM assess AS A
JOIN assess AS B
ON A.road = B.road AND a.added_on = B.added on
JOIN assess AS C
ON A.road = C.road AND a.added_on = C.added on
JOIN assess AS D
ON A.road = D.road AND a.added_on = D.added on
WHERE A.item = '81'
AND B.item = '82'
AND (C.item = '83' OR C.item IS NULL)
AND (D.item = '84' OR D.item IS NULL)
AND datepart(month,A.added_on) = datepart(month,getdate()) -1
To clarify,
-no road is assessed more than once a day
-each item is only assessed once, and sometimes is NULL i.e. not applicable
-multiple roads are assessed each day
-this table has other assessments but we aren't worried about those.
Any ideas? Using SQL server 2008. Thanks.

Assuming you need to go Dynamic
Declare #SQL varchar(max)
Select #SQL = Stuff((Select Distinct ',' + QuoteName(Item) From YourTable Order By 1 For XML Path('')),1,1,'')
Select #SQL = 'Select [Road],' + #SQL + ',[added_on]
From YourTable
Pivot (max(Response) For Item in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
EDIT - The SQL Generated is as follows. (just in case you can't go
dynamic)
Select [Road],[82],[83],[84],[85],[added_on]
From YourTable
Pivot (max(Response) For Item in ([82],[83],[84],[85]) ) p

Another way of achieving this is less elegant, but uses basic operations if you don't want to use pivot.
Load up test data
create table #assess ( road int, item varchar(10), response varchar(3), added_on date )
insert #assess( road, item, response, added_on )
values
(1, '82', 'Yes', '2016-07-11' )
, (1, '83', 'Yes', '2016-07-11' )
, (1, '84', 'Yes', '2016-07-11' )
, (2, '82', 'Yes', '2016-08-11' )
, (2, '83', 'No', '2016-08-11' )
, (2, '85', 'Yes', '2016-08-11' )
Process the data
-- Get every possible `item`
select distinct item into #items from #assess
-- Ensure every road/added_on combination has all possible values of `item`
-- If the combination does not exist in original data, leave `response` as blank
select road, added_on, i.item, cast('' as varchar(3)) as response into #assess2
from #items as i cross join #assess AS A
group by road, added_on, i.item
update a set response = b.response
from #assess2 a inner join #assess b on A.road = B.road AND a.added_on = B.added_on AND a.item = b.item
-- Join table to itself 4 times - inner join if `item` must exist or left join if `item` is optional
select a.road, a.added_on, a.response as '82', b.response as '83', c.response as '84', d.response as '85'
FROM #assess2 AS A
INNER JOIN #assess2 AS B ON A.road = B.road AND a.added_on = B.added_on
LEFT JOIN #assess2 AS C ON A.road = C.road AND a.added_on = C.added_on
LEFT JOIN #assess2 AS D ON A.road = D.road AND a.added_on = D.added_on
WHERE A.item = '82'
AND B.item = '83'
AND (C.item = '84' OR C.item IS NULL)
AND (D.item = '85' OR D.item IS NULL)
--AND datepart(month,A.added_on) = datepart(month,getdate()) -1
The resultset is:
road added_on 82 83 84 85
1 2016-07-11 Yes Yes Yes
2 2016-08-11 Yes No Yes

I would do this using conditional aggregation:
select road,
max(case when item = 82 then response end) as response_82,
max(case when item = 83 then response end) as response_83,
max(case when item = 84 then response end) as response_84,
max(case when item = 85 then response end) as response_85,
added_on
from t
group by road, added_on
order by road;
For the month component, you can add a where clause. One method is:
where year(date_added) * 12 + month(date_added) = year(getdate())*12 + month(getdate()) - 1
Or, you can use logic like this:
where date_added < dateadd(day, 1 - day(getdate()), cast(getdate() as date)) and
date_added >= dateadd(month, -1, dateadd(day, 1 - day(getdate()), cast(getdate() as date)))
The second looks more complicated but it is sargable, meaning that an index on date_added can be used (if one is available).

Related

Not does not exclude query info

I have a really long query and I'm finding that my NOT is not excluding what's in parenthesis after the NOT.
I saw Exclude and where not exists, but I'd have to re-select for that, and there's too many complicatedly joined tables in what I selected already, plus one table is very big and takes a long time to select what I have already, so I can't re-select because it will make the query take too long. How do I get this exclusion to work?
INSERT INTO #UNeedingC(id, CASEID, firstname, lastname, userid, AGEOFNOTIFICATION, DATETIMEDECISIONMADE, DELEGATESYSTEM, Person_id, request_type_id, service_place_id, status_summary, externalUserId, subject, onDate, externalPersonId, externalSystemId)
select distinct
c.id
,uc.case_id
,t_case.FIRSTNAME as first
,t_case.LASTNAME as last
,t_case.user_id as userid
,CONVERT(VARCHAR, DATEDIFF(dd, SC.status_change_date, GETDATE())) + ' Day(s) ' + CONVERT(VARCHAR, DATEDIFF(hh, SC.status_change_date, GETDATE()) % 24) + ' Hour(s) ' as [AGE OF NOTIFICATION]
,SC.status_change_date AS [DATE TIME DECISION MADE]
,[ckoltp_sys].DBO.ckfn_GetStringLocaleValue(152,9,uc.delegate_system,50,0) AS [DELEGATESYSTEM]
,c.person_id
,uc.request_type_id ------
,uc.service_place_id
,uc.status_summary
,eou.external_id
,c.tzix_id+' '+[ckoltp_sys].dbo.ckfn_GetStringLocaleValue(148,9,uc.status_summary,5,0)+' type' AS subject
,dateadd( hour,41,dateadd(day,0,datediff(d,0,sc.status_change_date)) ) AS onDate
,emd.externalId externalPersonId
,eou.system_id as externalSystemId
--,u.disable
from
#tempC t_case with (NOLOCK)
inner join dbo.org_case c with (nolock) ON t_case.Person_id=c.Person_id
INNER JOIN dbo.org_2_case uc with (NOLOCK) ON uc.case_id=c.id
inner JOIN dbo.ORG_LOS S WITH (NOLOCK) ON S.case_id = UC.case_id
inner JOIN dbo.ORG_EXTENSION SC WITH (NOLOCK) ON SC.los_id= S.id
inner join dbo.org_user u with (NOLOCK) on u.id=t_case.user_id
inner join dbo.org_person op with (NOLOCK) on op.id=c.Person_id
inner JOIN dbo.u_person_concept_value MC ON MC.CID = op.cid --this is the slow table
inner join dbo.EXTERNAL_ORG_USER_DATA eou with (NOLOCK) ON eou.org_user_id = t_case.user_id
inner join dbo.EXTERNAL_person_DATA emd with (NOLOCK) ON emd.CID = op.cid --op.id --?
WHERE
DATEDIFF(day, SC.status_change_date , GETDATE()) <= 2
AND
u.disable <> 1
AND
( --(denied/approved)
dbo.ckfn_GetStringLocaleValue(148,9,uc.status_summary,5,0) = 'Denied'
OR
(dbo.ckfn_GetStringLocaleValue(148,9,uc.status_summary,5,0) in( 'Fully Approved', 'Partially Approved'))
)
AND
(
(
ISNULL(uc.request_type_id,'') in( 12)
AND DATEDIFF(month, SC.status_change_date , GETDATE()) <= 2
)
OR
(
ISNULL(uc.request_type_id,'') in( 10,11)
)
--OR
--(
-- --exclude this
-- (
-- MC.concept_id = '501620' --general val1 (1000/1001)
-- AND
-- (C.ID in (select case_id from #CASES where str_value in ('1000','1001'))
-- AND (uc.service_place_id = 31 OR uc.service_place_id = 32))
-- ) --not
--) --or
)--AND
AND
(t_case.firstname not like '%external%' and t_case.lastname not like '%case manager%')
AND
(
C.ID in (select case_id from #CASES where concept_id='501620')--MC.concept_id = '501620'
)
--overall around AND (denied/approved)--
and DBO.ckfn_GetStringLocaleValue(152,9,uc.delegate_system,50,0) in ('AP','CA')
AND NOT --this not is not working...this appears in query results
(
--exclude these
(
MC.concept_id = '501620'
AND
(C.ID in (select case_id from #CASES where str_value in ('1000','1001'))
AND (uc.service_place_id = 31 OR uc.service_place_id = 32))
) --not
) --
select * from #UNeedingC
results show what is excluded:
id caseid firstname lastname userid ageofNotification Datetimedecisionmade DelegateSys Person_id request_type_id service_place_id status_summary externalUserId subject
onDate externalPersonId externalSystemId
000256200 256200 Sree Par 1234 0 Apr 5 CA
4270000 11 31 3 sparee 000256200 Fully Approved tested Ad 2021-04-06 17:00 363000 2
My question: do you know why the NOT is not working and how I can get this to exclude without another select? See "this not is not working" comment. I searched online but only found exclude and where not exists, which require another select, which I don't want.
I think I figured it out: "NOT acts on one condition. To negate two or more conditions, repeat the NOT for each condition,"
from not on two things.
This seems to work:
...
AND
--exclude these
(
MC.concept_id = '501620' --general val1 (1000/1001)
AND
(C.ID not in (select case_id from #CASES where str_value in ('1000','1001'))
AND (uc.service_place_id not in ('31','32')))
) --not

Pivot on duplicate column name

The query below is doing what I want, except a given accessruleId could have more than one businessArea. So, the current query is just grabbing the max one instead of all of them.
I get businessArea column to list all of the values perhaps comma delimited like the screenshot below.
I am using SQL Server 2016.
AccessRuleId EffectiveDate TermDate CreatedByUser CreateDateTime LastUpdatedUser LastUpdatedDateTime
1 2019-12-13 2020-01-22 User1 2019-12-11 User2 2019-12-12
RuleFieldId FieldName
1 BusinessArea
2 ProviderTaxId
3 VendorName
RuleOperationId AccessRuleId Fieldid Value
1 1 1 ABC
2 1 2 1234537890
3 1 3 Vendor1
30 1 4 XYZ
SELECT *
FROM (
SELECT ar.AccessRuleId
,ar.EffectiveDate
,ar.TermDate
,ar.CreatedByUser
,ar.LastUpdatedUser
,rf.FieldName
,ro.Value
FROM AccessRule.AccessRule ar
JOIN AccessRule.RuleOperation ro ON ar.AccessRuleId = ro.AccessRuleId
JOIN AccessRule.RuleField rf ON ro.FieldId = rf.RuleFieldId
) AS t
pivot(max([value]) FOR [FieldName] IN (
[BusinessArea]
,[ProviderTaxId]
,[VendorName]
)) AS pt
You need to merge the value for the field before the pivoting:
;WITH cte_raw(AccessRuleId,EffectiveDate,TermDate,CreatedByUser,LastUpdatedUser,FieldName,Value)
AS
(
SELECT ar.AccessRuleId
,ar.EffectiveDate
,ar.TermDate
,ar.CreatedByUser
,ar.LastUpdatedUser
,rf.FieldName
,ro.Value
FROM AccessRule.AccessRule ar
JOIN AccessRule.RuleOperation ro ON ar.AccessRuleId = ro.AccessRuleId
JOIN AccessRule.RuleField rf ON ro.FieldId = rf.RuleFieldId
),
cte_merged(AccessRuleId,EffectiveDate,TermDate,CreatedByUser,LastUpdatedUser,FieldName,Value)
AS
(
SELECT r.AccessRuleId,r.EffectiveDate,r.TermDate,r.CreatedByUser,r.LastUpdatedUser,r.FieldName,
STUFF((SELECT N','+v.Value
FROM cte_raw v
WHERE v.AccessRuleId=r.AccessRuleId
AND v.EffectiveDate=r.EffectiveDate
AND v.TermDate=r.TermDate
AND v.CreatedByUser=r.CreatedByUser
AND v.LastUpdatedUser=r.LastUpdatedUser
AND v.FieldName=r.FieldName
ORDER BY v.Value
FROM XML PATH (N''),TYPE).value('.','nvarchar(4000)')
,1,1,N'') AS Value
FROM cte_raw r
GROUP BY r.AccessRuleId
,r.EffectiveDate
,r.TermDate
,r.CreatedByUser
,r.LastUpdatedUser
,r.FieldName
)
SELECT *
FROM cte_merged t
pivot(max([value]) FOR [FieldName] IN (
[BusinessArea]
,[ProviderTaxId]
,[VendorName]
)) AS pt
I figured out how to do this in an a more simplified way.
SELECT ar.AccessRuleId
,ar.EffectiveDate
,ar.TermDate
,(select Value from AccessRule.RuleOperation ro where ro.AccessRuleId = ar.AccessRuleId and ro.FieldId = 2) as ProviderTaxId
,(select Value from AccessRule.RuleOperation ro where ro.AccessRuleId = ar.AccessRuleId and ro.FieldId = 3) as VendorName
,(SELECT STUFF( (SELECT ',' + value FROM AccessRule.RuleOperation ro where ro.AccessRuleId = ar.AccessRuleId and ro.FieldId = 1 FOR XML PATH('')),1, 1, '')) AS BusinessAreas
FROM AccessRule.AccessRule ar

create an classification for months ordered

I'm trying to create an column in my query to show an ordered classification ( show 1, 2, 3 ( as in first, second, third ...)) relative to date... in my current query i have filtered data from the last 12 months ( as example, from 1-9-2016 to 31-8-2017)
using DATEADD(mm; DATEDIFF(m; - 1; GETDATE()) - 12; 0)
for the first date and
DATEADD(s; - 1; DATEADD(mm; DATEDIFF(m; 0; GETDATE()) + 1; 0))
for the last day of the current month. And i also have two columns, one with the month and other with the year, both extracted from a document date column present in the data ( i'm using
MONTH(dbo.Mov_Venda_Cab.dtmData) and YEAR(dbo.Mov_Venda_Cab.dtmData)).
My goal is to have a column showing something like this :
If the month is the first from the interval ( if is month 9 and year 2016 ) is has to show 1 , if is the second ( month 10 and year 2016) , show 2, all continuously until the current month ( that is 8 and year 2017) and showing 12.
If the values where static i could do a simple case and would achieve what i wanted. My problem is that since when i get the data filtered by my current date and the 12 months behind, i don't manage to get the same result because i don't know exactly what i should do in the CASE expression.
so that it could help my columns are :
Item ; Qty ; Month ; Year ; dtmData ; orderedMonth
ORIGINAL QUERY :
SELECT DISTINCT DATEADD(mm, DATEDIFF(m, - 1, GETDATE()) - 12, 0) AS DATA_INI,
DATEADD(s, - 1, DATEADD(mm, DATEDIFF(m, 0, GETDATE()) + 1, 0)) AS DATA_FIM,
dbo.Mov_Venda_Lin.Id,
MONTH(dbo.Mov_Venda_Cab.dtmData) AS Mes,
YEAR(dbo.Mov_Venda_Cab.dtmData) AS Ano,
dbo.Mov_Venda_Lin.fltValorMercadoriaSIVA * dbo.Mov_Venda_Cab.intSinal AS Mercadoria,
dbo.Mov_Venda_Lin.fltValorLiquido * dbo.Mov_Venda_Cab.intSinal AS ValorLiquido,
CASE
WHEN tbl_tipos_documentos.bitconsideraqtdmapas = 1
THEN (Mov_Venda_Lin.fltQuantidade * mov_venda_cab.intsinal)
ELSE 0
END AS Quantidade,
dbo.Mov_Venda_Lin.strCodSeccao AS Seccao,
dbo.Mov_Venda_Lin.strAbrevTpDoc AS TpDoc,
dbo.Tbl_Tipos_Documentos.strDescricao AS DescTpDoc,
dbo.Mov_Venda_Lin.intNumLinha AS Linha,
dbo.Mov_Venda_Lin.strCodExercicio AS Exercicio,
dbo.Mov_Venda_Cab.strAbrevMoeda AS Moeda,
dbo.Mov_Venda_Cab.fltCambio AS Cambio,
dbo.Mov_Venda_Lin.strCodArtigo AS Artigo,
dbo.Tbl_Gce_Artigos.strDescricao AS DescArtigo,
dbo.Mov_Venda_Lin.strCodClassMovStk AS MovStk,
dbo.Tbl_ClassificacaoMovStk.strDescricao AS DescMovStk,
CASE
WHEN mov_venda_cab.inttpentidade = 0
THEN tbl_gce_tipos_entidade.strcodigo
ELSE NULL
END AS TpEntidade,
CASE
WHEN mov_venda_cab.inttpentidade = 0
THEN tbl_gce_tipos_entidade.strdescricao
ELSE NULL
END AS DescTpEntidade,
CASE
WHEN mov_venda_cab.intcodentidade <> 0
THEN mov_venda_cab.intcodentidade
ELSE NULL
END AS CodEntidade,
CASE
WHEN mov_venda_cab.inttpentidade = 0
AND mov_venda_cab.intcodentidade <> 0
THEN 'Cliente'
WHEN mov_venda_cab.inttpentidade = 1
AND mov_venda_cab.intcodentidade <> 0
THEN 'Outro Devedor'
ELSE NULL
END AS TipoEntidade,
CASE
WHEN mov_venda_cab.inttpentidade = 0
THEN tbl_clientes.strnome
ELSE tbl_outros_devedores.strnome
END AS DescNome,
dbo.Tbl_SubZonas.strAbrevZona AS Zona,
dbo.Tbl_Zonas.strDescricao AS DescZona,
dbo.Mov_Venda_Cab.strAbrevSubZona AS SubZona,
dbo.Tbl_SubZonas.strDescricao AS DescSubZona,
dbo.Mov_Venda_Cab.intCodVendedor AS Vendedor,
dbo.Tbl_Gce_Vendedores.strNome AS DescNomeVend,
dbo.Tbl_Gce_Artigos.strCodCategoria AS Categoria,
dbo.Tbl_Gce_Categorias.strDescricao AS DescCategoria,
dbo.Tbl_Gce_Artigos.strTpArtigo AS TpArtigo,
dbo.Tbl_Gce_Tipos_Artigos.strDescricao AS DescTpArtigo,
CAST(NULL AS VARCHAR(13)) AS CodFamiliaAgrup,
CAST(NULL AS VARCHAR(35)) AS DescFamAgrup,
CAST(NULL AS VARCHAR(13)) AS CodFamiliaRes,
CAST(NULL AS VARCHAR(35)) AS DescFamRes,
dbo.Mov_Venda_Cab.strForteAbrevMoeda AS abrevmoeda,
dbo.Mov_Venda_Cab.fltForteCambio AS fortecambio
FROM dbo.Mov_Venda_Lin WITH (NOLOCK)
LEFT OUTER JOIN dbo.Mov_Venda_Cab WITH (NOLOCK)
ON dbo.Mov_Venda_Lin.strCodSeccao = dbo.Mov_Venda_Cab.strCodSeccao
AND dbo.Mov_Venda_Lin.strAbrevTpDoc = dbo.Mov_Venda_Cab.strAbrevTpDoc
AND dbo.Mov_Venda_Lin.strCodExercicio = dbo.Mov_Venda_Cab.strCodExercicio
AND dbo.Mov_Venda_Lin.intNumero = dbo.Mov_Venda_Cab.intNumero
LEFT OUTER JOIN dbo.Tbl_Gce_Armazens WITH (NOLOCK)
ON dbo.Mov_Venda_Lin.strCodArmazem = dbo.Tbl_Gce_Armazens.strCodigo
LEFT OUTER JOIN dbo.Tbl_Gce_Artigos WITH (NOLOCK)
ON dbo.Tbl_Gce_Artigos.strCodigo = dbo.Mov_Venda_Lin.strCodArtigo
LEFT OUTER JOIN dbo.Tbl_Gce_ArtigosFamilias WITH (NOLOCK)
ON dbo.Tbl_Gce_Artigos.strCodigo = dbo.Tbl_Gce_ArtigosFamilias.strCodArtigo
LEFT OUTER JOIN dbo.Tbl_Gce_Familias WITH (NOLOCK)
ON dbo.Tbl_Gce_ArtigosFamilias.strCodFamilia = dbo.Tbl_Gce_Familias.strCodigo
LEFT OUTER JOIN dbo.Tbl_Gce_ArtigosReferencias WITH (NOLOCK)
ON dbo.Tbl_Gce_Artigos.strCodigo = dbo.Tbl_Gce_ArtigosReferencias.strCodArtigo
LEFT OUTER JOIN dbo.Tbl_Gce_Referencias WITH (NOLOCK)
ON dbo.Tbl_Gce_ArtigosReferencias.strCodReferencia = dbo.Tbl_Gce_Referencias.strCodigo
LEFT OUTER JOIN dbo.Tbl_Gce_Tipos_Artigos WITH (NOLOCK)
ON dbo.Tbl_Gce_Artigos.strTpArtigo = dbo.Tbl_Gce_Tipos_Artigos.strCodigo
LEFT OUTER JOIN dbo.Tbl_Clientes WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.intCodEntidade = dbo.Tbl_Clientes.intCodigo
LEFT OUTER JOIN dbo.Tbl_Direccoes WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.intCodEntidade = dbo.Tbl_Direccoes.intCodigo
AND dbo.Mov_Venda_Cab.intDireccao = dbo.Tbl_Direccoes.intNumero
AND dbo.Mov_Venda_Cab.intTpEntidade = dbo.Tbl_Direccoes.intTp_Entidade
LEFT OUTER JOIN dbo.Tbl_Outros_Devedores WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.intCodEntidade = dbo.Tbl_Outros_Devedores.intCodigo
LEFT OUTER JOIN dbo.Tbl_Gce_Vendedores WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.intCodVendedor = dbo.Tbl_Gce_Vendedores.intCodigo
LEFT OUTER JOIN dbo.Tbl_Tipos_Documentos WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.strAbrevTpDoc = dbo.Tbl_Tipos_Documentos.strAbreviatura
LEFT OUTER JOIN dbo.Tbl_SubZonas WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.strAbrevSubZona = dbo.Tbl_SubZonas.strAbreviatura
LEFT OUTER JOIN dbo.Tbl_Zonas WITH (NOLOCK)
ON dbo.Tbl_SubZonas.strAbrevZona = dbo.Tbl_Zonas.strAbreviatura
LEFT OUTER JOIN dbo.Tbl_Gce_Categorias WITH (NOLOCK)
ON dbo.Tbl_Gce_Artigos.strCodCategoria = dbo.Tbl_Gce_Categorias.strCodigo
LEFT OUTER JOIN dbo.Tbl_Gce_Seccoes WITH (NOLOCK)
ON dbo.Mov_Venda_Cab.strCodSeccao = dbo.Tbl_Gce_Seccoes.strCodigo
LEFT OUTER JOIN dbo.Tbl_Gce_Tipos_Entidade WITH (NOLOCK)
ON dbo.Tbl_Clientes.strTpEntidade = dbo.Tbl_Gce_Tipos_Entidade.strCodigo
LEFT OUTER JOIN dbo.Tbl_ClassificacaoMovStk WITH (NOLOCK)
ON dbo.Mov_Venda_Lin.strCodClassMovStk = dbo.Tbl_ClassificacaoMovStk.strCodigo
WHERE (dbo.Mov_Venda_Cab.intTpEntidade = 0
OR dbo.Mov_Venda_Cab.intTpEntidade IS NULL)
AND (dbo.Mov_Venda_Cab.strAbrevTpDoc IN ('CRFCX', 'FACIV', 'FACTC', 'FCTA', 'LANIV', 'LOFX', 'LONC', 'LXANI', 'NCFCX', 'NFACC', 'NFACE', 'NFACM', 'NFACT', 'NNCRC', 'NNCRE', 'NNCRM', 'NNDEB', 'NNDEC', 'NNDEV', 'NVDIC', 'NVDIN', 'XLACC', 'XLACD'))
AND (dbo.Mov_Venda_Cab.strCodSeccao IN ('1', 'ENCT1', 'ENCT2', 'ENCT3', 'ENCT4', 'ENCT5', 'ENCT6'))
AND (dbo.Mov_Venda_Cab.dtmData > DATEADD(mm, DATEDIFF(m, - 1, GETDATE()) - 12, 0))
AND (dbo.Mov_Venda_Cab.dtmData <= DATEADD(s, - 1, DATEADD(mm, DATEDIFF(m, 0, GETDATE()) + 1, 0)))
AND (dbo.Mov_Venda_Lin.intTpLinha > 2)
AND (dbo.Mov_Venda_Cab.bitAnulado = 0)
AND (dbo.Mov_Venda_Cab.bitConvertido = 0)
Luckily there's a much less complicated method than using a bunch of CASE statements. You can use the ROW_NUMBER function.
First, don't split your dates into month and year. Just use Getdate() to calculate your desired range and compare your source dates to that. Then you add the ROW_NUMBER to get your ordering output:
SELECT
*
,ordered_output = (ROW_NUMBER()OVER(PARTITION BY grouping_field ORDER BY cast(dtmData as datetime) ASC))
FROM Mov_Venda_Cab
WHERE cast(dtmData as datetime) >= getdate() - 365
This example assumes your have some ID field or similar on which your want to group your output, represented by grouping_field in the example. Your results would look like:
grouping_field dtmData ordered_output
1 8/1/2017 1
1 8/2/2017 2
1 8/3/2017 3
2 8/1/2017 1
2 8/2/2017 2
2 8/3/2017 3
If you don't want to group your output, just ordering everything by the date, you can omit the PARTITION BY grouping_field text. You'd get instead something like:
dtmData ordered_output
8/1/2017 1
8/2/2017 2
8/3/2017 3
8/4/2017 4
8/5/2017 5
8/6/2017 6
EDIT: Asker clarified that all records with the same month should get the same ordered output.
To do that you first need to assign each month/year combo a rank and rejoin that to the main table using two layers of subqueries:
SELECT b.*, c.month_rank
from Mov_Venda_Cab as b
inner join
(select mnt, yr, ROW_NUMBER() OVER(ORDER BY A.yr, A.mnt) AS month_rank
from (
SELECT DISTINCT
MONTH(dtmData) as mnt
, YEAR(dtmData) as yr
from Mov_Venda_Cab
WHERE cast(dtmData as datetime) >= getdate() - 365
) as a
) as c
on MONTH(b.dtmData) = c.mnt and YEAR(b.dtmData) = c.yr

Remove duplicate rows in t-sql query results

I have a some T-SQL below and i am facing a problem where each row is being returned twice with the same values. How can ensure each is returned once or force a select Distinct
;WITH CTE_ReportDetails
AS (
SELECT
CASE(GROUPING(M.Acronym))
WHEN 0 THEN [Acronym]
WHEN 1 THEN 'GRAND TOTAL'
END AS [Company],
CASE(GROUPING(DC.Name))
WHEN 0 THEN DC.[Name]
WHEN 1 THEN 'N/A'
END AS [CatName],
CASE(GROUPING(D.[Name]))
WHEN 0 THEN D.[Name]
WHEN 1 THEN 'Total '+ '('+DC.[Name]+')'
END AS [Name],
SUM(ISNULL(B.One, 0)) AS One,
SUM(ISNULL(B.Two, 0)) AS Two,
SUM(ISNULL(B.Three, 0)) AS Three,
ISNULL(B.Description, '') AS Description,
GROUPING(M.Acronym) AS CompanyGrouping,
GROUPING(DC.[Name]) AS DCatGroup,
GROUPING(D.[Name]) AS DGroup
FROM Dee D
INNER JOIN DeeCategory DC ON D.DeeCategoryId = DC.DeeCategoryId
INNER JOIN BD B ON B.DeeId = D.DeeId
INNER JOIN Report R ON R.RptId = B.RptId
INNER JOIN Company M ON R.CompanyId = M.CompanyId
WHERE (R.ReportDate >= #StartDate AND R.ReportDate <= #EndDate) AND (R.CompanyId IN (SELECT DATA FROM SPLIT(#CompanyIds,',')))
GROUP BY M.Acronym, DC.Name, D.Name,B.Description
WITH ROLLUP
)
SELECT Company, Name As [Dee],
One,
Three,
Two,
(One + Three + Two) AS Total,
Description
FROM CTE_ReportDetails
Your report should have a unique combinations of values from the group by. So, these four columns should be unique:
GROUP BY M.Acronym, DC.Name, D.Name,B.Description
If I had to guess, you are getting duplicates because B.Description is duplicated in the B table. I would suggest removing it from the GROUP BY and changing this line:
ISNULL(B.Description, '') AS Description,
to
ISNULL(max(B.Description), '') AS Description,

How do I select the max of several fields in the middle of a one to many to many query

All,
I have this query below which is a one to many to many relationship.
The relationship is as such, a story can have multiple tasks (1>M) each task can have multiple time entries (M-M)
I want to get the 1st occurrence of 3 fields in the tasks section and null the remainder for each story. So for example;
Story 1234
Tasks 12, 13, 14,15
Time entry 120, 121, 134, 135 etc....
There are 3 fields in tasks OptimisticEstimate, ProbableEstimate and Pessimistic Estimate that get repeated at the task level when Time entry table is linked in to the query (as it should be).
I want to get the 1st occurrence of those fields for each task and leave any other occurrence NULL so that when we sum it up the estimated don't get summed along with the hours from time entry.
Hopefully that is clear.
WITH
WorkItem_CTE AS
(-- Child Level (Task)
SELECT wi1.AreaID
,a.Name AS AreaName
,wi1.ProjectID
,wi1.IterationID
-- Work Items
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
,wi1.WorkItemID
,wi1.[Type] AS WorkItemType
,wi1.Name AS WorkItemName
,wi1.[Status] AS WorkItemStatus
,wi1.[Priority] AS WorkItemPriority
,wi1.Complexity
,wi1.Estimate
-- Tasks
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
,wi2.WorkItemID AS TaskID
,wi2.Name AS TaskName
,wi2.[Status] AS TaskStatus
,wi2.AssignedTo AS TaskAssignedTo
,wi2.EstimateOptimistic
,Case When wi2.EstimateProbable IS NULL Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
,wi2.EstimatePessimistic
,wi2.WorkCompleted
,wi2.WorkRemaining
FROM dbo.WorkItem wi1 WITH (NOLOCK)
INNER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
ON wi1.WorkItemID = wi2.ParentID
AND wi2.[Status] <> 'Deleted'
LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
ON wi1.AreaID = a.AreaID
--LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
-- ON wi1.ProjectID = p.ProjectID
WHERE wi1.[Status] <> 'Deleted'
UNION ALL
-- Parent level (Story, Bug, Feedback)
SELECT wi1.AreaID
,a.Name AS AreaName
,wi1.ProjectID
,wi1.IterationID
-- Work Items
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
,wi1.WorkItemID
,wi1.[Type] AS WorkItemType
,wi1.Name AS WorkItemName
,wi1.[Status] AS WorkItemStatus
,wi1.[Priority] AS WorkItemPriority
,wi1.Complexity
,wi1.Estimate
-- Tasks
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
,wi2.WorkItemID AS TaskID
,wi2.Name AS TaskName
,wi2.[Status] AS TaskStatus
,wi2.AssignedTo AS TaskAssignedTo
,wi2.EstimateOptimistic
,Case When wi2.EstimateProbable IS NULL Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
,wi2.EstimatePessimistic
,wi2.WorkCompleted
,wi2.WorkRemaining
FROM dbo.WorkItem wi1 WITH (NOLOCK)
LEFT OUTER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
ON wi1.WorkItemID = wi2.ParentID
AND wi2.[Status] <> 'Deleted'
LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
ON wi1.AreaID = a.AreaID
WHERE wi1.[Type] <> 'Task'
AND wi1.[Status] <> 'Deleted'
AND wi2.ParentID IS NULL
),
--Time Entry for Tasks
TimeEntry_CTE As
(SELECT te.WorkItemID
,te.ProjectID
,te.Date
,te.Hours
,te.CreatedBy
,te.CreatedDateUtc
,te.LastModifiedBy
,te.LastModifiedDateUtc
,te.Note
FROM TimeEntry te
)
SELECT wi.AreaID
,wi.AreaName
,wi.ProjectID
,p.Name AS ProjectName
,wi.WorkItemCreatedDTS
,wi.WorkItemID
,wi.WorkItemType
,wi.WorkItemName
,wi.WorkItemStatus
,wi.WorkItemPriority
,wi.Complexity
,wi.Estimate AS StoryEstimate
,wi.TaskCreatedDTS
,wi.TaskID
,wi.TaskName
,wi.EstimateOptimistic
,wi.EstimateProbable
,wi.EstimatePessimistic
,wi.TaskStatus
,wi.TaskAssignedTo
,wi.WorkCompleted
,wi.WorkRemaining
,te.WorkItemID as TimeWorkItemID
,te.ProjectID
,te.Date
,te.Hours
,te.CreatedBy
,te.CreatedDateUtc
,te.LastModifiedBy
,te.LastModifiedDateUtc
,te.Note
FROM WorkItem_CTE wi WITH (NOLOCK)
LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
ON wi.ProjectID = p.ProjectID
inner Join TimeEntry_CTE te With (nolock)
ON wi.TaskID = te.WorkItemID
Thanks in Advance for any help.
Revised Code based on suggestions. Closer but not quite right.
WITH
WorkItem_CTE AS
(-- Child Level (Task)
SELECT wi1.AreaID
,a.Name AS AreaName
,wi1.ProjectID
,wi1.IterationID
-- Work Items
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
,wi1.WorkItemID
,wi1.[Type] AS WorkItemType
,wi1.Name AS WorkItemName
,wi1.[Status] AS WorkItemStatus
,wi1.[Priority] AS WorkItemPriority
,wi1.Complexity
,wi1.Estimate
-- Tasks
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
,wi2.WorkItemID AS TaskID
,wi2.Name AS TaskName
,wi2.[Status] AS TaskStatus
,wi2.AssignedTo AS TaskAssignedTo
,wi2.EstimateOptimistic
,Case When wi2.EstimateProbable IS NULL Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
,wi2.EstimatePessimistic
,wi2.WorkCompleted
,wi2.WorkRemaining
FROM dbo.WorkItem wi1 WITH (NOLOCK)
INNER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
ON wi1.WorkItemID = wi2.ParentID
AND wi2.[Status] <> 'Deleted'
LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
ON wi1.AreaID = a.AreaID
--LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
-- ON wi1.ProjectID = p.ProjectID
WHERE wi1.[Status] <> 'Deleted'
UNION ALL
-- Parent level (Story, Bug, Feedback)
SELECT wi1.AreaID
,a.Name AS AreaName
,wi1.ProjectID
,wi1.IterationID
-- Work Items
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
,wi1.WorkItemID
,wi1.[Type] AS WorkItemType
,wi1.Name AS WorkItemName
,wi1.[Status] AS WorkItemStatus
,wi1.[Priority] AS WorkItemPriority
,wi1.Complexity
,wi1.Estimate
-- Tasks
,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
,wi2.WorkItemID AS TaskID
,wi2.Name AS TaskName
,wi2.[Status] AS TaskStatus
,wi2.AssignedTo AS TaskAssignedTo
,wi2.EstimateOptimistic
,Case When wi2.EstimateProbable IS NULL Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
,wi2.EstimatePessimistic
,wi2.WorkCompleted
,wi2.WorkRemaining
FROM dbo.WorkItem wi1 WITH (NOLOCK)
LEFT OUTER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
ON wi1.WorkItemID = wi2.ParentID
AND wi2.[Status] <> 'Deleted'
LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
ON wi1.AreaID = a.AreaID
WHERE wi1.[Type] <> 'Task'
AND wi1.[Status] <> 'Deleted'
AND wi2.ParentID IS NULL
),
--Time Entry for Tasks
TimeEntry_CTE As
(SELECT te.WorkItemID
,te.ProjectID
,te.Date
,te.Hours
,te.CreatedBy
,te.CreatedDateUtc
,te.LastModifiedBy
,te.LastModifiedDateUtc
,te.Note
FROM TimeEntry te
),
wi_CTE As
(SELECT wi.AreaID
,wi.AreaName
,wi.ProjectID
,p.Name AS ProjectName
,wi.WorkItemCreatedDTS
,wi.WorkItemID
,wi.WorkItemType
,wi.WorkItemName
,wi.WorkItemStatus
,wi.WorkItemPriority
,wi.Complexity
,wi.Estimate AS StoryEstimate
,wi.TaskCreatedDTS
,wi.TaskID
,wi.TaskName
,wi.EstimateOptimistic
,wi.EstimateProbable
,wi.EstimatePessimistic
,wi.TaskStatus
,wi.TaskAssignedTo
,wi.WorkCompleted
,wi.WorkRemaining
,te.WorkItemID as TimeWorkItemID
,te.ProjectID TimeProjectID
,te.Date
,Sum(te.Hours) Hours
,te.CreatedBy
,te.CreatedDateUtc
,te.LastModifiedBy
,te.LastModifiedDateUtc
,te.Note
FROM WorkItem_CTE wi WITH (NOLOCK)
LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
ON wi.ProjectID = p.ProjectID
inner Join TimeEntry_CTE te With (nolock)
ON wi.TaskID = te.WorkItemID
--where wi.WorkItemID =94
Group By
wi.AreaID
,wi.AreaName
,wi.ProjectID
,p.Name
,wi.WorkItemCreatedDTS
,wi.WorkItemID
,wi.WorkItemType
,wi.WorkItemName
,wi.WorkItemStatus
,wi.WorkItemPriority
,wi.Complexity
,wi.Estimate
,wi.TaskCreatedDTS
,wi.TaskID
,wi.TaskName
,wi.EstimateOptimistic
,wi.EstimateProbable
,wi.EstimatePessimistic
,wi.TaskStatus
,wi.TaskAssignedTo
,wi.WorkCompleted
,wi.WorkRemaining
,te.WorkItemID
,te.ProjectID
,te.Date
,te.Hours
,te.CreatedBy
,te.CreatedDateUtc
,te.LastModifiedBy
,te.LastModifiedDateUtc
,te.Note),
cte AS (SELECT wi_cte.*, ROW_NUMBER() OVER(PARTITION BY WorkItemID, TaskID ORDER BY TimeWorkItemID) RN
FROM wi_CTE
)
SELECT
AreaID
,AreaName
,ProjectID
,ProjectName
,WorkItemCreatedDTS
,WorkItemID
,WorkItemType
,WorkItemName
,WorkItemStatus
,WorkItemPriority
,Complexity
,StoryEstimate
,TaskCreatedDTS
,TaskID
,TaskName
,EstimateOptimistic
,EstimateProbable
,EstimatePessimistic
,TaskStatus
,TaskAssignedTo
,WorkCompleted
,WorkRemaining
,WorkItemID
,ProjectID
,Date
,Hours
,CreatedBy
,CreatedDateUtc
,LastModifiedBy
,LastModifiedDateUtc
,Note
,RN
,SUM(CASE WHEN RN = 1 THEN Hours END) AS SumTime
FROM cte
Where RN=1
GROUP BY
AreaID
,AreaName
,ProjectID
,ProjectName
,WorkItemCreatedDTS
,WorkItemID
,WorkItemType
,WorkItemName
,WorkItemStatus
,WorkItemPriority
,Complexity
,StoryEstimate
,TaskCreatedDTS
,TaskID
,TaskName
,EstimateOptimistic
,EstimateProbable
,EstimatePessimistic
,TaskStatus
,TaskAssignedTo
,WorkCompleted
,WorkRemaining
,WorkItemID
,ProjectID
,Date
,Hours
,CreatedBy
,CreatedDateUtc
,LastModifiedBy
,LastModifiedDateUtc
,Note
,RN
What I get
ProjectID ProjectName WorkItemID WorkItemType WorkItemName EstimateOptimistic EstimateProbable EstimatePessimistic RN SumTime
11 Data Group 94 Story Backlog Report with new logic 2 3 4 1 8
11 Data Group 94 Story Backlog Report with new logic 2 3 4 2 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 3 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 4 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 1 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 2 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 3 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 4 8
11 Data Group 94 Story Backlog Report with new logic 2 3 4 5 3
What I'm Looking for
ProjectID ProjectName WorkItemID WorkItemType WorkItemName EstimateOptimistic EstimateProbable EstimatePessimistic RN SumTime
11 Data Group 94 Story Backlog Report with new logic 2 3 4 1 8
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 2 4
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 3 4
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 4 4
11 Data Group 94 Story Backlog Report with new logic 2 3 4 1 4
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 2 4
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 3 4
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 4 8
11 Data Group 94 Story Backlog Report with new logic NULL NULL NULL 5 3
Hopefully that helps clarify what I'm trying for.
I suggest using a conditional SUM() and the ROW_NUMBER() function.
Let's say the query above outputs data like this:
Story, Task, TimeEntry
1234, 12, 120
1234, 12, 121
1234, 12, 134
1234, 13, 135
1234, 13, 120
1234, 13, 121
1234, 13, 134
1234, 14, 135
1234, 14, 120
1234, 14, 121
1234, 14, 134
1234, 14, 135
You could use this:
;WITH cte AS (SELECT *, ROW_NUMBER() OVER(PARTITION BY Story, Task ORDER BY TimeEntry) RN
FROM Table1
)
SELECT Story, Task, SUM(CASE WHEN RN = 1 THEN TimeEntry END) AS SumTime
FROM cte
GROUP BY Story, Task
Demo: SQL Fiddle
Each line will be numbered, starting at 1 for each combination of Story and Task, allowing you to use the condition of RN = 1 to avoid aggregating duplicate lines. Since you said the values repeat it doesn't matter what you put in the ORDER BY clause for your ROW_NUMBER().