在编写复杂的SQL查询时需要帮助

时间:2018-08-31 08:19:09

标签: sql oracle select

我需要一些有关复杂SQL查询的帮助。 这是我的设置:我有两个表USER_TABLEUSER_VISIT_STATUSER_TABLE具有诸如ID,USER_NAME,UID,DEPARTMENTUSER_VISIT_STAT的列类似ID,USERID,LAST_VISIT_DATEUSERID表的USER_VISIT_STAT字段保存USER_TABLE.ID

当用户登录到应用程序时,他的当前日期保存在USER_VISIT_STAT表中(请参阅屏幕截图)。因此,我需要获取自最近两年以来未连接到应用程序的用户详细信息。但是我们必须注意UID。 (意味着您可以在USER_TABLE中看到两个条目,它们具有相同的UID,但大小写不同。在USER_VISIT_STAT中,您可以看到101 LAST_VISIT_DATE是31-08-18和103 LAST_VISIT_DATE20-01-16。因此,您必须忽略这两个ID,因为用户相同并且他处于活动状态)。在响应表中,我需要用户名,用户uid,用户部门和用户max(最后激活日期)。

+--------------------------------------+
|             USER_TABLE               |
+--------------------------------------+
| ID    | NAME    | UID   | DEPARTMENT |
+--------------------------------------+
| 101   | PRAKASH | US45  | ENGG       |
| 102   | RAJESH  | US22  | ENGG       |
| 103   | PRAKASH | us45  | HR         |
| 104   | HARI    |  US9  | ENGG       |
| 105   | MAYANK  | US90  | HR         |
+--------------------------------------+
+--------------------------------+
|          USER_VISIT_STAT       |
+--------------------------------+
| ID | USID | MAX(LAST_VISIT_DATE)|
+--------------------------------+
| 1  | 101 |    31-08-18         |
| 2  | 102 |    30-08-18         |
| 3  | 101 |    30-08-18         |
| 4  | 103 |    20-01-16         |
| 5  | 104 |    29-08-16         |
| 6  | 105 |    19-07-16         |
| 7  | 101 |    12-06-16         |
| 8  | 102 |    12-06-16         |
| 9  | 104 |    13-04-16         |
+--------------------------------+
+-------------------------------------------------+
|                    RESPONSE                     |
+-------------------------------------------------+
| NAME   | UID  |   DEPARTMENT | LAST_VISIT_DATE  |
+-------------------------------------------------+
| HARI   | US9  |   ENGG       |    29-08-16      |
| MAYANK | US09 |   HR         |  19-07-16        |
+-------------------------------------------------+

5 个答案:

答案 0 :(得分:2)

我将使用row_number来获取每个uid的最新用户详细信息,并将它们加入到uid的最后访问日期中,并以此进行过滤:

SELECT name, u.uid, department, max_visit
FROM   (SELECT name,
               uid,
               department,
               ROW_NUMBER() OVER (PARTITION BY uid ORDER BY id DESC) AS rn
        FROM   user_table) u
JOIN   (SELECT   uid, MAX(last_visit_date) AS max_visit
        FROM     user_visit_stat
        GROUP BY uid
        HAVING   MONTHS_BETWEEN(sysdate, MAX(last_visit_date)) >= 24) us ON u.uid = us.uid
WHERE  rn = 1              

答案 1 :(得分:0)

尝试以下方法:

select a.uid,a.name,b.department,a.id,lastvisit
from
(select uid,name,max(id) as id
from USER_TABLE group by uid,name)a
inner join USER_TABLE b on a.uid=b.uid
inner join
(select uid,max(LAST_VISIT_DATE) as lastvisit
group by uid having max(LAST_VISIT_DATE)< trunc(sysdate, 'yyyy') - interval '2' year)x
on a.id=x.id

答案 2 :(得分:0)

使用聚合函数并加入

  select u.*,t.last_visit from     
    (
   select min(ID) as ID ,Name, UPPER(UID) as UID,DEPARTMENT from USER_TABLE
    group by Name, UPPER(UID),DEPARTMENT
    ) as u 
    join
    (
    select UID,max(LAST_VISIT_DATE) as last_visit from USER_VISIT_STAT us
    group by UID 
    having max(LAST_VISIT_DATE) between  add_months(sysdate,-26) and add_months(sysdate,-24)
    ) as t
    on u.ID=t.UID

从对话看来,您似乎需要以下内容

