你好,我尝试将两行合并为一个机构的进出时间。这是我的查询
select
agency_name,
"IN",
out
from (
select
eofficeuat.entrylog_vehicle.agent_id,
eofficeuat.cnf_agents.agent_name,
eofficeuat.gatepass.agency_name,
eofficeuat.gatepass.agency_id,
TO_CHAR(eofficeuat.entrylog_vehicle.scantime, 'dd-mm-yyyy HH12:MI:SS PM') as Time,
eofficeuat.entrylog_vehicle.action as action,
eofficeuat.gatelist.shortname as gate,
eofficeuat.entrylog_vehicle.passnumber,
eofficeuat.entrylog_vehicle.cardnumber,
eofficeuat.gatepass.vehicletype,
eofficeuat.gatepass.ISSUEDATETIME,
row_number() over (
partition by agency_name, trunc(to_date(TO_CHAR(eofficeuat.entrylog_vehicle.scantime, 'dd-mm-yyyy HH12:MI:SS PM'), 'dd-mm-yyyy hh:mi:ss pm')), action order by eofficeuat.entrylog_vehicle.scantime) rn
FROM
eofficeuat.entrylog_vehicle
INNER JOIN eofficeuat.cnf_agents ON eofficeuat.entrylog_vehicle.agent_id = eofficeuat.cnf_agents.agent_id
INNER JOIN eofficeuat.gatelist ON eofficeuat.entrylog_vehicle.gate_id = eofficeuat.gatelist.id
INNER JOIN eofficeuat.gatepass ON eofficeuat.entrylog_vehicle.passnumber = eofficeuat.gatepass.id
WHERE
eofficeuat.entrylog_vehicle.passnumber = '10000920616'
and eofficeuat.entrylog_vehicle.scantime between TO_DATE ('03/10/2019', 'dd/mm/yyyy') and TO_DATE ('04/10/2019', 'dd/mm/yyyy')
)
pivot (max(time) for action in ('IN' as "IN", 'OUT' as "OUT"))
order by rn;
这是小提琴http://sqlfiddle.com/#!4/d465a/1 我想将两行合并为一列,该行的进出日期为03-10-2019日期,类似地为04-10-2019日期。那就是为什么我使用分析功能 。但这不会合并成一排。所以显示4行,但我想显示2行。你能帮我吗?
答案 0 :(得分:1)
您可以通过在表上使用透视图而不使用case表达式来更简单地执行此操作,例如:
select agency_name,
dt,
"IN",
out
from (select agency_name,
trunc(to_date(time, 'dd-mm-yyyy hh:mi:ss pm')) dt,
to_date(time, 'dd-mm-yyyy hh:mi:ss pm') time,
action,
row_number() over (partition by agency_name, trunc(to_date(time, 'dd-mm-yyyy hh:mi:ss pm')), action order by time) rn
from kvtest)
pivot (max(time) for action in ('IN' as "IN", 'OUT' as "OUT"))
order by rn;
还有here's the SQLFiddle支持此答案。
这可以通过查找日期,然后确定当天的第n行进出行来实现。然后,我们对数据进行透视,将rn作为要透视的列之一,这意味着,如果一天中有3来回的出入,那么您将在输出中得到3行。
如果您希望IN和OUT在几天内工作(例如,在午夜之前到达,在午夜之后离开),则将需要其他解决方案。我在回答中假设与IN对应的OUT将始终在同一天。
顺便说一句,为什么将您的TIME
列定义为VARCHAR2?这是存储日期或时间戳信息的不好的数据类型。我希望您的实际表确实是DATE
(或TIMESTAMP
)数据类型。如果不是,我强烈建议您考虑将数据类型更改为更合适的数据类型。
如果您只是想要每天最早的IN时间和最晚的OUT时间,则只需要一个条件聚合查询,例如:
select agency_name,
trunc(to_date(time, 'dd-mm-yyyy hh:mi:ss pm')) dt,
min(case when action = 'IN' then to_date(time, 'dd-mm-yyyy hh:mi:ss pm') end) "IN",
max(case when action = 'OUT' then to_date(time, 'dd-mm-yyyy hh:mi:ss pm') end) out
from kvtest
group by agency_name,
trunc(to_date(time, 'dd-mm-yyyy hh:mi:ss pm'));
答案 1 :(得分:1)
您可以简化很多操作,并使用TRUNC
代替ROW_NUMBER
:
Oracle设置:
不将日期存储为字符串;使用适当的数据类型,因此在这种情况下,DATE
:
create table kvtest ( agency_name, action, TIME ) AS
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-03' + INTERVAL '15:52:26' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-03' + INTERVAL '18:17:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-04' + INTERVAL '15:52:26' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-04' + INTERVAL '18:17:48' HOUR TO SECOND FROM DUAL;
查询:
SELECT agency_name,
"IN",
OUT
FROM (
SELECT T.*,
TRUNC( TIME ) AS day
FROM kvtest t
)
PIVOT ( MIN( time ) FOR action IN ( 'IN' AS "IN", 'OUT' AS "OUT" ) )
ORDER BY day;
输出:
| AGENCY_NAME | IN | OUT |
|-------------|----------------------|----------------------|
| ABC LIMITED | 2019-10-03T15:52:26Z | 2019-10-03T18:17:48Z |
| ABC LIMITED | 2019-10-04T15:52:26Z | 2019-10-04T18:17:48Z |
更新:
from comment:代理机构每天都会有很多次进出,所以我使用此案例来获得先进先出的时间
Oracle设置:
create table kvtest ( agency_name, action, TIME ) AS
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-03' + INTERVAL '15:52:26' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-03' + INTERVAL '18:17:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-03' + INTERVAL '18:52:26' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-03' + INTERVAL '19:17:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-04' + INTERVAL '15:52:26' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-04' + INTERVAL '18:17:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-05' + INTERVAL '23:17:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-06' + INTERVAL '00:17:48' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'IN', DATE '2019-10-06' + INTERVAL '09:00:00' HOUR TO SECOND FROM DUAL UNION ALL
SELECT 'ABC LIMITED', 'OUT', DATE '2019-10-06' + INTERVAL '15:00:00' HOUR TO SECOND FROM DUAL;
查询:
SELECT agency_name,
MIN( CASE action WHEN 'IN' THEN TIME END ) AS "IN",
MAX( CASE action WHEN 'OUT' THEN TIME END ) AS OUT
FROM kvtest
GROUP BY agency_name, TRUNC( TIME )
ORDER BY agency_name, TRUNC( TIME );
输出:
| AGENCY_NAME | IN | OUT |
|-------------|----------------------|----------------------|
| ABC LIMITED | 2019-10-03T15:52:26Z | 2019-10-03T19:17:48Z |
| ABC LIMITED | 2019-10-04T15:52:26Z | 2019-10-04T18:17:48Z |
| ABC LIMITED | 2019-10-05T23:17:48Z | (null) |
| ABC LIMITED | 2019-10-06T09:00:00Z | 2019-10-06T15:00:00Z |
答案 2 :(得分:1)
假设问题中的数据是交错的,则数据透视似乎比必需的更为复杂。您可以只使用分析功能和过滤:
select agency_name, time as in_time, out_time
from (select k.*,
min(case when "action" = 'OUT' then time end) over
(partition by agency_name
order by time desc
) as out_time
from kvtest k
) k
where "action" = 'IN';
Here是db <>小提琴。