当连接表中没有条目

时间:2017-02-13 18:33:09

标签: sql sql-server tsql case where-clause

我有一个问题,我正试图从一个人的时间段拉出时间表。如果他们有一个条目,我会得到一个他们的名字和时间表状态的行。但是如果他们在一段时间内没有提交两个时间表中的任何一个,那么他们根本不会出现在查询中(这意味着当有人跟随他们时他们会被错过)。

这是一个简单的示例查询,它不返回任何内容,因为resource_id在period_end_date中没有大于where子句限制的数据:

SELECT time_status_id, last_name
FROM dbo.wh_resource
LEFT JOIN wh_time_report ON wh_time_report.creator_resource_id = wh_resource.resource_id
WHERE wh_resource.resource_id = '31100670'
AND period_end_date >= '2017-01-29'
ORDER BY last_name

我发现将它(period_end_date >= '2017-01-29' OR period_end_date IS NULL)设置为不可行,因为它们过去已输入数据(如果它们从未有过,则会将它们拉出来)。

如果由于period_end_date没有找到数据,有没有办法放一个简单的0?我在看CASE WHERE但没有成功到达任何地方。

如果他们没有比搜索到的更新的条目,我宁愿得到一个0的time_status_id和该人的姓名。这可能相当简单吗?

我正在寻求简化调用,但最糟糕的是我可以提取所有姓氏,然后提取所有时间表状态,然后查找不存在的任何条目。以下工作做得很好(但没有提交任何时间表的人失踪)

SELECT wh_resource.resource_id, last_name, first_name, narrative_full_name, department_name,
ISNULL(MAX(CASE WHEN wh_time_report.period_end_date = '2017-02-04' THEN time_status_id END),0) as timesheet_status1,
SUM(CASE WHEN date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN ROUND(wh_time_subitem.hours_worked,2) END) as hours_total1,
SUM(CASE WHEN date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN wh_time_subitem.hours_worked END) as hours_total_old1, 
SUM(CASE WHEN allocation_code_id = '91207' AND date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN wh_time_subitem.hours_worked END) as sick_leave1,
SUM(CASE WHEN allocation_code_id = '91206' AND date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN wh_time_subitem.hours_worked END) as vacation1, 
SUM(CASE WHEN allocation_code_id = '91209' AND date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN wh_time_subitem.hours_worked END) as personal_leave1,
SUM(CASE WHEN allocation_code_id = '91208' AND date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN wh_time_subitem.hours_worked END) as holiday1,
SUM(CASE WHEN allocation_code_id = '30091631' AND date_worked >= '2017-01-29' AND date_worked <= '2017-02-04' THEN wh_time_subitem.hours_worked END) as funeral_leave1, 
ISNULL(MAX(CASE WHEN wh_time_report.period_end_date = '2017-02-11' THEN time_status_id END),0) as timesheet_status2,
SUM(CASE WHEN date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN ROUND(wh_time_subitem.hours_worked,2) END) as hours_total2,
SUM(CASE WHEN date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN wh_time_subitem.hours_worked END) as hours_total_old2, 
SUM(CASE WHEN allocation_code_id = '91207' AND date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN wh_time_subitem.hours_worked END) as sick_leave2,
SUM(CASE WHEN allocation_code_id = '91206' AND date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN wh_time_subitem.hours_worked END) as vacation2, 
SUM(CASE WHEN allocation_code_id = '91209' AND date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN wh_time_subitem.hours_worked END) as personal_leave2,
SUM(CASE WHEN allocation_code_id = '91208' AND date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN wh_time_subitem.hours_worked END) as holiday2,
SUM(CASE WHEN allocation_code_id = '30091631' AND date_worked >= '2017-02-05' AND date_worked <= '2017-02-11' THEN wh_time_subitem.hours_worked END) as funeral_leave2
FROM dbo.wh_resource
JOIN dbo.wh_department_resource ON wh_resource.resource_id = wh_department_resource.resource_id 
JOIN dbo.wh_department ON wh_department_resource.department_id = wh_department.department_id
LEFT JOIN wh_time_item ON wh_time_item.user_id =  wh_resource.resource_id
LEFT JOIN wh_time_subitem ON wh_time_subitem.time_item_id = wh_time_item.time_item_id
LEFT JOIN wh_time_report ON wh_time_report.creator_resource_id = wh_department_resource.resource_id 
WHERE wh_department_resource.is_default_department = 1 
AND wh_resource.is_active = 1 
AND last_name != 'API.User' 
AND wh_department.department_id = '30091606'
AND department_name NOT IN ('Sales', 'Marketing', 'Operations', '') 
AND (wh_time_report.period_end_date IN ('2017-02-04', '2017-02-11') OR wh_time_report.period_end_date IS NULL)
GROUP BY wh_resource.resource_id, last_name, first_name, narrative_full_name, hire_date, department_name
ORDER BY last_name