select u.*, x.last_visit from
       (
       select Name, UPPER(UID) as UID,DEPARTMENT from USER_TABLE
        group by Name, UPPER(UID),DEPARTMENT
        ) as u 

        join
        (   
        select a.name,a.last_visit from
        (
        select distinct iu.NAME,last_visit from
        (
        select USID,max(LAST_VISIT_DATE) as last_visit from USER_VISIT_STAT us
        group by USID 
        having max(LAST_VISIT_DATE) between  add_months(sysdate,-26) and add_months(sysdate,-24)
        ) as t1 
        join
        USER_TABLE as iu on t1.USID=iu.ID
        ) a left join           

        (
        select distinct iu.NAME,    
        (
        select USID  from USER_VISIT_STAT us
        group by USID 
        having min(LAST_VISIT_DATE) between  add_months(sysdate,-23) and add_months(sysdate,0)
        ) as t1 
        join
        USER_TABLE as iu on t1.UID=iu.ID    
        ) b on a.NAME=b.NAME
        where b.NAME is null 
        ) x on u.Name=x.Name

答案 3 :(得分:0)

类似

select uid,name,department,last_visit_date
from (
  select 
    a.id id, max(a.id) over (partition by a.uid) maxid,
    a.uid uid,a.name name,a.department department,
    max(last_visit_date) over (partition by a.uid) last_visit_date
  from 
    user_table a, user_visit_stat b
  where 
    a.id=b.uid
)
where last_visit_date<=add_years(sysdate,-2) and a.id=maxid

答案 4 :(得分:0)

使用MAX()函数的解析形式,将其划分为UID的大写字母即可解决此问题。 SQL Fiddle

可作为演示

查询1

SELECT
  M.LAST_VISIT_DATE, U.*
FROM (
    SELECT
      U."UID" 
    , V.LAST_VISIT_DATE
    , MAX(V.LAST_VISIT_DATE) OVER(PARTITION BY UPPER(U."UID")) MAX_VISIT
    FROM USER_TABLE U
    INNER JOIN USER_VISIT_STAT V ON U.ID = V.USID
    ) M
INNER JOIN USER_TABLE U ON M."UID" = U."UID"
WHERE M.MAX_VISIT < ADD_MONTHS(SYSDATE,-24)
AND M.LAST_VISIT_DATE = M.MAX_VISIT

Results

|       LAST_VISIT_DATE |  ID |   NAME |  UID | DEPARTMENT |
|-----------------------|-----|--------|------|------------|
| 2016-08-29 00:00:00.0 | 104 |   HARI |  US9 |       ENGG |
| 2016-07-19 00:00:00.0 | 105 | MAYANK | US90 |         HR |

Oracle 11g R2架构设置

CREATE TABLE USER_TABLE
    ("ID" int, "NAME" varchar2(7), "UID" varchar2(4), "DEPARTMENT" varchar2(4))
;

INSERT ALL
    INTO USER_TABLE ("ID", "NAME", "UID", "DEPARTMENT")
         VALUES (101, 'PRAKASH', 'US45', 'ENGG')
    INTO USER_TABLE ("ID", "NAME", "UID", "DEPARTMENT")
         VALUES (102, 'RAJESH', 'US22', 'ENGG')
    INTO USER_TABLE ("ID", "NAME", "UID", "DEPARTMENT")
         VALUES (103, 'PRAKASH', 'us45', 'HR')
    INTO USER_TABLE ("ID", "NAME", "UID", "DEPARTMENT")
         VALUES (104, 'HARI', 'US9', 'ENGG')
    INTO USER_TABLE ("ID", "NAME", "UID", "DEPARTMENT")
         VALUES (105, 'MAYANK', 'US90', 'HR')
SELECT * FROM dual
;

CREATE TABLE USER_VISIT_STAT       
    ("ID" int, "USID" int, "LAST_VISIT_DATE" timestamp)
;

INSERT ALL 
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (1, 101, '31-Aug-2018 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (2, 102, '30-Aug-2018 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (3, 101, '30-Aug-2018 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (4, 103, '20-Feb-2016 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (5, 104, '29-Aug-2016 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (6, 105, '19-Jul-2016 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (7, 101, '12-Jun-2016 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (8, 102, '12-Jun-2016 12:00:00 AM')
    INTO USER_VISIT_STAT        ("ID", "USID", "LAST_VISIT_DATE")
         VALUES (9, 104, '13-Apr-2016 12:00:00 AM')
SELECT * FROM dual
;