将DATENAME()函数添加到查询会导致重复行,尽管存在'distinct‘。
TREE - TreeId, CityId, DatePlanted
WATER - WaterId, TreeId(fk), DateWateredTable1与表2是一对多
树表中的每一行都表示种植了一棵树。“地下水位”就是给树浇水的一个例子。一棵树一年浇水很多次。你明白了吧。
我需要返回一份报告,显示种植的树木数量,按月和次数,它被浇水。
SELECT t.CityId
, COUNT(distinct t.TreeId) as 'Trees Planted'
, COUNT(w.TreeId) as 'Trees Watered'
FROM TREE t
JOIN WATER w ON t.TreeId = w.TreeId
WHERE w.DateWatered between @Start AND @End
GROUP BY t.CityId这可以很好地工作。但是,当我尝试按月分组时,t.Treeid不再清晰,因此树的数量太高。
SELECT t.CityId
, DATENAME(month, w.DateWatered)
, COUNT(distinct t.TreeId) as 'Trees Planted'
, COUNT(w.TreeId) as 'Trees Watered'
FROM TREE t
JOIN WATER w ON t.TreeId = w.TreeId
WHERE w.DateWatered between @Start AND @End
GROUP BY t.CityId, DATENAME(month, w.DateWatered)编辑:我已经找到了为什么我得到了重复,但不知道如何修复它。如果一棵树在2016年4月浇水,然后在2016年5月浇水,我得到的计数是种植了2棵树,浇水了2棵树,而这本应是一棵树种植和2次浇水。如果我执行第一次查询,但没有返回日期,则会得到正确的数字。因此,通过添加日期,即使我按年分组,然后按月分组,用同一棵树的两次浇水,它也显示了种植了两次的树。我目前正在研究CTE的使用,可能是为了将查询的每个部分分开。
发布于 2017-04-08 08:02:58
SELECT t.CityId
, ISNULL(DATENAME(month, w.DateWatered), DATENAME(month, t.DatePlanted))
, (SELECT COUNT(tDistinct.TreeId) FROM TREE tDistinct
WHERE tDistinct.TreeId = t.TreeId AND DATENAME(month, tDistinct.DatePlanted) = DATENAME(month, t.DateWatered) AND t.DatePlanted between @Start AND @End) as 'Trees Planted'
, COUNT(w.TreeId) as 'Trees Watered'
FROM TREE t
JOIN WATER w ON t.TreeId = w.TreeId
WHERE w.DateWatered between @Start AND @End
GROUP BY t.CityId, DATENAME(month, w.DateWatered), DATENAME(month, t.DatePlanted)这里唯一的缺点是,在种植了一棵树的一个月内没有浇水的情况下,日期将为空,因此我为that...not添加了检查确保您的数据看起来是什么样子,因此忽略ISNULL检查而支持您的原始分组可能是有意义的
编辑:根据您的要求,我不认为CTE是必要的;根据您提供的附加信息,我稍微修改了查询以满足您的需求:
`SELECT DATENAME(MONTH, myConsolidatedTree.DateAction) as myDate
,(SELECT COUNT(*)
FROM TREE AS t
WHERE
DATENAME(MONTH, myConsolidatedTree.DateAction) = DATENAME(MONTH, t.DatePlanted)
) as myNumberOfPlanted
,(SELECT COUNT(*)
FROM WATER AS w
WHERE
DATENAME(MONTH, myConsolidatedTree.DateAction) = DATENAME(MONTH, w.DateWatered)
) as myNumberOfWatered
FROM(
SELECT t.DatePlanted as DateAction
,t.TreeId as IdAction
,'PLANTED' as TreeAction
FROM TREE t
UNION
SELECT w.DateWatered as DateAction
,w.TreeId as IdAction
,'WATERED' as TreeAction
FROM WATER w) as myConsolidatedTree
WHERE myConsolidatedTree.DateAction between @StartDate and @EndDate
GROUP BY DATENAME(MONTH, myConsolidatedTree.DateAction), DATEPART(MONTH, myConsolidatedTree.DateAction)
ORDER BY DATEPART(MONTH, myConsolidatedTree.DateAction)`虽然统一的子查询包含的信息比这个问题所需的信息多,但我将附加的TreeId和派生的TreeAction列留在那里,以防将来您可能会遇到这样的需要。
发布于 2017-04-11 11:49:29
这演示了如何在公用表表达式(CTE)中将问题分解为多个步骤。请注意,您可以将最终的select替换为注释的select之一,以查看中间结果。这是一种测试、调试或了解正在发生的事情的便捷方法。
你面临的问题之一是试图仅根据浇水日期来总结数据。如果一棵树在一个月内没有浇水,那么它就不会被计算在内。下面的代码分别总结了日期范围内的种植和浇水,然后将它们合并为一个结果集。
-- Sample data.
declare @Trees as Table ( TreeId Int Identity, CityId Int, DatePlanted Date );
declare @Waterings as Table ( WateringId Int Identity, TreeId Int, DateWatered Date );
insert into @Trees ( CityId, DatePlanted ) values
( 1, '20160115' ), ( 1, '20160118' ),
( 1, '20160308' ), ( 1, '20160318' ), ( 1, '20160118' ),
( 1, '20170105' ),
( 1, '20170205' ),
( 1, '20170401' ),
( 2, '20160113' ), ( 2, '20160130' ),
( 2, '20170226' ), ( 2, '20170227' ), ( 2, '20170228' );
insert into @Waterings ( TreeId, DateWatered ) values
( 1, '20160122' ), ( 1, '20160129' ), ( 1, '20160210' ), ( 1, '20160601' ),
( 5, '20160120' ), ( 5, '20160127' ), ( 5, '20160215' ), ( 5, '20160301' ), ( 5, '20160515' );
select * from @Trees;
select * from @Waterings;
-- Combine the data.
declare @StartDate as Date = '20100101', @EndDate as Date = '20200101';
with
-- Each tree with the year and month it was planted.
TreesPlanted as (
select CityId, TreeId,
DatePart( year, DatePlanted ) as YearPlanted,
DatePart( month, DatePlanted ) as MonthPlanted
from @Trees
where @StartDate <= DatePlanted and DatePlanted <= @EndDate ),
-- Tree plantings summarized by city, year and month.
TreesPlantedSummary as (
select CityId, YearPlanted, MonthPlanted, Count( TreeId ) as Trees
from TreesPlanted
group by CityId, YearPlanted, MonthPlanted ),
-- Each watering and the year and month it occurred.
TreesWatered as (
select CityId, W.TreeId,
DatePart( year, W.DateWatered ) as YearWatered,
DatePart( month, W.DateWatered ) as MonthWatered
from @Trees as T left outer join
@Waterings as W on W.TreeId = T.TreeId
where @StartDate <= W.DateWatered and W.DateWatered <= @EndDate ),
-- Waterings summarized by city, year and month.
TreesWateredSummary as (
select CityId, YearWatered, MonthWatered,
Count( distinct TreeId ) as Trees, Count( TreeId ) as Waterings
from TreesWatered
group by CityId, YearWatered, MonthWatered )
-- Combine the plantings and waterings for the specified period.
select Coalesce( TPS.CityId, TWS.CityId ) as CityId,
Coalesce( TPS.YearPlanted, TWS.YearWatered ) as Year,
Coalesce( TPS.MonthPlanted, TWS.MonthWatered ) as Month,
Coalesce( TPS.Trees, 0 ) as TreesPlanted,
Coalesce( TWS.Trees, 0 ) as TreesWatered,
Coalesce( TWS.Waterings, 0 ) as Waterings
from TreesPlantedSummary as TPS full outer join
TreesWateredSummary as TWS on TWS.CityId = TPS.CityId and
TWS.YearWatered = TPS.YearPlanted and TWS.MonthWatered = TPS.MonthPlanted
order by CityId, Year, Month;
-- Alternative queries for testing/debugging/understanding:
-- select * from TreesPlantedSummary order by CityId, YearPlanted, MonthPlanted;
-- select * from TreesWateredSummary order by CityId, YearWatered, MonthWatered;现在,您希望在结果中包含缺少的月份(没有活动),嗯?
https://stackoverflow.com/questions/43288299
复制相似问题