在Postgresql中使用3个表中的2个左外连接

时间:2015-01-19 14:50:58

标签: postgresql

我需要向系统显示所有输入日期范围的客户。 所有客户都被分配到一个组,但不一定分配给员工。

当我按原样运行查询时:

SELECT
 clients.name_lastfirst_cs, 
  to_char (clients.date_intake,'MM/DD/YY')AS Date_Created,
  clients.client_id, 
  clients.display_intake, 
  staff.staff_name_cs, 
  groups.name
FROM 
  public.clients, 
  public.groups, 
  public.staff, 
  public.link_group
WHERE 
  clients.zrud_staff = staff.zzud_staff AND
  clients.zzud_client = link_group.zrud_client AND
  groups.zzud_group = link_group.zrud_group AND
  clients.date_intake BETWEEN (now() - '8 days'::interval)::timestamp AND now()
ORDER BY
  groups.name ASC,
  clients.client_id ASC,    
  staff.staff_name_cs ASC

我得到121个条目

如果我发表评论:

SELECT
 clients.name_lastfirst_cs, 
  to_char (clients.date_intake,'MM/DD/YY')AS Date_Created,
  clients.client_id, 
  clients.display_intake, 
  -- staff.staff_name_cs,  -- Line Commented out
  groups.name
FROM 
  public.clients, 
  public.groups, 
  public.staff, 
  public.link_group
WHERE 
  --  clients.zrud_staff = staff.zzud_staff AND --Line commented out
  clients.zzud_client = link_group.zrud_client AND
  groups.zzud_group = link_group.zrud_group AND
  clients.date_intake BETWEEN (now() - '8 days'::interval)::timestamp AND now()
ORDER BY
  groups.name ASC,
  clients.client_id ASC,    
  staff.staff_name_cs ASC

我得到173个条目

我知道我需要做一个外部联接来捕获所有客户端,无论是否存在   是指派的工作人员,但每次尝试都失败了。我已经完成了外连接   两张桌子,但加上三分之一已经扭曲了我的大脑。

感谢您的任何建议

1 个答案:

答案 0 :(得分:1)

我无法对此进行测试(或知道它是正确的),但我在您的查询中读到的是您想要类似于此的内容:

SELECT --I just used short aliases. I choose something other than the table name so I know it is an alias "c" for client etc...
  c.name_lastfirst_cs, 
  to_char (c.date_intake,'MM/DD/YY')AS Date_Created,
  c.client_id, 
  c.display_intake, 
  s.staff_name_cs, 
  g.name,
  l.zrud_client AS "link_client",--I'm selecting some data here so that I can debug later, you can just filter this out with another select if you need to
  l.zzud_group AS "link_group" --Again, so I can see these relationships
FROM 
  public.clients c 
  LEFT OUTER JOIN staff s ON --is staff required? If it isn't then outer join (optional)
    s.zzud_staff = c.zrud_staff --so we linked staff to clients here
  LEFT OUTER JOIN public.link_group l ON --this looks like a lookup table to me so we select the lookup record
    l.zrud_client = c.zzud_client -- this is how I define the lookup, a client id
  LEFT OUTER JOIN public.groups g ON --then we use that to lookup a group
    g.zzup_group = l.zrud_group --which is defined by this data here
WHERE -- the following must be true
  c.date_intake BETWEEN (now() - '8 days'::interval)::timestamp AND now()

现在为什么:我基本上将你的where子句移动到JOIN x ON y=z语法。根据我的经验,这是编写维护查询的更好方法,因为它允许您指定表之间的关系,而不是执行大型连接并尝试使用where子句过滤该数据。请记住,每个条件都是必需的,而不是可选的,所以当你说你想要具有以下条件的记录时,你就会得到它们(如果我读得正确的话 - 我可能不会因为我没有架构我的前面)如果记录缺少链接表记录或工作人员你要过滤掉它。

或者(可能明显更慢)你可以选择任何东西,这样你就可以把它链接起来:

SELECT 
  *
FROM
 (
   SELECT 
     *
   FROM 
     public.clients 
   WHERE
     x condition
  )
WHERE
  y condition

OR

SELECT * FROM x WHERE x.condition IN (SELECT * FROM y)

在您的情况下,这种策略可能不会比标准的连接语法更容易。

^这里有一些认真的意见:我建议你使用我在上面概述的连接语法。它在功能上与连接和指定where子句相同,但正如您所指出的,如果您不理解它们可能导致笛卡尔连接的关系。 http://www.tutorialspoint.com/sql/sql-cartesian-joins.htm。最后,我倾向于指定我想要的连接类型。我在查询中写了很多INNER JOINOUTER JOIN因为它有助于下一个人(通常是我)弄清楚我的意思。如果是可选的,则使用外部联接,如果需要,则使用内部联接(默认)。

祝你好运!那里有更好的SQL开发人员,可能还有另一种方法可以做到。