Mysql SQL Server中Select的正确格式

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

对于任何数据库,我都有一个简单的查询,它总是在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在选择列表中无效,因为它未包含在聚合函数或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只能用于子查询。但这真的不是