简体   繁体   English

同一表上的LEFT OUTER JOIN返回0条记录

[英]LEFT OUTER JOIN on same table returns 0 records

I already searched on other posts for my problem but nothing worked. 我已经在其他帖子上搜索了我的问题,但没有任何效果。

I have a table with customers and turnover forecasts data for restaurants, both planned and realized values are in the same table (had to keep it that way from the previous DB). 我有一个包含客户的表和餐厅的营业额预测数据,计划值和已实现值都在同一表中(必须与以前的数据库保持一致)。

I need to get planned forecasts and realized forecasts of the last year for a specific restaurant (site) and a specific activity (restaurant, take away, click n collect) and for a range of date (usually a full month). 我需要获得特定餐厅(站点)和特定活动(餐厅,外卖店,单击“ n收集”)以及日期范围(通常是一个月)的过去一年的计划的预测和已实现的预测。

My issue is when the planned forecasts are non-existing and the last year realized exists, the request returns nothing. 我的问题是,当计划的预测不存在并且实现的最后一年存在时,请求什么也不会返回。

Here's my request : 这是我的要求:

SELECT 
    P.AFO_ACTIVITY_ID,
    P.AFO_SITE_ID,
    P.AFO_FORECAST_DATE,
    P.AFO_SERVICE_ID,
    P.AFO_PLANNED_CUSTOMERS,
    P.AFO_REALIZED_CUSTOMERS,
    P.AFO_GROUP_CUSTOMERS,
    P.AFO_PLANNED_TURNOVER,
    P.AFO_REALIZED_TURNOVER,
    P.AFO_GROUP_TURNOVER,
    P.AFO_NB_EMPLOYEES,
    P.AFO_TURNOVER_EMPLOYEES,
    P.AFO_ID,
    p2.AFO_REALIZED_CUSTOMERS AS REAL_CUSTOMERS_PREVIOUS_YEAR,
    p2.AFO_REALIZED_TURNOVER  AS REAL_TURNOVER_PREVIOUS_YEAR
FROM 
    ACT_FORECAST P
LEFT OUTER JOIN 
    act_forecast p2 ON p2.AFO_FORECAST_DATE = p.AFO_FORECAST_DATE - 364
                    AND p2.AFO_SITE_ID = p.AFO_SITE_ID
                    AND p2.AFO_ACTIVITY_ID = p.AFO_ACTIVITY_ID
                    AND p2.AFO_SERVICE_ID = p.AFO_SERVICE_ID
WHERE 
    P.AFO_SITE_ID = :siteid
    AND P.AFO_ACTIVITY_ID = :activityid
    AND P.AFO_FORECAST_DATE BETWEEN :startdate AND :enddate

If I play the request for February 2018 I have my data (2018 and 2017). 如果我播放2018年2月的请求,我将有我的数据(2018年和2017年)。

But if I play it for February 2019 I have nothing, it's ok for the planned part of the year because the forecast is not done yet but for the previous year part, I should have some data. 但是,如果我在2019年2月播放它,则一无所有,这对于该年的计划部分是可以的,因为尚未完成预测,但对于上一年的部分,我应该有一些数据。

I tried with RIGHT OUTER JOIN too but nothing cames out. 我也尝试过RIGHT OUTER JOIN,但没有任何结果。

Sample Data : 样本数据 :

ActivityId SiteId ForecastDate ServiceId PlannedCustomers RealizedCustomers GroupCustomers PlannedTurnover RealizedTurnover GroupTurnover NbEmployeeMeal TurnoverEmployeeMeal ID      RealizedCustomersPreviousYear RealizedTurnoverPreviousYear
1          58     01/02/18     1         0                0                 0              0               11               0             0              11                   2953773 0                             39,85
1          58     01/02/18     3         345              398               0              3467,25         4052,01          0             0              0                    2953774 328                           3291,53
1          58     01/02/18     5         10               16                0              140             194,04           0             16             60,9                 2953775 7                             91,12
1          58     01/02/18     7         125              151               0              1200            1413,93          0             0              0                    2953776 112                           1063,89

Any ideas? 有任何想法吗?