一个查询返回73个结果,并且有76个人,所以如果我做了一个查询来拉人

SELECT * FROM dbo.wh_resource 
JOIN wh_department_resource ON wh_resource.resource_id = wh_department_resource.resource_id
WHERE wh_resource.is_active = 1
AND department_id = '30091606' 
AND is_default_department ='1'
ORDER BY last_name, first_name

我可以通过检查名称是否存在来获取PHP中两个查询所需的所有数据。但我宁愿在一个查询中得到它!

编辑: 使用SqlZim的推送,我有以下查询适合我。它可能很乱,但它运行得很快(比这个更换的1000个查询要快得多,不是开玩笑)。日期将通过PHP提供,如果需要,也将提供部门ID。

SELECT wh_resource.resource_id, last_name, first_name, narrative_full_name, department_name,
ISNULL(MAX(CASE WHEN T1.period_end_date = '2017-02-04' THEN T1.time_status_id END),0) as timesheet_status1,
SUM(CASE WHEN S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN ROUND(S1.hours_worked,2) END) as hours_total1,
SUM(CASE WHEN S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN S1.hours_worked END) as hours_total_old1, 
SUM(CASE WHEN S1.allocation_code_id = '91207' AND S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN S1.hours_worked END) as sick_leave1,
SUM(CASE WHEN S1.allocation_code_id = '91206' AND S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN S1.hours_worked END) as vacation1, 
SUM(CASE WHEN S1.allocation_code_id = '91209' AND S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN S1.hours_worked END) as personal_leave1,
SUM(CASE WHEN S1.allocation_code_id = '91208' AND S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN S1.hours_worked END) as holiday1,
SUM(CASE WHEN S1.allocation_code_id = '30091631' AND S1.date_worked >= '2017-01-29' AND S1.date_worked <= '2017-02-04' THEN S1.hours_worked END) as funeral_leave1, 
ISNULL(MAX(CASE WHEN T2.period_end_date = '2017-02-11' THEN T2.time_status_id END),0) as timesheet_status2,
SUM(CASE WHEN S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN ROUND(S2.hours_worked,2) END) as hours_total2,
SUM(CASE WHEN S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN S2.hours_worked END) as hours_total_old2, 
SUM(CASE WHEN S2.allocation_code_id = '91207' AND S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN S2.hours_worked END) as sick_leave2,
SUM(CASE WHEN S2.allocation_code_id = '91206' AND S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN S2.hours_worked END) as vacation2, 
SUM(CASE WHEN S2.allocation_code_id = '91209' AND S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN S2.hours_worked END) as personal_leave2,
SUM(CASE WHEN S2.allocation_code_id = '91208' AND S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN S2.hours_worked END) as holiday2,
SUM(CASE WHEN S2.allocation_code_id = '30091631' AND S2.date_worked >= '2017-02-05' AND S2.date_worked <= '2017-02-11' THEN S2.hours_worked END) as funeral_leave2
FROM dbo.wh_resource
JOIN dbo.wh_department_resource ON wh_resource.resource_id = wh_department_resource.resource_id 
JOIN dbo.wh_department ON wh_department_resource.department_id = wh_department.department_id
LEFT JOIN wh_time_item ON wh_time_item.user_id =  wh_resource.resource_id
LEFT JOIN wh_time_report T1 ON T1.creator_resource_id = wh_resource.resource_id AND T1.period_end_date = '2017-02-04'
LEFT JOIN wh_time_subitem S1 ON S1.time_item_id = wh_time_item.time_item_id AND S1.date_worked >= '2017-01-29' AND S1.date_worked < '2017-02-05'
LEFT JOIN wh_time_report T2 ON T2.creator_resource_id = wh_resource.resource_id AND T2.period_end_date = '2017-02-11'
LEFT JOIN wh_time_subitem S2 ON S2.time_item_id = wh_time_item.time_item_id AND S2.date_worked >= '2017-02-05' AND S2.date_worked < '2017-02-12'
WHERE wh_department_resource.is_default_department = 1 
AND wh_resource.is_active = 1 
AND last_name != 'API.User' 
AND wh_department.department_id = '30091606'
AND department_name NOT IN ('Sales', 'Marketing', 'Operations', '') 
GROUP BY wh_resource.resource_id, last_name, first_name, narrative_full_name, hire_date, department_name
ORDER BY last_name

