使用左连接在postgres数据库中进行SQL查询

时间:2018-02-09 22:38:11

标签: java sql postgresql

好的,所以我做了一些研究,显然,左连接可以根据右边连接的表返回超过1条记录。

我的查询是:

SELECT 
 ord.ID AS ord_id,
 oli.sfid AS oli_sfid,
 ord.HasMSISDN__c AS ord_HasMSISDN__c,
 ord.dealer_code__c AS ord_dealer_code__c, 
 ord.recordtypeid AS ord_recordtypeid,
 ord.order_number__c AS ord_order_number__c,
 ord.status AS ord_status,
 ord.opportunityid AS ord_opportunityid,
 ord.sfid AS ord_sfid,
 ord.cancelled_by__c AS ord_cancelled_by__c,
 ord.cancelled_on__c AS ord_cancelled_on__c,
 ord.created_by__c AS ord_created_by__c,
 ord.created_on__c AS ord_created_on__c,
 ord.docusign_email_address__c AS ord_docusign_email_address__c,
 ord.esignature_resent_to__c AS ord_esignature_resent_to__c, 
 ord.esignature_resent_by__c AS ord_esignature_resent_by__c,
 ord.esignature_resent_on__c AS ord_esignature_resent_on__c, 
 ord.pricebook2id AS ord_pricebook2id,
 cont.opportunity__c AS cont_opportunity__c,
 cont.sfid AS cont_sfid,
 opp.isclosed AS opp_isclosed,
 opp.sfid AS opp_sfid,
 opp.recordtypeid AS opp_recordtypeid,
 opp.pricebook2id AS opp_pricebook2id, 
 accban.sfid AS accban_sfid, 
 accban.ban__c AS accban_ban__c,
 usr.sfid AS usr_sfid  
 FROM fullsbxsalesforce.order ord
 LEFT JOIN fullsbxsalesforce.contract cont ON ord.contractid = cont.sfid
 LEFT JOIN fullsbxsalesforce.opportunity opp ON cont.opportunity__c = opp.sfid
 LEFT JOIN fullsbxsalesforce.user usr ON (ord.dealer_code__c = usr.dealer_code_bd__c OR ord.dealer_code__c = usr.Dealer_Code_Co_Sell__c OR ord.dealer_code__c = usr.Rep_Dealer_Code__c OR ord.dealer_code__c = usr.dealer_code_secondary__c) LEFT JOIN fullsbxsalesforce.account_ban_tax_id__c accban ON ord.ban_number__c = accban.ban__c 
 LEFT JOIN fullsbxsalesforce.orderitem oli ON ord.sfid = oli.orderid 
 WHERE ord.sfid = 'SPECIFIC ID'

最初,我的印象是这会返回1行。我错了,它返回3行,因为订单附加了3个不同的OLI。如何确保或更改我的逻辑,以便我以相同的顺序返回OLI的集合或仅返回第一个OLI,以便我不处理3个重复

3 个答案:

答案 0 :(得分:1)

不是很好,但您可以在子FROM子句中将子查询设置为表,而不是使用oli进行左连接:

, (select * from fullsbxsalesforce.orderitem WHERE ord.sfid = orderid limit 1) oli

答案 1 :(得分:1)

如果您希望以相同的顺序返回行,只需在查询的最后添加ORDER BY <col_name_list>子句即可。

OLI是一个独特的价值吗?哪个表定义了OLI?

如果您始终希望此查询始终返回一行,只需在查询末尾添加LIMIT 1即可。

如果您的查询返回多个OLI并且您只需要每个OLI一行,那么您可以使用窗口函数:

SELECT ...
FROM (
  -- Your initial query with new field added
  SELECT ...
  ROW_NUMBER() OVER(PARTITION BY OLI_field_name ORDER BY <ordering_clause>) AS RowRank
  FROM ...
) src
WHERE RowRank = 1

这将每<OLI_field_name>返回一行。

<强>更新
如果您希望每个OLI只有一行并保留所有详细信息,请使用窗口函数方法。像这样:

