MySql 与 Postgresql 视图创建

Ale*_*vić 2 postgresql group-by

我在 MySql 中有这个视图查询,它可以工作

SELECT s.id AS id,
       s.customer_id AS customer_id,
       s.shipment_status_id AS shipment_status_id,
       ss.name AS shipment_status_name,
       s.ship_from_date AS ship_from_date,
       s.ship_to_company AS ship_to_company,
       s.ship_from_company AS ship_from_company,
       s.ship_to_address1 AS ship_to_address1,
       s.ship_to_address2 AS ship_to_address2,
       s.ship_to_postal_code AS ship_to_postal_code,
       s.ship_to_city AS ship_to_city,
       c.country AS country,
       p.tracking_numbers AS tracking_numbers,
       s.quote_service_name AS quote_service_name,
       s.quote_total_charge AS quote_total_charge,
       p.weight AS weight,
       p.insurance_amount AS insurance_amount,
       p.cod_amount AS cod_amount,
       z.fedex AS ZONE,
       s_p.code AS state_province_code,
       s_p.zone AS state_province_zone,
       ss.name AS status_name,
       i.total AS total,
       cust.first_name AS customer_first_name,
       cust.last_name AS customer_last_name,
       (CASE
            WHEN (s.additional_services_saturday_delivery = 1) THEN 'Yes'
        END) AS saturday_delivery,
       (CASE
            WHEN (s.additional_services_hold_for_pickap = 1) THEN 'Yes'
        END) AS hold_for_pickap,
       (CASE
            WHEN (s.ship_to_residential = 1) THEN 'Yes'
        END) AS ship_to_residential,
       (CASE
            WHEN (s.additional_services_signature_required = 1) THEN 'Yes'
        END) AS signature_required
FROM (((((((shipments s
            LEFT JOIN shipment_package_group_data p on((s.id = p.shipment_id)))
           LEFT JOIN country c on((s.ship_to_country_id = c.id)))
          LEFT JOIN invoice i on((s.invoice_id = i.id)))
         LEFT JOIN state_province s_p on((s.ship_to_state = s_p.id)))
        LEFT JOIN shipment_statuses ss on((s.shipment_status_id = ss.id)))
       LEFT JOIN zones z on((s.zone_id = z.id)))
      JOIN customer cust on((s.customer_id = cust.id)))
GROUP BY s.id
Run Code Online (Sandbox Code Playgroud)

但是当我尝试将其转换为 PostgreSQL 视图时:

    SELECT s.id AS id,
       s.customer_id AS customer_id,
       s.shipment_status_id AS shipment_status_id,
       ss.name AS shipment_status_name,
       s.ship_from_date AS ship_from_date,
       s.ship_to_company AS ship_to_company,
       s.ship_from_company AS ship_from_company,
       s.ship_to_address1 AS ship_to_address1,
       s.ship_to_address2 AS ship_to_address2,
       s.ship_to_postal_code AS ship_to_postal_code,
       s.ship_to_city AS ship_to_city,
       c.country AS country,
       p.tracking_numbers AS tracking_numbers,
       s.quote_service_name AS quote_service_name,
       s.quote_total_charge AS quote_total_charge,
       p.weight AS weight,
       p.insurance_amount AS insurance_amount,
       p.cod_amount AS cod_amount,
       z.fedex AS ZONE,
       s_p.code AS state_province_code,
       s_p.zone AS state_province_zone,
       ss.name AS status_name,
       i.total AS total,
       cust.first_name AS customer_first_name,
       cust.last_name AS customer_last_name,
       (CASE
            WHEN (s.additional_services_saturday_delivery = 1) THEN 'Yes'
        END) AS saturday_delivery,
       (CASE
            WHEN (s.additional_services_hold_for_pickap = 1) THEN 'Yes'
        END) AS hold_for_pickap,
       (CASE
            WHEN (s.ship_to_residential = 1) THEN 'Yes'
        END) AS ship_to_residential,
       (CASE
            WHEN (s.additional_services_signature_required = 1) THEN 'Yes'
        END) AS signature_required
FROM (shipments s
            LEFT JOIN shipment_package_group_data p on(s.id::INT = p.shipment_id)
           LEFT JOIN country c on((s.ship_to_country_id = c.id))
          LEFT JOIN invoice i on((s.invoice_id = i.id))
         LEFT JOIN state_province s_p on((s.ship_to_state::INT = s_p.id))
        LEFT JOIN shipment_statuses ss on((s.shipment_status_id = ss.id))
       LEFT JOIN zones z on((s.zone_id = z.id))
      JOIN customer cust on((s.customer_id = cust.id)))
GROUP BY s.id
Run Code Online (Sandbox Code Playgroud)

PostgreSQL 抱怨以下内容:

    [Err] ERROR:  column "ss.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 4:        ss.name AS shipment_status_name,
               ^
Run Code Online (Sandbox Code Playgroud)

Jos*_*idt 7

TL;DR MySQL 忽略 SQL 标准并允许您的原始查询返回不确定的结果。Postgres 不允许你这样做。您需要正确定义您期望的结果。

您可以在此 SO 帖子中看到 MySQL 所依赖的行为的解释。当您将查询转换为 Postgres 时,您需要填写原始查询的作者忽略的内容:有一个GROUP BY s.id,因此对于每个s.id分组依据,ss.name必须返回哪个?可能有几个不同的ss.name值,数据库应该如何决定给你哪一个?请注意,这ss.name不是此查询中唯一有问题的列,您正在选择的所有非聚合列可能需要在此查询中正确处理。

最终,您将需要使用以下组合:

  • GROUP BY完全摆脱并简单地返回所有结果
  • GROUP BY 您正在使用的所有非聚合列SELECT,例如GROUP BY s.id, s.customer_id, s.shipment_status_id, ...
  • 使用SELECT ... DISTINCT ON ... ORDER BY要告诉Postgres的,你只在乎曾经收到一个单一的s.customer_ids.shipment_status_idss.name,等等。对于每个s.id你是GROUP由荷兰国际集团。该ORDER BY会指示的Postgres如何决定哪些每一个s.customer_id等返回。

...而且可能还有一些我忽略的解决方法,但这应该可以让您朝着正确的方向开始。