6

我有以下查询:

SELECT sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount, 'rma' as     
    "creditType", "Clients"."company" as "client", "Clients".id as "ClientId", "Rmas".* 
FROM "Rmas" JOIN "EsnsRmas" on("EsnsRmas"."RmaId" = "Rmas"."id") 
    JOIN "Esns" on ("Esns".id = "EsnsRmas"."EsnId") 
    JOIN "EsnsSalesOrderItems" on("EsnsSalesOrderItems"."EsnId" = "Esns"."id" ) 
    JOIN "SalesOrderItems" on("SalesOrderItems"."id" = "EsnsSalesOrderItems"."SalesOrderItemId") 
    JOIN "Clients" on("Clients"."id" = "Rmas"."ClientId" )
WHERE "Rmas"."credited"=false AND "Rmas"."verifyStatus" IS NOT null 
GROUP BY "Clients".id, "Rmas".id;

问题是表"EsnsSalesOrderItems"可以EsnId在不同的条目中具有相同的内容。我想将查询限制为仅提取"EsnsSalesOrderItems"具有相同"EsnId".

“最后一个”条目是指以下内容:

表中最后出现的那个"EsnsSalesOrderItems"。因此,例如,如果"EsnsSalesOrderItems"有两个条目分别带有"EsnId" = 6and"createdAt" = '2012-06-19'和 ,'2012-07-19'它应该只给我来自 的条目'2012-07-19'

4

4 回答 4

16
SELECT (count(*) * sum(s."price")) AS amount
     , 'rma'       AS "creditType"
     , c."company" AS "client"
     , c.id        AS "ClientId"
     , r.* 
FROM   "Rmas"            r
JOIN   "EsnsRmas"        er ON er."RmaId" = r."id"
JOIN   "Esns"            e  ON e.id = er."EsnId"
JOIN  (
   SELECT DISTINCT ON ("EsnId") *
   FROM   "EsnsSalesOrderItems"
   ORDER  BY "EsnId", "createdAt" DESC
   )                     es ON es."EsnId" = e."id"
JOIN   "SalesOrderItems" s  ON s."id" = es."SalesOrderItemId"
JOIN   "Clients"         c  ON c."id" = r."ClientId"
WHERE  r."credited" = FALSE
AND    r."verifyStatus" IS NOT NULL 
GROUP  BY c.id, r.id;

您在问题中的查询在另一个聚合上具有非法聚合:

sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount

简化并转换为合法语法:

(count(*) * sum(s."price")) AS amount

但是你真的想乘以每组的计数吗?

"EsnsSalesOrderItems"我用 检索每组的单行DISTINCT ON。详细解释:

我还添加了表别名和格式,以使查询更易于人眼解析。如果您可以避免驼峰式大小写,则可以摆脱所有使视图蒙上阴影的双引号。

于 2012-09-29T13:16:26.633 回答
5

就像是:

join (
  select "EsnId", 
         row_number() over (partition by "EsnId" order by "createdAt" desc) as rn
  from "EsnsSalesOrderItems"
) t ON t."EsnId" = "Esns"."id" and rn = 1

EsnId"这将根据"EsnsSalesOrderItems"列选择最新的“ creation_date。由于您没有发布表的结构,因此我不得不“发明”一个列名。您可以使用任何允许您定义行顺序的列适合你。

但请记住,“最后一行”的概念仅在您指定订单或行时才有效。一个这样的表是没有顺序的,查询的结果也不是,除非你指定一个order by

于 2012-09-29T08:21:51.807 回答
4

死灵法是因为答案已经过时了。
利用PG 9.3LATERAL中引入的关键字

离开 | 对 | 内部 JOIN LATERAL

我将用一个例子来解释:
假设你有一个表“联系人”。
现在联系人具有组织单位。
他们可以在一个时间点有一个 OU,但在 N 个时间点有 N 个 OU。

现在,如果您必须在某个时间段(不是报告日期,而是日期范围)内查询联系人和 OU,如果您只是进行左连接,则可以将记录数增加 N 倍。
因此,要显示 OU,您只需为每个联系人加入第一个 OU(其中首先是任意标准 - 例如,当取最后一个值时,这只是排序时第一个值的另一种说法按日期降序排列)。

在 SQL 服务器中,您将使用交叉应用(或者更确切地说是 OUTER APPLY,因为我们需要左连接),这将在它必须连接的每一行上调用一个表值函数。

SELECT * FROM T_Contacts 

--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1 
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989

-- CROSS APPLY -- = INNER JOIN 
OUTER APPLY    -- = LEFT JOIN 
(
    SELECT TOP 1 
         --MAP_CTCOU_UID    
         MAP_CTCOU_CT_UID   
        ,MAP_CTCOU_COU_UID  
        ,MAP_CTCOU_DateFrom 
        ,MAP_CTCOU_DateTo   
   FROM T_MAP_Contacts_Ref_OrganisationalUnit 
   WHERE MAP_CTCOU_SoftDeleteStatus = 1 
   AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID 

    /*  
    AND 
    ( 
        (@in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) 
        AND 
        (@in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom) 
    ) 
    */
   ORDER BY MAP_CTCOU_DateFrom 
) AS FirstOE 

在 PostgreSQL 中,从 9.3 版开始,您也可以这样做 - 只需使用LATERAL关键字即可:

SELECT * FROM T_Contacts 

--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1 
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989


LEFT JOIN LATERAL 
(
    SELECT 
         --MAP_CTCOU_UID    
         MAP_CTCOU_CT_UID   
        ,MAP_CTCOU_COU_UID  
        ,MAP_CTCOU_DateFrom 
        ,MAP_CTCOU_DateTo   
   FROM T_MAP_Contacts_Ref_OrganisationalUnit 
   WHERE MAP_CTCOU_SoftDeleteStatus = 1 
   AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID 

    /*  
    AND 
    ( 
        (__in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo) 
        AND 
        (__in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom) 
    ) 
    */
   ORDER BY MAP_CTCOU_DateFrom 
   LIMIT 1 
) AS FirstOE 
于 2016-01-28T14:43:18.443 回答
3

尝试在您的 ON 子句中使用子查询。一个抽象的例子:

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...
于 2012-09-29T07:25:25.270 回答