为什么我会收到错误消息“'<列名>' 必须出现在 GROUP BY 子句中或用于聚合函数中”?

0 postgresql group-by errors

我哪里错了?为什么在添加 MAX 函数时会收到该消息?

查询涉及:

WITH
   references_cve AS (
      SELECT vulnerability_id, reference
      FROM dim_vulnerability_reference
      WHERE dim_vulnerability_reference.source = 'NVD'
   )
SELECT DISTINCT ON (
      da.ip_address,
      favi.port,
      dv.severity,dp.name, dv.title,
      dv.description,
      fix,
      dv.nexpose_id,
      cve.reference,
      da.host_name,
      dos.description,
      da.last_assessed_for_vulnerabilities,
      davbs.solution_id
   )
   da.ip_address AS IPAddress,
   CASE WHEN favi.port = -1 THEN NULL ELSE favi.port END AS Port,
   dv.severity AS Severity,
   dp.name AS Protocol,
   dv.title AS VulnerabilityName,
   htmlToText(dv.description) AS Summary,
   htmlToText(dv.description) AS Description,
   htmlToText(fix) as Solution,
   'https://www.rapid7.com/db/vulnerabilities/' || dv.nexpose_id as SeeAlso,
   dv.nexpose_id AS NexposeID,
   ''||null as PluginOutput,
   cve.reference as CVE,
   ''||null as APPorOS,
   ''||null as BU,
   da.host_name as DEVICENAME,
   date(da.last_assessed_for_vulnerabilities) as LastScanDate,
   dos.description as DeviceOperatingSystem,
   MAX(sr.solution_id),
   davbs.vulnerability_id,
   dv.vulnerability_id


FROM fact_asset_vulnerability_instance favi
   LEFT JOIN dim_asset da USING (asset_id)
   LEFT JOIN dim_vulnerability dv USING (vulnerability_id)
   LEFT JOIN dim_site_asset dsa USING (asset_id)
   LEFT JOIN dim_site ds USING (site_id)
   LEFT JOIN dim_vulnerability_status dvs USING (status_id)
   LEFT JOIN dim_protocol dp USING (protocol_id)
   LEFT JOIN dim_service dsvc USING (service_id)
   LEFT JOIN dim_operating_system dos USING (operating_system_id)
   LEFT JOIN dim_asset_vulnerability_best_solution davbs ON da.asset_id = davbs.asset_id AND dv.vulnerability_id = davbs.vulnerability_id
   LEFT JOIN dim_solution sr on davbs.solution_id = sr.solution_id
   LEFT JOIN references_cve cve on favi.vulnerability_id = cve.vulnerability_id

ORDER BY da.ip_address
Run Code Online (Sandbox Code Playgroud)

结果消息:

错误:列“da.ip_address”必须出现在 GROUP BY 子句中或用于聚合函数
字符:456

McN*_*ets 5

我假设您使用的是 PostgreSQL。

我想 - 我无法重现你的整个查询 - 你收到这个错误是因为你添加了一个聚合:

MAX(sr.solution_id)
Run Code Online (Sandbox Code Playgroud)

我已经建立了一个最小的例子来重现这个错误:

CREATE TABLE t(id INT, foo int, bar int);
INSERT INTO t VALUES
(1, 10, 20),
(1, 11, 21),
(1, 12, 22),
(2, 30, 40),
(2, 31, 41),
(2, 32, 42);
Run Code Online (Sandbox Code Playgroud)

使用类似的语法:

SELECT
    DISTINCT ON (id) id,
    foo,
    MAX(bar) bar
FROM
    t
ORDER BY 
    id, foo;
Run Code Online (Sandbox Code Playgroud)

它返回下一个错误:

错误:列“t.id”必须出现在 GROUP BY 子句中或用于聚合函数第 2 行:DISTINCT ON (id) id,

解决它的一个想法是使用子查询来计算聚合值(但这并不像人们期望的那样工作):

SELECT
    DISTINCT ON (id) id,
    foo,
    (SELECT 
        MAX(bar)
     FROM
       t t1
     WHERE
       t1.id = t.id) max_bar
FROM
    t
ORDER BY 
    id, max_bar;
Run Code Online (Sandbox Code Playgroud)
身份证 | 富| 最大栏
-: | --: | ------:
 1 | 10 | 22
 2 | 30 | 42

假设您想要每行一行id,即具有最大值的行bar,那么这就是如何使用DISTINCT ON

SELECT
    DISTINCT ON (id) id,
    foo,
    bar
FROM
    t
ORDER BY 
    id, bar DESC;
Run Code Online (Sandbox Code Playgroud)
身份证 | 富| 最大栏
-: | --: | ------:
 1 | 12 | 22
 2 | 32 | 42

db<>在这里摆弄


使用DISTINCT ON和在澄清一点要求的评论之后,您希望每个漏洞都有一行 - 标识为dv.nexpose_id

查询每个漏洞都有一行,但是,某些漏洞有 1 个以上的解决方案,这会导致该行重复但具有不同的解决方案 ID。我只需要每行 1 个解决方案 ID。

Nexpose ID 用于识别漏洞。

您的查询应该被重写:

WITH
   references_cve AS (
      SELECT vulnerability_id, reference
      FROM dim_vulnerability_reference
      WHERE dim_vulnerability_reference.source = 'NVD'
   )
SELECT DISTINCT ON (
      dv.nexpose_id    -- one result for each vulnearibility
   )
   da.ip_address AS IPAddress,
      -- ...
   dos.description as DeviceOperatingSystem,

   sr.solution_id,               --<-- This is changed

   davbs.vulnerability_id,
   dv.vulnerability_id


FROM fact_asset_vulnerability_instance favi
   LEFT JOIN dim_asset da USING (asset_id)

      -- ...

ORDER BY 
      dv.nexpose_id,        -- same as the DISTNCT ON   
      sr.solution_id DESC   -- plus the ordering we want
  ;
Run Code Online (Sandbox Code Playgroud)