限制加盟一行(Limit join to one row)

2019-09-23 05:14发布

我有以下查询:

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" = 6"createdAt" = '2012-06-19''2012-07-19'分别应该只给我从入'2012-07-19'

Answer 1:

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 。 详细说明:

  • 选择由组中每组第一排?

我还添加了表的别名和格式,使查询更容易解析人类的眼睛。 如果你能避免骆驼情况下你可以摆脱所有的双引号的混浊的看法。



Answer 2:

就像是:

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 。 当你没有张贴你的表的结构,我不得不“发明”列名。 您可以使用,使您可以在适合你的行定义顺序任何列。

但要记住,如果你specifiy订单或行的“最后一排”的概念才有效。 的桌子,这样是不是有序的,也不是一个查询的,除非你指定一个结果order by



Answer 3:

Necromancing因为答案是过时的。
就拿优势LATERALPG 9.3引入了关键字

左| 右| INNER JOIN 侧向

我将用一个例子说明:
假设你有一个表“联系人”。
现在有接触的组织单位。
他们可以在某个时间点有一个OU,但ñ组织单位在时间N个点。

现在,如果你要查询的时间段 (不报告日期,但日期范围)的接触和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 


Answer 4:

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

SELECT 
    *
FROM table1
JOIN table2 ON table2.id = (
    SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE 
    ...


文章来源: Limit join to one row