简体   繁体   中英

Return in only one table info from two tables into rows when info is in columns

In PostgreSQL I have 2 tables with fields:

  • Working_date: id (autonumeric), employee_code (varchar (6)), working_date (date), working_hour (time),
  • Attendance: id (autonumeric), employee_code (varchar (6)), attendance_date (date), attendance_hour (time),

Data example:

Working_date

ID  | employee_code | working_date | working_hour
1   | 12345         | 2015-07-09   | 08:00
2   | 12345         | 2015-07-09   | 13:00
3   | 12345         | 2015-07-09   | 14:00
4   | 12345         | 2015-07-09   | 17:00
5   | 12345         | 2015-07-10   | 08:00
6   | 12345         | 2015-07-10   | 13:00
7   | 12345         | 2015-07-10   | 14:00
8   | 12345         | 2015-07-10   | 17:00
9   | 12345         | 2015-07-11   | 08:00
10  | 12345         | 2015-07-11   | 13:00
11  | 12345         | 2015-07-11   | 14:00
12  | 12345         | 2015-07-11   | 17:00
13  | 12345         | 2015-07-12   | 08:00
14  | 12345         | 2015-07-12   | 13:00
15  | 12345         | 2015-07-12   | 14:00
16  | 12345         | 2015-07-12   | 17:00
17  | 12345         | 2015-07-13   | 08:00
18  | 12345         | 2015-07-13   | 13:00
19  | 12345         | 2015-07-13   | 14:00
20  | 12345         | 2015-07-13   | 17:00

Attendance

ID  | employee_code | attendance_date | attendance_hour
1   | 12345         | 2015-07-09      | 07:56:53
2   | 12345         | 2015-07-09      | 10:33:31
3   | 12345         | 2015-07-09      | 13:00:42
4   | 12345         | 2015-07-09      | 13:00:47
5   | 12345         | 2015-07-09      | 13:30:21
6   | 12345         | 2015-07-09      | 17:00:01
7   | 12345         | 2015-07-10      | 07:48:35
8   | 12345         | 2015-07-10      | 12:15:20
9   | 12345         | 2015-07-10      | 13:58:42
10  | 12345         | 2015-07-10      | 17:02:00
11  | 12345         | 2015-07-11      | 08:06:46
12  | 12345         | 2015-07-11      | 12:00:01
13  | 12345         | 2015-07-11      | 13:52:01
14  | 12345         | 2015-07-11      | 17:05:08
15  | 12345         | 2015-07-12      | 07:55:02
16  | 12345         | 2015-07-12      | 12:03:22
17  | 12345         | 2015-07-12      | 13:37:40
18  | 12345         | 2015-07-12      | 17:05:01
19  | 12345         | 2015-07-13      | 07:54:25
20  | 12345         | 2015-07-13      | 10:44:15
21  | 12345         | 2015-07-13      | 13:59:21
22  | 12345         | 2015-07-13      | 17:01:17

In table "Attendance" there are some repetitive rows because employee entered attendance more than once. For example on 2015-07-09 there are 2 attendance times (13:00:42, 13:00:47) when it is time to go out for lunch. In this case, I should get only one of the two records.

The other case on 2015-07-09 there is 10:33:31. It is recorded when the employee asks permission to leave work and then returns in this case at 13:00:42 / 13:00:47.

Is there a way for getting working_date , working_hour with its respective attendance_hour in one table with only pure SQL queries (maybe some type of subqueries)?

Example:

ID  | employee_code | working_date | working_hour1 | attendance_time_1 | working_hour2 | attendance_time_2    | working_hour3 | attendance_time_3 | working_hour4 | attendance_time_4
1   | 12345         | 2015-07-09   | 08:00         | 07:56:53          | 13:00:00      | 13:00:42 or 13:00:47 | 14:00         | 13:30:21          | 17:00         | 17:00:01
2   | 12345         | 2015-07-10   | 08:00         | 07:48:35          | 13:00:00      | 12:15:20             | 14:00         | 13:58:42          | 17:00         | 17:02:00
3   | 12345         | 2015-07-11   | 08:00         | 08:06:46          | 13:00:00      | 12:00:01             | 14:00         | 13:52:01          | 17:00         | 17:05:08
4   | 12345         | 2015-07-12   | 08:00         | 07:55:02          | 13:00:00      | 12:03:22             | 14:00         | 13:37:40          | 17:00         | 17:05:01
5   | 12345         | 2015-07-13   | 08:00         | 07:54:25          | 13:00:00      | 10:44:15             | 14:00         | 13:59:21          | 17:00         | 17:01:17

In case it is not possible to get it with pure SQL querie, how can it achieved with maybe PL/PGSQL?

Currently I make it with PHP like this:

  • I query employee_code and working_date fields from working_date table. This query is run between 2 dates: from_date , to_date .
  • Inside a "for statement" I consult with every row of working_date all the working_hour rows: working_hour1 , working_hour2 , working_hour3 , working_hour4 . For every row is run an SQL query. For this query I send it employee_code and working_date parameters.
  • Inside a nested "for statement", with every working_hour , I run a query to "attendance_date" table with parameters: employee_code , working_date and working_hour . It returns the attendance_hour for every working_hour .

This way (calling SELECTS from PHP with nested "for statement") is too slow for getting and showing the info. I see the process when executing it and process takes 100% of CPU.

You can join those tables on their dates and aggregate the attendance times into an array by grouping by date and employee_code somewhat like this:

SELECT
w.employee_code, 
w.working_date,
array_agg(distinct(w.working_hour)) working_hours,
array_agg(distinct(a.attendance_hour)) attendance_hours
FROM Working_date w
LEFT JOIN attendance a
ON (w.working_date = a.attendance_date)
GROUP BY w.working_date, w.employee_code
ORDER BY w.working_date

You could use the unnest() function of postgres to unnest those arrays, but it will put them into new rows not columns. Putting them into separate columns is difficult because those arrays probably won't be the same length and all rows have to have the same columns.

Heres a fiddle http://sqlfiddle.com/#!15/2a75c/7/0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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