SQL 查询问题,请教一下大家。

2019-10-12 09:11:32 +08:00
 Gatsbywl

Oracle


所以特来此请教各位大佬们有没有好的方法,怎么实现? SQL or PL/SQL ? 不胜感激!

3276 次点击
所在节点    数据库
21 条回复
sadfQED2
2019-10-12 09:14:15 +08:00
U_ID 不是唯一的??那这咋匹配
cwjokaka
2019-10-12 09:17:59 +08:00
JOIN 的结果用 DISTINCT 去重好像可以
xuanbg
2019-10-12 09:21:52 +08:00
这个数据 SQL 没办法做到一一配对。如果数据是有序的,你还能写代码用循环来处理。
xuanbg
2019-10-12 09:22:58 +08:00
非要 SQL 处理,只能存储过程用游标。这种方法严重不推荐!
kiracyan
2019-10-12 09:23:52 +08:00
如果 in out 按时间顺序匹配的话 你可以按 U_ID 分组 然后在对应 比如 U_ID=1 有 Gruop1 Group2, 这非唯一对应肯定要先处理原数据的
ESeanZ
2019-10-12 09:26:11 +08:00
通过 min、max,根据 U_id 获取大当前 in 的最小 out 时间,
xuanbg
2019-10-12 09:27:46 +08:00
想了一下,还有一种间接的办法,就是给你的原始数据加一列 group_id,让每一对 IN_OUT 拥有相同且唯一的 id 就行了。然后你就能按 group_id 进行 group by 配对了。
LeeSeoung
2019-10-12 09:33:01 +08:00
这个还涉及到行转列的问题,就算 sql 写出来也是一坨,建议代码里逻辑处理
tk2049jq
2019-10-12 09:38:02 +08:00
select
a.U_ID,
a.DATE_TIME as IN_TIME,
b.DATE_TIME as OUT_TIME
from (select * from tb_1 where IN_OUT = 'IN') a
join (select * from tb_1 where IN_OUT = 'OUT') b
on a.U_ID = b.U_ID
bluarry
2019-10-12 09:38:41 +08:00
没用过 oracle,不知道可不可以用 group by 然后排个序
oaix
2019-10-12 09:49:45 +08:00
JOIN 之后再对 U_ID,IN_TIME 做个分组,取最小的 OUT_TIME
select U_ID, IN_TIME, min(OUT_TIMES) OUT_TIME
from (select U_ID, a.DATE_TIME IN_TIME, b.DATE_TIME OUT_TIMES
from TT a
join TT b on a.U_ID = b.U_ID and a.DATE_TIME < b.DATE_TIME
where a.IN_OUT = 'IN'
and b.IN_OUT = 'OUT') t
group by U_ID, IN_TIME
wwwwaaanng
2019-10-12 09:52:48 +08:00
两条 sql union 一下?
a87965028
2019-10-12 09:53:08 +08:00
;with TT_IN as (
select *, ROW_NUMBER() over(partition by U_ID order by DATE_TIME) as rn
from TT where IN_OUT = 'IN'
),
TT_OUT as (
select *, ROW_NUMBER() over(partition by U_ID order by DATE_TIME) as rn
from TT where IN_OUT = 'OUT'
)
select TT_IN.U_ID, TT_IN.DATE_TIME as IN_TIME, TT_OUT.DATE_TIME as OUT_TIME
from TT_IN
left join TT_OUT on TT_IN.rn = TT_OUT.rn

如果用 sql server 的话,应该就是这么写。可以参考一下
anzu
2019-10-12 10:08:19 +08:00
如果 in out 是严格匹配,有 in 必有 out 的情况下,可以利用行号进行匹配。
这是 mysql 的,假设表名是 inout

