简体   繁体   English

如何执行以下 SQL(或 PL/SQL)查询

[英]How do I perform the following SQL (or PL/SQL) Query

If facing the following requirement: The user needs a table where he can see an employeeID, employeeName and the days where employees weren't working.如果面临以下要求:用户需要一个表,在该表中他可以看到员工 ID、员工姓名和员工不工作的天数。 The raw data is stored in the following tables:原始数据存储在下表中:

Employee: Emp_ID, Emp_Name

WorkDays: Emp_ID, Date

The process is that everytime an employee has worked, his ID and the date of the day is inserted into the WorkDays table.该过程是每当员工工作时,他的 ID 和当天的日期都会插入 WorkDays 表中。

Now I need a SQL or PL/SQL Query where I choose a date range (fe between 2021-10-01 and 2021-11.01) and for every employee who hasn't worked on at least 1 day during that time (meaning there is a row "missing" in the WorkDays table for a particular ID and Date), he is displayed in one row with the dates he hasn't worked.现在我需要一个 SQL 或 PL/SQL 查询,在其中我选择一个日期范围(fe 介于 2021 年 10 月 1 日和 2021 年 11 月 1 日之间)以及在此期间至少有 1 天没有工作的每个员工(意味着有WorkDays 表中“缺少”特定 ID 和日期的一行),他将显示在一行中,其中包含他没有工作的日期。 The dates are all in one column of the row, fe seperated by commas.日期都在一行的一列中,fe 用逗号分隔。

For better understanding, if there are two employees who haven't worked during that time the final table should look something like this:为了更好地理解,如果有两名员工在那段时间没有工作,那么决赛桌应该是这样的:

Emp_ID | Emp_Name |             Hasn't Worked               |
1      | John     |      2021-10-01, 2021-10-03, 2021-10-06 |
3      | Mary     |      2021-10-02, 2021-10-03             |

I don't want my code to get done for me but instead get help with the problem of querying a table where i have to loop trough the data and display multiple results (the dates) in one corresponding row.我不希望我的代码为我完成,而是在查询表的问题上获得帮助,在该表中我必须循环遍历数据并在相应的行中显示多个结果(日期)。

Thanks a lot for help!非常感谢您的帮助! Jack杰克

Use a row generator to create a calendar and then use a PARTITION OUTER JOIN and find the non-matched rows and then aggregate:使用行生成器创建日历,然后使用PARTITION OUTER JOIN并找到不匹配的行,然后聚合:

WITH calendar (day) AS (
  SELECT DATE '2021-10-01' FROM DUAL
UNION ALL
  SELECT day + 1 FROM calendar WHERE day < DATE '2021-11-01'
)
SELECT w.emp_id,
       MAX(emp_name) AS emp_name,
       LISTAGG(TO_CHAR(c.day, 'YYYY-MM-DD'), ', ') WITHIN GROUP (ORDER BY c.day)
         AS non_work_days
FROM   calendar c
       LEFT OUTER JOIN workdays w
       PARTITION BY (w.emp_id)
       ON (c.day = w."DATE")
       LEFT OUTER JOIN employee e
       ON (w.emp_id = e.emp_id)
WHERE  w."DATE" IS NULL
GROUP BY w.emp_id;

or you can use CROSS JOIN :或者您可以使用CROSS JOIN

WITH calendar (day) AS (
  SELECT DATE '2021-10-01' FROM DUAL
UNION ALL
  SELECT day + 1 FROM calendar WHERE day < DATE '2021-11-01'
)
SELECT e.emp_id,
       MAX(e.emp_name) AS emp_name,
       LISTAGG(TO_CHAR(c.day, 'YYYY-MM-DD'), ', ') WITHIN GROUP (ORDER BY c.day)
         AS non_work_days
FROM   calendar c
       CROSS JOIN employee e
       LEFT OUTER JOIN workdays w
       ON (c.day = w."DATE" AND e.emp_id = w.emp_id)
WHERE  w."DATE" IS NULL
GROUP BY e.emp_id;

Which, for the sample data:其中,对于样本数据:

CREATE TABLE Employee (Emp_ID, Emp_Name) AS
SELECT 1, 'Alice' FROM DUAL UNION ALL
SELECT 2, 'Beryl' FROM DUAL;

CREATE TABLE WorkDays (Emp_ID, "DATE") AS
WITH calendar (dt) AS (
  SELECT DATE '2021-10-01' + LEVEL - 1 FROM DUAL CONNECT BY LEVEL <= 32
)
SELECT 1, dt FROM calendar WHERE dt NOT IN (DATE '2021-10-01', DATE '2021-10-03', DATE '2021-10-06')
UNION ALL
SELECT 2, dt FROM calendar WHERE dt NOT IN (DATE '2021-10-02', DATE '2021-10-03')

Both output: output:

EMP_ID EMP_ID EMP_NAME EMP_NAME NON_WORK_DAYS NON_WORK_DAYS
1 1 Alice爱丽丝 2021-10-01, 2021-10-03, 2021-10-06 2021-10-01, 2021-10-03, 2021-10-06
2 2 Beryl绿柱石 2021-10-02, 2021-10-03 2021-10-02, 2021-10-03

db<>fiddle here db<> 在这里摆弄

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

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