【问题标题】:SQL query , group by only one columnSQL查询,仅按一列分组
【发布时间】:2018-10-17 08:51:15
【问题描述】:

我只想按项目对该查询进行分组,因为同一项目有两条记录,但我只想要一条。 但是当我添加 group by 子句时,它会要求我添加其他列以及哪些分组不起作用。

*

DECLARE @Year varchar(75) = '2018'
DECLARE @von DateTime = '1.09.2018'
DECLARE @bis DateTime = '30.09.2018'
select new_projekt ,new_geschftsartname, new_mitarbeitername, new_stundensatz
from Filterednew_projektkondition ps
left join Filterednew_fakturierungsplan fp on ps.new_projekt = fp.new_hauptprojekt1
where ps.statecodename = 'Aktiv'
  and fp.new_startdatum >= @von +'00:00:00' 
  and fp.new_enddatum <= @bis +'23:59:59'
  --and new_projekt= Filterednew_projekt.new_
--group by new_projekt

*

查看列 new_projekt 。第 2 行和第 3 行有相同的项目,但我希望它只出现一次。由于其他列不同,这是不可能的。 如果感兴趣的话,还有另一个coluim projectcondition id对两者都是唯一的

【问题讨论】:

  • 如果列不包含在GROUP BY 中,那么它必须在聚合函数中。我们无法运行您的查询,因为我们无权访问它;所以你能详细说明一下吗?提供样本数据和预期结果。
  • WHERE 子句中的 fp 条件将 LEFT JOIN 转换为 INNER JOIN。将这些条件移至 ON 子句以获得真正的 LEFT JOIN 结果。
  • 使用GROUP BY进行聚合,使用DISTINCT选择唯一记录。
  • 嗨,请查看 new_projekt 列。第 2 行和第 3 行有相同的项目,但我希望它只出现一次。由于其他列不同,这是不可能的。您了解问题吗?
  • OK 我们了解您的问题。下一个问题:对于 new_ges... 和 new_stund... 列,您有两个不同的值。合并两行时应该显示哪一个?

标签: sql sql-server ssrs-2012


【解决方案1】:

你不能要求数据库为你任意决定,做组的时候应该扔掉哪些记录。你必须准确和具体

例如,这里有一些关于一个人的数据:

Name, AddressZipCode
John Doe, 90210
John Doe, 12345

SELECT name, addresszipcode FROM person INNER JOIN address on address.personid = person.id

为这个人存储了两个地址,输出中重复了人员数据!

“我不想这样。我只想看到这个人的一行,以及他的地址”

哪个地址?

这就是你必须告诉数据库的内容

“嗯,显然是他现在的地址”

你如何表示一个地址是当前的?

“结束日期为空的那个”

SELECT name, addresszipcode FROM person INNER JOIN address on address.personid = person.id WHERE address.enddate = null

如果您仍然得到两个地址,则有两个地址记录为空 - 您的数据违反了您的业务数据建模原则(“一个人的地址历史记录最多应该有一个当前的地址,表示截止日期为空") - 修复数据

“为什么我不能按名称分组?”

你可以,但如果你这样做了,你仍然必须告诉数据库如何积累它显示给你的非名字数据。你想要一个地址数据,它有 2 个要显示给你,你必须告诉它要丢弃哪个。你可以这样做:

SELECT name, MAX(addresszipcode) FROM person INNER JOIN address on address.personid = person.id GROUP BY name

“但我不想要最大邮政编码?这没有意义”

好的,使用 MIN、SUM、AVG,任何有意义的东西。如果这些都没有意义,则使用有意义的东西,例如具有最高结束日期的地址行,或作为未来结束日期的最低结束日期。如果您只希望显示一个地址,您必须决定如何将该数据归结为一条记录 - 您必须编写数据库遵循的规则,并且毫无疑问您必须创建一个规则 所以让它成为一个描述你真正想要的规则


好的,所以您创建了一个规则 - 您只需要具有最小 new_stundenstatz 的行

DECLARE @Year varchar(75) = '2018'
DECLARE @von DateTime = '1.09.2018'
DECLARE @bis DateTime = '30.09.2018'
select new_projekt ,new_geschftsartname, new_mitarbeitername, new_stundensatz
from 

(SELECT *, ROW_NUMBER() OVER(PARTITON BY new_projekt ORDER BY new_stundensatz) rown FROM Filterednew_projektkondition) ps

left join 
Filterednew_fakturierungsplan fp on ps.new_projekt = fp.new_hauptprojekt1 
where ps.statecodename = 'Aktiv'
  and fp.new_startdatum >= @von +'00:00:00' 
  and fp.new_enddatum <= @bis +'23:59:59'
  and ps.rown = 1

在这里,我使用了一个分析操作来对您的 PS 表中的行进行编号。它们按new_stundensatz 的升序编号,从 1 开始。编号在new_projekt 更改时重新开始,因此每个new_projekt 将有一个数字 1 行.. 然后我们将其设为 where

(对将来应用此技术很有帮助。如果是我们要添加行号的 FP 表,我们需要将 AND fp.rown= 1 放在 ON 子句中,而不是 WHERE 子句中,因为把它在 where 会使 LEFT 连接表现得像一个 INNER,隐藏没有任何 FP 匹配记录的行)

【讨论】:

  • OVER 关键字附近的语法不正确。我修复了分区拼写,但仍然出现错误?
  • 也是新的:studensatz 在 Filterednew_projektkondition 表中,而不是在 Filterednew_fakturierungsplan 中
  • Row_Number is missing () 它修复了错误但 new_stundesatz 在其他表中。我该如何解决这个问题?
  • 已解决,抱歉。完全限定每个列名始终是一个好主意(将所有缺少的 PS. 和 FP. 添加到选择列表中的列名中),因为它可以防止查询在添加到生产系统后停止工作 - 如果将来有人添加与另一个表中的现有列同名的 db 列(例如,将来有人将 new_studensatz 添加到 fp 表中)然后使用两个表的这个查询将突然对命名列有一个模棱两可的引用;这就是为什么用表别名完全限定每一列是个好主意
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 2011-09-08
  • 2020-06-05
相关资源
最近更新 更多