SELECT t_in.U_ID, t_in.DATE_TIME AS in_time, t_out.DATE_TIME AS out_time
FROM
(SELECT
@rowNum1:=@rowNum1 + 1 AS n, i.*
FROM
`inout` i
, (SELECT @rowNum1:=0) tn
WHERE in_out = 'in'
ORDER BY DATE_TIME
) t_in
LEFT JOIN
(SELECT
@rowNum2:=@rowNum2 + 1 AS n, i.*
FROM
`inout` i
, (SELECT @rowNum2:=0) tn
WHERE in_out = 'out'
ORDER BY DATE_TIME
) t_out ON t_in.n=t_out.n
a87965028
2019-10-12 10:13:21 +08:00
@a87965028 #13 最后一行写少了
select TT_IN.U_ID, TT_IN.DATE_TIME as IN_TIME, TT_OUT.DATE_TIME as OUT_TIME
from TT_IN
left join TT_OUT on TT_IN.rn = TT_OUT.rn and TT_IN.U_ID = TT_OUT.U_ID
opengps
2019-10-12 10:17:54 +08:00
不建议合并,看表结构很显然是物联网开关传感器的上报信息。实际上,这么处理会掩盖“漏点”问题。源头建议用程序接收时候处理成时间轴变化状态。也就是说保留原始数据,用程序直接读取源数据加工
Gatsbywl
2019-10-12 11:50:51 +08:00
@ESeanZ @a87965028
谢谢大家!我写完了。
思路是
1. 先分别选出 IN 和 OUT 的数据
2. 再 LEFT JOIN ON (出的时间晚于进的时间)
3. 最后根据人员和进入时间分组,出的时间排序,每一个进入时间选择最早出的时间( RN = 1 )

SELECT T3.F_ID
, T3.F_NAME
, T3.IN_T
, T3.OUT_T
, T3.RN
FROM (
SELECT T1.F_ID
, T1.F_NAME
, T1.DATE_TIME IN_T
, T2.DATE_TIME OUT_T
, ROW_NUMBER() OVER(PARTITION BY T1.F_ID, T1.DATE_TIME
ORDER BY T2.DATE_TIME) RN
FROM
(SELECT F1.DATE_TIME
, F1.F_ID
, F1.F_NAME
, F1.F_DEPART
, F1.IN_OUT
FROM ADMIN.FAB_TIME F1
WHERE F1.IN_OUT = '001-正常进入开门'
AND F1.DATE_TIME BETWEEN
TO_DATE(20191001000000, 'YYYY-MM-DD HH24:MI:SS')
AND TO_DATE(20191002000000, 'YYYY-MM-DD HH24:MI:SS')
) T1
LEFT JOIN
(SELECT F1.DATE_TIME
, F1.F_ID
, F1.F_NAME
, F1.F_DEPART
, F1.IN_OUT
FROM ADMIN.FAB_TIME F1
WHERE F1.IN_OUT = '002-正常外出开门'
AND F1.DATE_TIME BETWEEN
TO_DATE(20191001000000, 'YYYY-MM-DD HH24:MI:SS')
AND TO_DATE(20191002000000, 'YYYY-MM-DD HH24:MI:SS')
) T2
ON T1.F_ID = T2.F_ID
AND T1.DATE_TIME <= T2.DATE_TIME
ORDER BY T1.F_ID,T1.DATE_TIME
) T3
WHERE T3.RN = 1
;
ESeanZ
2019-10-12 15:14:30 +08:00
@Gatsbywl 老哥你这代码量有点多啊
粗略写了一段 应该没啥毛病(环境 Mysql,某些地方应该不一样)
SELECT InTable.u_id,InTable.date_titme AS In_Time, (SELECT MIN(date_titme)
FROM demo_1 AS OutTable WHERE OutTable.date_titme>InTable.date_titme AND OutTable.In_Out="Out") AS Out_time
FROM demo_1 AS InTable WHERE InTable.In_Out="In"
wqzjk393
2019-10-12 15:43:55 +08:00
case when 啊。。。
jowenzzzzz
2019-10-12 16:04:37 +08:00
你是想原表数据转换到查询结果样式吧,不用 join.on 用分析函数应该可以解决

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/608465

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX