Mysql SQL Server中Select的正确格式
对于任何数据库,我都有一个简单的查询,它总是在MySQL中运行,而不是在SQL Server中运行Mysql SQL Server中Select的正确格式,mysql,sql-server,Mysql,Sql Server,对于任何数据库,我都有一个简单的查询,它总是在MySQL中运行,而不是在SQL Server中运行 select tagalerts.id, ts, assetid, node.zonename, battlevel from tagalerts, node where ack=0 and tagalerts.nodeid=node.id group by assetid order by ts desc 错误是: 列tagalerts.id在选择列表中无效,因为它未包含在聚合函数或grou
select
tagalerts.id,
ts,
assetid,
node.zonename,
battlevel
from tagalerts, node
where
ack=0 and
tagalerts.nodeid=node.id
group by assetid
order by ts desc
错误是:
列tagalerts.id在选择列表中无效,因为它未包含在聚合函数或group by子句中
将tagalerts.id
添加到groupby
子句并不是一个简单的情况,因为ts
和assetid
等会重复错误,这意味着所有选择都需要在一个组或聚合函数中。。。这两种情况都会导致无意义和不准确的结果
将select拆分为子查询以正确排序和分组(这同样适用于MySQL,正如您所期望的那样)会使情况变得更糟
SELECT * from
(select
tagalerts.id,
ts,
assetid,
node.zonename,
battlevel
from tagalerts, node
where
ack=0 and
tagalerts.nodeid=node.id
order by ts desc
)T1
group by assetid
除非使用TOP etc,否则order by子句在视图、内联函数、派生表和表达式中无效
“正确输出”应为
id ts assetid zonename battlevel
1234 a datetime 1569 Reception 0
3182 another datetime 1572 Reception 0
要么我完全错误地阅读了SQL Server的规则,要么这是该数据库的一个主要缺陷
如何编写此代码以在两个系统上都工作?在大多数数据库中,如果不使用聚合函数,则不能只包含不在
分组依据中的列
MySql是一个例外。但MS SQL Server并非如此
因此,您可以仅使用“assetid”来保留分组
然后对所有其他列使用适当的聚合函数
此外,为了老天爷的缘故,请使用该语法。
类似SQL的select*from table1,table2,其中table1.id2=table2.id
使用上个世纪的语法
SELECT
MAX(node.id) AS id,
MAX(ta.ts) AS ts,
ta.assetid,
MAX(node.zonename) AS zonename,
MAX(ta.battlevel) AS battlevel
FROM tagalerts AS ta
JOIN node ON node.id = ta.nodeid
WHERE ta.ack = 0
GROUP BY ta.assetid
ORDER BY ta.ts DESC;
在MS SQL Server中使用的另一个技巧是窗口函数行号。
但这可能不是你需要的
例如:
SELECT id, ts, assetid, zonename, battlevel
FROM
(
SELECT
node.id,
ta.ts,
ta.assetid,
node.zonename,
ta.battlevel,
ROW_NUMBER() OVER (PARTITION BY ta.assetid ORDER BY ta.ts DESC) AS rn
FROM tagalerts AS ta
JOIN node ON node.id = ta.nodeid
WHERE ta.ack = 0
) q
WHERE rn = 1
ORDER BY ts DESC;
我强烈怀疑这个查询是错误的,即使在MySql中也是如此
我们缺少很多细节(示例数据,我们不知道所有列都属于哪个表),但我知道的是您正在按assetid
进行分组,其中一个assetid
值可能在组中有多个ts
(时间戳)值。看起来您也在依靠ts desc的顺序来确保首先在结果中看到最近的时间戳,并确保每个assetid
组使用该组最新的ts
时间戳
MySql只保证前者,不保证后者。此查询中的任何内容都不能保证每个assetid
使用的是可用的最新时间戳。您可能会看到错误的时间戳,然后也会将这些错误的时间戳用于
订购方。这就是Sql Server规则要停止的问题MySql违反了SQL标准,允许您编写错误的查询
相反,您需要查看每一列,或者将其按
添加到组中(最好是在所有值都已知相同的情况下),或者将其包装在一个聚合函数中,如MAX()
、MIN()
、AVG()
,等等,这样就可以确定使用组中的值
如果一个组中某列的所有值都相同,则将其添加到组中是没有问题的。如果值不同,则需要精确地确定为结果集选择了哪一个
当我在这里时,tagalerts,node
join语法已经过时20多年了。在每个表中使用别名,并在每个列前面加上别名也是一种很好的做法。我提到这些是为了解释为什么我在下面的代码示例中更改了它,尽管我只在我确信该列属于哪个表的列前加前缀
此查询应在两个数据库上运行:
SELECT ta.assetid, MAX(ta.id) "id", MAX(ta.ts) "ts",
MAX(n.zonename) "zonename", MAX(battlevel) "battlevel"
FROM tagalerts ta
INNER JOIN node n ON ta.nodeid = n.id
WHERE ack = 0
GROUP BY ta.assetid
ORDER BY ts DESC
这里还有一个问题,结果可能是从联接的节点
表中的不同记录中选择值。因此,如果battlevel
是节点
表的一部分,您可能会看到一个结果,该结果将zonename
与数据中任何记录中从未出现的battlevel
相匹配。在Sql Server中,通过使用APPLY
将一个节点
记录与每个tagalert
匹配,可以轻松解决此问题。MySql不支持这一点(至少自2012年以来,其他所有主要数据库中都有应用程序或等效程序),但在这种情况下,您可以使用它模拟两个连接,其中第一个连接是一个子查询,它使用GROUP BY来确定值将唯一标识所需的节点
记录,第二个连接是到节点
表以实际生成该记录。不幸的是,我们需要了解更多有关表的信息,才能真正为您编写此代码。将Order By
移动到group By
下的外部查询,但您仍然会从分组中得到错误。相反,该缺陷存在于mysql中。如果在三列之间使用聚合,则只需要按其他列进行分组。如果其他列的值超过1,那么如果没有group by,将返回哪个值?您希望得到什么结果,为什么要使用group by?谢谢,但是,这会导致T1.id在选择列表中无效,因为它既不包含在聚合函数中,也不包含在group by CLUASE中。MySql允许您在这里执行的操作实际上违反了SQL标准。Sql Server的方法(要求您使用聚合函数,如MAX()
或AVG()
,对不在分组依据
)中的列进行聚合)是正确的。感谢您,我添加了最大值,但它随后抱怨了order by,因此我删除了order by,它起了作用(可能是因为所有的最大值)。我觉得很奇怪。我将远离SQL Server。是的,在MS SQL中,如果使用TOP或FOR XML,则ORDER BY只能用于子查询。但这真的不是