Regards 问候

Your where clause is only find records in P in the range you specify. 您的where子句仅在您指定范围内的P中查找记录。 If there none, there are no source rows to left outer join from . 如果没有,有没有源行至左外连接。

You could generate all possible dates in the period you are looking at, via an inline view or a CTE, and then look for records matching either sets of dates: 您可以通过内联视图或CTE生成您正在查看的时段内的所有可能日期,然后查找与任一日期集匹配的记录:

WITH CTE (this_year, last_year) AS (
  SELECT :startdate + level - 1, :startdate + level - 365
  FROM dual
  CONNECT BY level <= :enddate - :startdate + 1
)
SELECT 
    :activityid AS AFO_ACTIVITY_ID,
    :siteid AS AFO_SITE_ID,
    CTE.this_year AS AFO_FORECAST_DATE,
    P.AFO_SERVICE_ID,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_PLANNED_CUSTOMERS END) AS AFO_PLANNED_CUSTOMERS,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_REALIZED_CUSTOMERS END) AS AFO_REALIZED_CUSTOMERS,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_GROUP_CUSTOMERS END) AS AFO_GROUP_CUSTOMERS,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_PLANNED_TURNOVER END) AS AFO_PLANNED_TURNOVER,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_REALIZED_TURNOVER END) AS AFO_REALIZED_TURNOVER,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_GROUP_TURNOVER END) AS AFO_GROUP_TURNOVER,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_NB_EMPLOYEES END) AS AFO_NB_EMPLOYEES,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_TURNOVER_EMPLOYEES END) AS AFO_TURNOVER_EMPLOYEES,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = this_year
      THEN P.AFO_ID END) AS AFO_ID,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = last_year
      THEN P.AFO_REALIZED_CUSTOMERS END) AS REAL_CUSTOMERS_PREVIOUS_YEAR,
    MAX(CASE WHEN P.AFO_FORECAST_DATE = last_year
      THEN P.AFO_REALIZED_TURNOVER END) AS REAL_TURNOVER_PREVIOUS_YEAR
FROM
    CTE
JOIN
    ACT_FORECAST P
ON
    P.AFO_FORECAST_DATE = CTE.this_year
OR
    P.AFO_FORECAST_DATE = CTE.last_year
WHERE 
    P.AFO_SITE_ID = :siteid
    AND P.AFO_ACTIVITY_ID = :activityid
GROUP BY
    :activityid,
    :siteid,
    CTE.this_year,
    P.AFO_SERVICE_ID;

Rather than attempting to outer join (either way) it looks for the specific dates in both years, and does a kind of manual pivot to show the value from the relevant year in the right column. 与其尝试外部联接(无论哪种方式),它都不是寻找两年中的特定日期,而是进行一种手动枢纽操作,以在右侧栏中显示相关年份的价值。 Notice the last two column expression use last_year , while the rest use this_year (except the ones being grouped on). 注意最后两列的表达式使用last_year ,其余的使用this_year (分组的除外)。

For SERVICE_ID you might want to coalesce to pick up last years value if there isn't one for this year. 对于SERVICE_ID ,如果今年没有值,则可能希望合并以获取上一年的值。 You could also coalesce the others to zero if you don't want to see nulls. 如果不想看到空值,也可以将其他值合并为零。


If you don't want to use a WITH clause then you can use an inline view instead: 如果您不想使用WITH子句,则可以使用内联视图:

SELECT
...
FROM
    (
        SELECT :startdate + level - 1 AS this_year,
               :startdate + level - 365 AS last_year
        FROM dual
        CONNECT BY level <= :enddate - :startdate + 1
    ) CTE
JOIN
    ACT_FORECAST P
...

though you might want a more descriptive name than CTE (with either version...) 尽管您可能想要一个比CTE更具描述性的名称(使用任一版本...)


With your sample data reworked as a CTE, with nulls for the values not shown in the question: 将样本数据重新整理为CTE后,问题中未显示的值将为空:

