Sql 在多个列上计算不同的
有没有更好的方法来执行这样的查询:Sql 在多个列上计算不同的,sql,sql-server,performance,tsql,query-optimization,Sql,Sql Server,Performance,Tsql,Query Optimization,有没有更好的方法来执行这样的查询: SELECT COUNT(*) FROM (SELECT DISTINCT DocumentId, DocumentSessionId FROM DocumentOutputItems) AS internalQuery 我需要计算此表中不同项目的数量,但不同项目超过两列 我的查询工作正常,但我想知道我是否可以只使用一个查询而不使用子查询来获得最终结果 SELECT COUNT(*) FROM DocumentOutputItems GRO
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
我需要计算此表中不同项目的数量,但不同项目超过两列
我的查询工作正常,但我想知道我是否可以只使用一个查询而不使用子查询来获得最终结果
SELECT COUNT(*)
FROM DocumentOutputItems
GROUP BY DocumentId, DocumentSessionId
您不喜欢现有查询的哪些方面?如果您担心跨两列的DISTINCT不会返回唯一的排列,为什么不试试呢 它当然可以像您在Oracle中所期望的那样工作
SQL> select distinct deptno, job from emp
2 order by deptno, job
3 /
DEPTNO JOB
---------- ---------
10 CLERK
10 MANAGER
10 PRESIDENT
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
9 rows selected.
SQL> select count(*) from (
2 select distinct deptno, job from emp
3 )
4 /
COUNT(*)
----------
9
SQL>
编辑
我在分析方面走了一条死胡同,但答案是显而易见的,令人沮丧
SQL> select count(distinct concat(deptno,job)) from emp
2 /
COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
9
SQL>
编辑2
鉴于以下数据,上述连接解决方案将计算错误:
col1 col2
---- ----
A AA
AA A
所以我们需要包含一个分隔符
select col1 + '*' + col2 from t23
/
显然,所选的分隔符必须是一个字符或一组字符,这两列中都不能出现 比如: select count(*) from (select count(*) cnt from DocumentOutputItems group by DocumentId, DocumentSessionId) t1
Select code, id, title, name
(select count(distinct col1) from mytable where code = a.code and length(title) >0)
from mytable a
group by code, id, title, name
--needs distinct over col2 as well as col1
可能只是做了与您已经做的相同的事情,但它避免了明显的区别。这里有一个没有子选择的较短版本:
SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems
它在MySQL中运行良好,我认为优化器更容易理解这一点
编辑:显然我误读了MSSQL和MySQL-对此很抱歉,但也许它会有所帮助。如果您只有一个字段需要区分,您可以使用:
SELECT COUNT(DISTINCT DocumentId)
FROM DocumentOutputItems
这将返回与原始查询计划相同的查询计划,这是在设置SHOWPLAN_ALL ON时测试的。但是,您使用的是两个字段,因此您可以尝试一些疯狂的操作,例如:
SELECT COUNT(DISTINCT convert(varchar(15),DocumentId)+'|~|'+convert(varchar(15), DocumentSessionId))
FROM DocumentOutputItems
但如果涉及空值,则会出现问题。我会坚持原来的查询。您的查询没有问题,但您也可以这样做:
WITH internalQuery (Amount)
AS
(
SELECT (0)
FROM DocumentOutputItems
GROUP BY DocumentId, DocumentSessionId
)
SELECT COUNT(*) AS NumberOfDistinctRows
FROM internalQuery
若要提高性能,可以尝试在两列的哈希值或连接值上创建一个持久化计算列 一旦它被持久化,只要该列是确定的并且您使用的是sane数据库设置,就可以对其进行索引和/或创建统计信息 我相信计算列的不同计数将等同于您的查询。编辑:更改为不太可靠的仅校验和查询 我在SQLServer2005中发现了一种实现这一点的方法,这种方法对我来说非常有效,通过将列添加到校验和函数中,我可以使用所需的任意多个列。反向函数将int转换为varchar,以使distinct更可靠
SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems
我希望SQL女士也能像A、B这样做,但它不能 起初,JayTee的回答似乎是一个解决方案,因为一些测试校验和未能创建唯一值。一个简单的例子是,CHECKSUM31467519和CHECKSUM691120823给出的答案都是55 然后,我做了一些研究,发现微软不建议使用校验和进行变更检测。在一些论坛中,一些人建议使用
SELECT COUNT(DISTINCT CHECKSUM(value1, value2, ..., valueN) + CHECKSUM(valueN, value(N-1), ..., value1))
但这也不令人困惑
可以按照中的建议使用HASHBYTES函数。然而,这也有一小部分不返回独特结果的机会
我建议使用
SELECT COUNT(DISTINCT CAST(DocumentId AS VARCHAR)+'-'+CAST(DocumentSessionId AS VARCHAR)) FROM DocumentOutputItems
当我在谷歌上搜索我自己的问题时,我发现如果你计算不同的对象,你会得到正确的返回数,我使用的是MySQL
SELECT COUNT(DISTINCT DocumentID) AS Count1,
COUNT(DISTINCT DocumentSessionId) AS Count2
FROM DocumentOutputItems
要作为单个查询运行,请连接列,然后获取连接字符串的实例的不同计数
SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
在MySQL中,您可以在不使用连接步骤的情况下执行相同的操作,如下所示:
SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;
MySQL文档中提到了此功能:
它对我有用。在oracle中:
SELECT SUM(DECODE(COUNT(*),1,1,1))
FROM DocumentOutputItems GROUP BY DocumentId, DocumentSessionId;
在jpql中:
SELECT SUM(CASE WHEN COUNT(i)=1 THEN 1 ELSE 1 END)
FROM DocumentOutputItems i GROUP BY i.DocumentId, i.DocumentSessionId;
这个怎么样,
Select DocumentId, DocumentSessionId, count(*) as c
from DocumentOutputItems
group by DocumentId, DocumentSessionId;
这将为我们提供DocumentId和DocumentSessionId的所有可能组合的计数,其中大多数是?SQL数据库可以使用类似元组的值,因此您只需执行以下操作: 选择COUNTDISTINCT DocumentId、DocumentSessionId 来自文档输出项; 如果您的数据库不支持此功能,则可以根据@oncel umut turer的校验和建议或提供良好唯一性的其他标量函数(例如。 COUNTDISTINCT CONCATDocumentId“:”,DocumentSessionId 元组的相关使用正在查询中执行,例如: 从DocumentOutpuItems中选择* 其中DocumentId、DocumentSessionId位于“a”、“1”、“b”、“2”中;
您只需使用计数功能两次即可 在这种情况下,它将是:
SELECT COUNT (DISTINCT DocumentId), COUNT (DISTINCT DocumentSessionId)
FROM DocumentOutputItems
此代码使用distinct on 2参数,并提供特定于这些distinct值row count的行数计数。在MySQL中,它对我来说就像一种魅力
select DISTINCT DocumentId as i, DocumentSessionId as s , count(*)
from DocumentOutputItems
group by i ,s;
我有一个类似的问题,但我的查询是一个子查询,在主查询中有比较数据。比如: select count(*) from (select count(*) cnt from DocumentOutputItems group by DocumentId, DocumentSessionId) t1
Select code, id, title, name
(select count(distinct col1) from mytable where code = a.code and length(title) >0)
from mytable a
group by code, id, title, name
--needs distinct over col2 as well as col1
忽略这一点的复杂性,我意识到我无法使用原始问题中描述的双子查询将a.code的值放入子查询中
Select count(1) from (select distinct col1, col2 from mytable where code = a.code...)
--this doesn't work because the sub-query doesn't know what "a" is
因此,我最终发现我可以作弊,并合并了以下专栏:
Select count(distinct(col1 || col2)) from mytable where code = a.code...
这就是最终起作用的方法我用过这个方法
这对我很有效
SELECT COUNT(DISTINCT DocumentID || DocumentSessionId)
FROM DocumentOutputItems
就我的情况而言,它提供了正确的结果。如果您使用的是固定长度的数据类型,您可以转换为二进制,以非常轻松和快速地完成此操作。假设DocumentId和DocumentSessionId都是整数,因此长度为4字节
SELECT COUNT(DISTINCT CAST(DocumentId as binary(4)) + CAST(DocumentSessionId as binary(4)))
FROM DocumentOutputItems
我的具体问题要求我将总和除以各种外键和日期字段的不同组合的计数,用另一个外键分组,偶尔用某些值或键过滤。表非常大,使用子查询大大增加了查询时间。而且由于复杂性,统计根本不是一个可行的选择。校验和解决方案的转换速度也太慢了,特别是由于各种数据类型,我不能冒其不可靠性的风险
然而,与简单使用求和相比,使用上述解决方案几乎没有增加查询时间,应该是完全可靠的!它应该能够帮助处于类似情况的其他人,因此我将其发布在这里。IordanTanev,Mark Brackett,RC-感谢您的回复,这是一次很好的尝试,但您需要在发布之前检查您所做的事情。您提供的查询与我的查询不同。你可以很容易地看到我总是有一个标量a结果,但你的查询返回多行。刚刚更新了问题,以包含你从一个回答中得到的澄清性评论。易建联:这是一个好问题。我还想知道是否有一种更简单的方法来做这件事为了得到最终的答案,你必须用另一个SELECT COUNT*FROM….来包装它。从本质上说,这个答案只是提供了另一种方法来列出要计算的不同值。这不比你原来的解决方案好多少。谢谢戴夫。我知道在我的情况下,你可以使用group by而不是distinct。我想知道你是否只用一个查询就能得到最终结果。我认为这是不可能的,但我可能错了。在SQL Server中,您会看到:Msg 102,级别15,状态1,第1行“,”附近的语法不正确。这就是我所想的。如果可能的话,我想在MSSQL中做类似的事情。@Kamil Nowicki,在SQL Server中,一次计数只能有一个字段,在我的回答中,我显示您可以将两个字段连接成一个字段,然后尝试这种方法。不过,我还是坚持原样,因为查询计划最终都是一样的。请看一下@JayTee-answer。它就像一个符咒。计算不同的校验和[Field1],[Field2]即使在MySQL中,这也不完全等同于原始查询,因为带有null的行不会被计算。在我使用SET SHOWPLAN_ALL ON的测试中,它具有相同的执行计划和完全相同的TotalSubtreeCost,具体取决于原始查询的复杂性,使用GROUP BY解决这一问题可能会给查询转换带来一些额外的挑战,以实现所需的输出,例如,当原始查询已经有GROUP BY或具有来自me的子句…+1时。谢谢你的回答。我的查询工作得很好,但我想知道是否可以只使用一个查询而不使用我的子查询+1来获得最终结果。谢谢,但我会按照你的建议坚持我的问题。使用convert会进一步降低性能。+1很好,当您有正确的列类型来对…执行校验和时,它会非常完美;对于像校验和这样的散列,对于不同的输入,返回相同散列的可能性很小,因此计数可能会稍微偏离。HashBytes的可能性更小,但仍然不是零。如果这两个ID是int的32b,那么无损散列可以将它们组合成像Id1一样的bigint 64b,这种可能性甚至不是很小,特别是当您开始组合列时,这就是它的本意。我对这种方法很好奇,在一个特殊的例子中,校验和的计数减少了10%。如果你想得再长一点,校验和只返回一个int,所以如果你对一个完整的bigint范围进行校验和,你会得到一个比实际值小20亿倍的不同计数-1对查询进行了更新,使其包括使用REVERSE来消除重复的可能性。如果我们避免校验和,我们可以将这两个值连接在一起吗?我想,这有可能被视为同一件事:“他”、“艺术”、“听到”、“t”。但我认为可以用一个分隔符来解决这个问题,因为@APC提出了一些在两列中都没有出现的值,所以“he | art”!=”听到了吗?简单的连接方法还有其他问题吗?非常好的建议!我读得越多,就越意识到SQL更多的是应用纯逻辑,而不是了解语法和函数。。我希望我有两张赞成票!这个建议太好了。这避免了我编写不必要的代码。请添加一个示例或代码示例,以详细说明这意味着什么以及如何执行?这与在这些列上创建多列索引有何区别?如果这毫无意义,我很抱歉。我是SQL新手。上面的查询将返回与OP不同的结果集
寻找DocumentId和DocumentSessionId的不同组合。如果OP使用的是MySQL而不是MS SQL Server,Alexander Kjäll已经发布了正确的答案。这是一个SQL Server问题,您发布的两个选项都已在以下问题的答案中提到:and.FWIW,这几乎适用于PostgreSQL;只需要额外的括号:从DocumentOutputiItems中选择COUNTDISTINCT DocumentId、DocumentSessionId;使用此方法时要非常小心,因为它可能导致计数错误。下面的示例将返回计数1。DocumentID | DocumentSessionID A | AB AA | BAs@Bort注意到,第一个选项可能会导致错误的结果,最好使用CONCAT|WS编写。第二种方法也不能保证产生与原始查询相同的结果,以防任何列可为空。哪些数据库支持select countdistincta,b?:D@VytenisBivainis我知道PostgreSQL不确定是哪个版本。这不符合问题中的要求,它为每列单独计算不同值。它不提供两列同时使用的不同值的计数。至少在MySQL 5.8中没有。这个问题被标记为SQL Server,这不是SQL Server语法