SELECT *
FROM (
  SELECT 
   ord.ID AS ord_id,
   oli.sfid AS oli_sfid,
   ord.HasMSISDN__c AS ord_HasMSISDN__c,
   ord.dealer_code__c AS ord_dealer_code__c, 
   ord.recordtypeid AS ord_recordtypeid,
   ord.order_number__c AS ord_order_number__c,
   ord.status AS ord_status,
   ord.opportunityid AS ord_opportunityid,
   ord.sfid AS ord_sfid,
   ord.cancelled_by__c AS ord_cancelled_by__c,
   ord.cancelled_on__c AS ord_cancelled_on__c,
   ord.created_by__c AS ord_created_by__c,
   ord.created_on__c AS ord_created_on__c,
   ord.docusign_email_address__c AS ord_docusign_email_address__c,
   ord.esignature_resent_to__c AS ord_esignature_resent_to__c, 
   ord.esignature_resent_by__c AS ord_esignature_resent_by__c,
   ord.esignature_resent_on__c AS ord_esignature_resent_on__c, 
   ord.pricebook2id AS ord_pricebook2id,
   cont.opportunity__c AS cont_opportunity__c,
   cont.sfid AS cont_sfid,
   opp.isclosed AS opp_isclosed,
   opp.sfid AS opp_sfid,
   opp.recordtypeid AS opp_recordtypeid,
   opp.pricebook2id AS opp_pricebook2id, 
   accban.sfid AS accban_sfid, 
   accban.ban__c AS accban_ban__c,
   usr.sfid AS usr_sfid,
   ROW_NUMBER() OVER(PARTITION BY oli.sfid ORDER BY <order_col>) AS RowRank -- Assigns a rank to each row with the same oli.sfid value
  FROM fullsbxsalesforce.order ord
  LEFT JOIN fullsbxsalesforce.contract cont ON ord.contractid = cont.sfid
  LEFT JOIN fullsbxsalesforce.opportunity opp ON cont.opportunity__c = opp.sfid
  LEFT JOIN fullsbxsalesforce.user usr ON (ord.dealer_code__c = usr.dealer_code_bd__c OR ord.dealer_code__c = usr.Dealer_Code_Co_Sell__c OR ord.dealer_code__c = usr.Rep_Dealer_Code__c OR ord.dealer_code__c = usr.dealer_code_secondary__c)
  LEFT JOIN fullsbxsalesforce.account_ban_tax_id__c accban ON ord.ban_number__c = accban.ban__c 
  LEFT JOIN fullsbxsalesforce.orderitem oli ON ord.sfid = oli.orderid 
  WHERE ord.sfid = 'SPECIFIC ID'
) src
WHERE RowRank = 1 -- Only get one row per oli.sfid value

这假设oli.sfidOLI ID

只需更改外部SELECT *即可返回除RowRank以外的所有字段。另外,修改<order_col>值以确定要为每个oli.sfid返回哪一行。

答案 2 :(得分:1)

我会质疑你是否只想要一张唱片?我看到两个可能的答案:

1。您想要所有订单商品

您从OrderItems表中选择意味着您需要来自那里的记录。如果三条记录与您的结果相符,那么您是否想要随意忽略某些记录似乎不合逻辑?

(我已经看到了,并且已经完成了,但它表明存在问题)

2。您根本不需要订购商品

这似乎更有可能,基于您愿意放弃数据。

您愿意将所有数据丢弃在一起意味着您实际上并不想要它。如果你不想要它,就根本不要包括该表。

结论

查看您的查询我猜你是2号。问题更可能是您不必要地包含了一个表。

您说oli.sfid AS oli_sfid的位置,您的意思是获得订单的sfid吗?如果是,则您不再需要OrderItems上的加入。

如果在阅读完所有内容之后,您仍然确定只需要一个完全随意的订单项order bylimit(正如其他人所建议的那样)就是解决方案。

3。编辑:第三种情况

在阅读OP的评论后:如果尝试验证OrderItems存在的所有内容,则聚合可能是另一种方式:

SELECT ord.ID AS ord_id,
       count(*) AS oli_count,
       ord.HasMSISDN__c AS ord_HasMSISDN__c,
       ...
       accban.ban__c AS accban_ban__c,
       usr.sfid AS usr_sfid  
FROM   order ord
       ...
       LEFT JOIN orderitem oli ON ord.sfid = oli.orderid 
WHERE  ord.sfid = 'SPECIFIC ID'
GROUP BY
       ord.ID,
       ord.HasMSISDN__c,
       ...
       accban.ban__c,
       usr.sfid

虽然在这种情况下,group by很难维护。

如果目标是忽略没有与之关联的项目的订单,那么您不需要left join,而是需要inner join

SELECT ord.ID AS ord_id,
       ...
       oli.sfid AS oli_sfid,
       usr.sfid AS usr_sfid  
FROM   fullsbxsalesforce.order ord
       INNER JOIN orderitem oli ON ord.sfid = oli.orderid 
       LEFT JOIN contract cont ON ord.contractid = cont.sfid
       LEFT JOIN opportunity opp ON cont.opportunity__c = opp.sfid
       LEFT JOIN user usr ON ord.dealer_code__c = usr.dealer_code_bd__c 
                             OR ord.dealer_code__c = usr.Dealer_Code_Co_Sell__c 
                             OR ord.dealer_code__c = usr.Rep_Dealer_Code__c 
                             OR ord.dealer_code__c = usr.dealer_code_secondary__c
       LEFT JOIN account_ban_tax_id__c accban ON ord.ban_number__c = accban.ban__c 
 WHERE ord.sfid = 'SPECIFIC ID'

请注意表序列中orderitem的位置变化。