3 个答案:

答案 0 :(得分:1)

如果您在outer join中引用where表的列(在本例中为左侧)而不允许null,则您将删除行。

如果您将where条件移至加入条件,则可以使用null和/或select处理isnull()中的coalesce()

对于您的查询,看起来像这样:

select 
    wr.resource_id
  , last_name
  , first_name
  , narrative_full_name
  , department_name
  , timesheet_status1 = isnull(max(case when wtr.period_end_date = '2017-02-04' then time_status_id end),0)
  , hours_total1      = sum(case when date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then round(wts.hours_worked,2) end)
  , hours_total_old1  = sum(case when date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then wts.hours_worked end)
  , sick_leave1       = sum(case when allocation_code_id = '91207'    and date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then wts.hours_worked end)
  , vacation1         = sum(case when allocation_code_id = '91206'    and date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then wts.hours_worked end)
  , personal_leave1   = sum(case when allocation_code_id = '91209'    and date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then wts.hours_worked end)
  , holiday1          = sum(case when allocation_code_id = '91208'    and date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then wts.hours_worked end)
  , funeral_leave1    = sum(case when allocation_code_id = '30091631' and date_worked >= '2017-01-29' and date_worked <= '2017-02-04' then wts.hours_worked end)
  , timesheet_status2 = isnull(max(case when wtr.period_end_date = '2017-02-11' then time_status_id end),0)
  , hours_total2      = sum(case when date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then round(wts.hours_worked,2) end)
  , hours_total_old2  = sum(case when date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then wts.hours_worked end)
  , sick_leave2       = sum(case when allocation_code_id = '91207'    and date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then wts.hours_worked end)
  , vacation2         = sum(case when allocation_code_id = '91206'    and date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then wts.hours_worked end)
  , personal_leave2   = sum(case when allocation_code_id = '91209'    and date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then wts.hours_worked end)
  , holiday2          = sum(case when allocation_code_id = '91208'    and date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then wts.hours_worked end)
  , funeral_leave2    = sum(case when allocation_code_id = '30091631' and date_worked >= '2017-02-05' and date_worked <= '2017-02-11' then wts.hours_worked end) 
from dbo.wh_resource as wr
  inner join dbo.wh_department_resource as wdr 
     on wr.resource_id = wdr.resource_id
    and wr.is_active = 1
    and wr.last_name != 'api.user'
    and wdr.is_default_department = 1
  inner join dbo.wh_department as wd 
     on wdr.department_id = wd.department_id
    and wd.department_id = '30091606'
    and department_name not in ('sales', 'marketing', 'operations', '')
  left join wh_time_item as wti 
     on wti.user_id =  wr.resource_id
  left join wh_time_subitem as wts 
     on wts.time_item_id = wti.time_item_id
  left join wh_time_report as wtr 
     on wtr.creator_resource_id = wdr.resource_id
    and wtr.period_end_date in ('2017-02-04', '2017-02-11') 
group by wr.resource_id, last_name, first_name, narrative_full_name, hire_date, department_name
order by last_name

答案 1 :(得分:0)

因为你没有为period_end_date提供表格而time_status_id不确定
但试试这个

SELECT time_status_id, last_name
FROM dbo.wh_resource
LEFT JOIN wh_time_report 
       ON wh_time_report.creator_resource_id = wh_resource.resource_id
      AND period_end_date >= '2017-01-29'
WHERE wh_resource.resource_id = '31100670'

ORDER BY last_name

答案 2 :(得分:0)

请原谅,但我没有足够的时间来操作您提供的完整查询。 您可以尝试 OUTER APPLY 来获得所需的结果 - 如果表中没有匹配cirteria的记录,则大小写为零。简短的例子,如何做到这一点:

SELECT 
     [time_status_id] = a.time_status_id
    ,[last_name] = a.last_name
    ,[count] = isnull(b.cnt, 0)
FROM 
    dbo.wh_resource as a
outer apply
    (
        select
            cnt = count(*)
        from
            wh_time_report
        where
             creator_resource_id = a.resource_id             
    ) as b     
WHERE a.resource_id = '31100670'
AND a.period_end_date >= '2017-01-29'
ORDER BY a.last_name