with act_forecast (afo_activity_id, afo_site_id, afo_forecast_date, afo_service_id,
  afo_planned_customers, afo_realized_customers, afo_group_customers,
  afo_planned_turnover, afo_realized_turnover, afo_group_turnover,
  afo_nb_employees, afo_turnover_employees, afo_id)
as (
            select 1, 58, date '2018-02-01', 1, 0, 0, 0, 0, 11, 0, 0, 11, 2953773 from dual
  union all select 1, 58, date '2017-02-02', 1, null, 0, null, null, 39.85, null, null, null, null from dual
  union all select 1, 58, date '2018-02-01', 3, 345, 398, 0, 3467.25, 4052.01, 0, 0, 0, 2953774 from dual
  union all select 1, 58, date '2017-02-02', 3, null, 328, null, null, 3291.53, null, null, null, null from dual
  union all select 1, 58, date '2018-02-01', 5, 10, 16, 0, 140, 194.04, 0, 16, 60.9, 2953775 from dual
  union all select 1, 58, date '2017-02-02', 5, null, 7, null, null, 91.12, null, null, null, null from dual
  union all select 1, 58, date '2018-02-01', 7, 125, 151, 0, 1200, 1413.93, 0, 0, 0, 2953776 from dual
  union all select 1, 58, date '2017-02-02', 7, null, 112, null, null, 1063.89, null, null, null, null from dual
)

then with a range in 2018 that gives: 然后在2018年给出的范围是:

AFO_ACTIVITY_ID AFO_SITE_ID AFO_FORECA AFO_SERVICE_ID AFO_PLANNED_CUSTOMERS AFO_REALIZED_CUSTOMERS AFO_GROUP_CUSTOMERS AFO_PLANNED_TURNOVER AFO_REALIZED_TURNOVER AFO_GROUP_TURNOVER AFO_NB_EMPLOYEES AFO_TURNOVER_EMPLOYEES     AFO_ID REAL_CUSTOMERS_PREVIOUS_YEAR REAL_TURNOVER_PREVIOUS_YEAR
--------------- ----------- ---------- -------------- --------------------- ---------------------- ------------------- -------------------- --------------------- ------------------ ---------------- ---------------------- ---------- ---------------------------- ---------------------------
              1          58 2018-02-01              3                   345                    398                   0              3467.25               4052.01                  0                0                      0    2953774                          328                     3291.53
              1          58 2018-02-01              7                   125                    151                   0                 1200               1413.93                  0                0                      0    2953776                          112                     1063.89
              1          58 2018-02-01              1                     0                      0                   0                    0                    11                  0                0                     11    2953773                            0                       39.85
              1          58 2018-02-01              5                    10                     16                   0                  140                194.04                  0               16                   60.9    2953775                            7                       91.12

and with a range in 2019 that gives: 并在2019年实现以下目标:

AFO_ACTIVITY_ID AFO_SITE_ID AFO_FORECA AFO_SERVICE_ID AFO_PLANNED_CUSTOMERS AFO_REALIZED_CUSTOMERS AFO_GROUP_CUSTOMERS AFO_PLANNED_TURNOVER AFO_REALIZED_TURNOVER AFO_GROUP_TURNOVER AFO_NB_EMPLOYEES AFO_TURNOVER_EMPLOYEES     AFO_ID REAL_CUSTOMERS_PREVIOUS_YEAR REAL_TURNOVER_PREVIOUS_YEAR
--------------- ----------- ---------- -------------- --------------------- ---------------------- ------------------- -------------------- --------------------- ------------------ ---------------- ---------------------- ---------- ---------------------------- ---------------------------
              1          58 2019-01-31              3                                                                                                                                                                                                            398                     4052.01
              1          58 2019-01-31              5                                                                                                                                                                                                             16                      194.04
              1          58 2019-01-31              1                                                                                                                                                                                                              0                          11
              1          58 2019-01-31              7                                                                                                                                                                                                            151                     1413.93

If I understand correctly, you can use a FULL OUTER JOIN : 如果我理解正确,则可以使用FULL OUTER JOIN

