我正在尝试计算每个用户的打开日记记录总数。 我的问题是用户名有三个不同的前缀。 CC YY或没有。 我可以替换使名称相同的前缀,但我无法通过此修改后的名称对它们进行分组。数据分布在三个表中,我需要排除关闭和非活动记录。
此简化查询返回我想要的未分组结果的示例。
select sname
,( Select count(lDiaryHeaderID)
FROM DiaryHeader
inner join OwnersCorporation on lObjectID = lOwnersCorporationID
where
sObjectType = 'B'
AND DiaryHeader.bRecordClosed = 'N'
AND DiaryHeader.dActionDueDate < cast (GETDATE() as DATE)
AND OwnersCorporation.bManaged = 'Y'
AND tbluser.lUserID = strata.dbo.OwnersCorporation.lUserID
) as TotalOverDue
FROM tblUser
WHERE bActive = 'Y'
AND bManager = 'Y'
ORDER by sName
结果
sname TotalOverDue
Belinda Smith 525
CC Belinda Smith 18
CC Julie Brown 13
CC Kris White 0
CC Sharon Towell 38
Colleen Black 131
Jessica Jones 166
Joanne Beigh 284
Julie Brown 449
YS Belinda Smith 31
YS Colleen Black 0
YS Joanne Beigh 21
我想要做的是从名称中删除CC和YS前缀 并将它们分组为一个条目,并将总数加在一起。
期望的结果
sname TotalOverDue
Belinda Smith 574
Julie Brown 462
Kris White 0
Sharon Towell 38
Colleen Black 131
Jessica Jones 166
Joanne Beigh 305
我想出了这个。
select Replace(Replace(sName, 'CC ',''), 'YS ','')
,( Select count(lDiaryHeaderID)
FROM DiaryHeader
inner join OwnersCorporation on lObjectID = lOwnersCorporationID
where
sObjectType = 'B'
AND DiaryHeader.bRecordClosed = 'N'
AND DiaryHeader.dActionDueDate < cast (GETDATE() as DATE)
AND OwnersCorporation.bManaged = 'Y'
AND tbluser.lUserID = strata.dbo.OwnersCorporation.lUserID
) as TotalOverDue
FROM tblUser
WHERE bActive = 'Y'
AND bManager = 'Y'
group by sName
但是我收到此错误消息
列'tblUser.lUserID'在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。
如果我将lUserID放在group by子句中,它只会按预期显示重复的用户名。
我出错的任何想法以及我应该如何做到这一点。 谢谢 大卫
更新
我的实际解决方案有多个列,我删除了其中两个以简化我的问题。现在我正在尝试再次扩展它,我遇到了更多问题。
这是我尝试将其他两列添加回来.DueToday和TotalDue然而我的总数正在滚雪球。
更新2 感谢Phylyp的鹰眼。他发现了一些剪切和粘贴错误,此代码现在返回所需的结果。 感谢所有回答了一些非常有趣和多样化的解决方案的人。我会坚持使用第一个有效的方法:)
select Replace(Replace(sName, 'CC ', ''), 'YS ', ''),
coalesce(sum(od.cnt), 0) as TotalOverDue,
coalesce(sum(dt.cnt), 0) as DueToday,
coalesce(sum(td.cnt), 0) as TotalDue
from tblUser u
left join (
select oc.lUserID,
count(lDiaryHeaderID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = lOwnersCorporationID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
and dh.dActionDueDate < cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) od on u.lUserID = od.lUserID
left join (
select oc.lUserID,
count(lDiaryHeaderID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = lOwnersCorporationID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
and dh.dActionDueDate = cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) dt on u.lUserID = dt.lUserID
left join (
select oc.lUserID,
count(lDiaryHeaderID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = lOwnersCorporationID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
--and dh.dActionDueDate < cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) td on u.lUserID = td.lUserID
where bActive = 'Y'
and bManager = 'Y'
group by Replace(Replace(sName, 'CC ', ''), 'YS ', '')
答案 0 :(得分:2)
首先,您需要按替换表达式而不是列sName进行分组。另外,请小心替换,因为它替换了字符串中任何位置的匹配。
其次,用左连接替换相关子查询。
select Replace(Replace(sName, 'CC ', ''), 'YS ', ''),
coalesce(sum(od.cnt), 0) as TotalOverDue
from tblUser u
left join (
select oc.lUserID,
count(ldhID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = locID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
and dh.dActionDueDate < cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) od on u.lUserID = od.lUserID
where bActive = 'Y'
and bManager = 'Y'
group by Replace(Replace(sName, 'CC ', ''), 'YS ', '')
答案 1 :(得分:1)
以下是我的建议。
我正在使用CASE
表达式来检查名称是否以 CC或YS开头,如果是,请删除前3个字母。这确保了名称本身中存在的任何CC / YS(例如作为首字母)不会被无意中移除,如REPLACE()
函数的情况。
SELECT
tblUserNameNormalized.sNameNormalized
, COALESCE(SUM(od.cnt), 0) AS TotalOverDue
, COALESCE(SUM(dt.cnt), 0) AS DueToday
, COALESCE(SUM(td.cnt), 0) AS TotalDue
FROM
(
SELECT
lUserID
, CASE
-- Check if the name starts with CC or YS, and skip the first 3 letters in that case
WHEN sName LIKE ('CC%') THEN SUBSTRING(sName, 4, LEN(sName) - 3)
WHEN sName LIKE ('YS%') THEN SUBSTRING(sName, 4, LEN(sName) - 3)
-- Else use the name as-is
ELSE sName
END AS sNameNormalized
FROM
tblUser
WHERE bActive = 'Y'
AND bManager = 'Y'
) as tblUserNameNormalized
LEFT JOIN (
select oc.lUserID,
count(lDiaryHeaderID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = lOwnersCorporationID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
and dh.dActionDueDate < cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) od on tblUserNameNormalized.lUserID = od.lUserID
LEFT JOIN (
select oc.lUserID,
count(lDiaryHeaderID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = lOwnersCorporationID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
and dh.dActionDueDate = cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) dt on tblUserNameNormalized.lUserID = dt.lUserID
LEFT JOIN (
select oc.lUserID,
count(lDiaryHeaderID) cnt
from DiaryHeader dh
inner join OwnersCorporation oc on lObjectID = lOwnersCorporationID
where sObjectType = 'B'
and dh.bRecordClosed = 'N'
--and dh.dActionDueDate < cast(GETDATE() as date)
and oc.bManaged = 'Y'
group by oc.lUserID
) td on tblUserNameNormalized.lUserID = td.lUserID
GROUP BY tblUserNameNormalized.sNameNormalized
答案 2 :(得分:1)
是的,它会给出错误,因为在您的代码中,您正在使用带有聚合函数的GROUP BY子句。
请尝试下面的脚本。
选择a.sName,Sum(TotalOverDue)作为TotalOverDue
FROM(
选择替换(替换(sName,&#39; CC&#39;,&#39;&#39;),&#39; YS&#39;,&#39;&#39;)作为sName
,(选择计数(lDiaryHeaderID)
来自DiaryHeader
内部联接OwnersCorporation on lObjectID = lOwnersCorporationID
其中
sObjectType =&#39; B&#39;
和DiaryHeader.bRecordClosed =&#39; N&#39;
和DiaryHeader.dActionDueDate&lt;施放(GETDATE()作为DATE)
AND OwnersCorporation.bManaged =&#39; Y&#39;
AND tbluser.lUserID = strata.dbo.OwnersCorporation.lUserID
)作为TotalOverDue
FROM tblUser
WHERE bActive = 'Y'
AND bManager = 'Y' ) a
按名称分组
答案 3 :(得分:0)
您可以像这样使用替换,然后将您想要的内容分组:
declare @CC varchar(20)
declare @YS varchar(20)
Set @CC = 'CC sample name'
Set @YS = 'CC sample name'
select replace(@CC,'CC ',''),replace(@YS,'YS ','');