SELECT 
    COALESCE(P.AFO_ACTIVITY_ID, P2.AFO_ACTIVITY_ID) as AFO_ACTIVITY_ID,
    COALESCE(P.AFO_SITE_ID, P2.AFO_SITE_ID) as AFO_SITE_ID, 
    P.AFO_FORECAST_DATE,
    P.AFO_SERVICE_ID,
    P.AFO_PLANNED_CUSTOMERS,
    P.AFO_REALIZED_CUSTOMERS,
    P.AFO_GROUP_CUSTOMERS,
    P.AFO_PLANNED_TURNOVER,
    P.AFO_REALIZED_TURNOVER,
    P.AFO_GROUP_TURNOVER,
    P.AFO_NB_EMPLOYEES,
    P.AFO_TURNOVER_EMPLOYEES,
    P.AFO_ID,
    p2.AFO_REALIZED_CUSTOMERS AS REAL_CUSTOMERS_PREVIOUS_YEAR,
    p2.AFO_REALIZED_TURNOVER  AS REAL_TURNOVER_PREVIOUS_YEAR
FROM (SELECT P.*
      FROM ACT_FORECAST P
      WHERE P.AFO_SITE_ID = :siteid AND
            P.AFO_ACTIVITY_ID = :activityid AND
            P.AFO_FORECAST_DATE BETWEEN :startdate AND :enddate
     ) P FULL JOIN
     (SELECT p2.*
      FROM act_forecast p2
      WHERE P2.AFO_SITE_ID = :siteid AND
            P2.AFO_ACTIVITY_ID = :activityid AND
            P2.AFO_FORECAST_DATE BETWEEN :startdate - 364 AND :enddate - 364
     ) p2
     ON p2.AFO_FORECAST_DATE = p.AFO_FORECAST_DATE - 364 AND
        p2.AFO_SITE_ID = p.AFO_SITE_ID AND
        p2.AFO_ACTIVITY_ID = p.AFO_ACTIVITY_ID AND
        p2.AFO_SERVICE_ID = p.AFO_SERVICE_ID

I was astonished to see - 364 (my expertise might be less than yours) and expected: 我很惊讶地看到- 364 (我的专业知识可能少于您的专业知识),并期望:

p.AFO_FORECAST_DATE - INTERVAL 364 DAY

Maybe that was interpreted as (micro)seconds? 也许这被解释为(微)秒?

(The typical debugging is by leaving out a part of the conditions like on AFO_FORECAST_DATE.) (典型的调试是通过省略部分条件,例如在AFO_FORECAST_DATE。)

Use somthing Like this below: 像下面这样使用东西:

    SELECT P.AFO_ACTIVITY_ID,
    P.AFO_SITE_ID,
    P.AFO_FORECAST_DATE,
    P.AFO_SERVICE_ID,
    P.AFO_PLANNED_CUSTOMERS,
    P.AFO_REALIZED_CUSTOMERS,
    P.AFO_GROUP_CUSTOMERS,
    P.AFO_PLANNED_TURNOVER,
    P.AFO_REALIZED_TURNOVER,
    P.AFO_GROUP_TURNOVER,
    P.AFO_NB_EMPLOYEES,
    P.AFO_TURNOVER_EMPLOYEES,
    P.AFO_ID,
    p2.AFO_REALIZED_CUSTOMERS AS REAL_CUSTOMERS_PREVIOUS_YEAR,
    p2.AFO_REALIZED_TURNOVER  AS REAL_TURNOVER_PREVIOUS_YEAR
    FROM ACT_FORECAST P
    LEFT OUTER JOIN(SELECT DISTINCT p2.AFO_FORECAST_DATE 
        FROM ACT_FORECAST P2)
    ON p2.AFO_FORECAST_DATE = p.AFO_FORECAST_DATE - 364
                    AND p2.AFO_SITE_ID = p.AFO_SITE_ID
                    AND p2.AFO_ACTIVITY_ID = p.AFO_ACTIVITY_ID
                    AND p2.AFO_SERVICE_ID = p.AFO_SERVICE_ID
WHERE 
    P.AFO_SITE_ID = :siteid
    AND P.AFO_ACTIVITY_ID = :activityid
    AND P.AFO_FORECAST_DATE BETWEEN :startdate AND :enddate

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM