形成SQL查询以跨行比较结果

时间:2012-01-05 12:43:41

标签: oracle

问题陈述:

  

选择所有商店名称,其状态,电话号码,生效日期   其电话号码已从2003年更改为现在。

架构是

store_name,phone number , start_date , status

示例行

    abc 1234  30-DEC-2011 open 
    abc 3433  04-Jan-2012 close
    bbb 4444  30-Jan-2010 open
    bbb 4444  31-Jan-2011 open

输出

    abc 1234 open 30-DEC-3011 till 3-Jan-2012
    abc 3433 close 04-Jan-2012 till date

我也很好,输出中有两行,排序的开始日期如

abc 1234 30-DEC-2011 open
abc  3433 04-Jan-2012 close
不应报告

bbb,因为电话号码没有变化。我们只应报告电话号码已更改的商店。

有人可以帮我解决这个关于Oracle的问题吗?我想通过使用相关查询可以完成,但我不知道如何构建一个。

请注意,我的表有大约3154953条记录,因此我还需要确保相关查询不会在很长一段时间内锁定表。这甚至可以用于Oracle吗?

谢谢!


APC的回答对我而言只是因为我在结果中看到了很多重复。

输入:

select store_name,phone_number,start_date, status where store_name=abc;

返回

STORE_name         Phone number start_date     STATUS
---------------- ---------------- ----------- ----------
abc              122 18-JAN-2011          open
abc              122 18-JAN-2011          open
abc              122 18-JAN-2011          close

运行查询会给我以下输出。

abc              122 open from 18-JAN-2011 to 17-JAN-2011
abc              122 open from 18-JAN-2011 to 17-JAN-2011
abc              122 close  from 18-JAN-2011 to date

你能解释为什么以及在哪里错过了吗?

2 个答案:

答案 0 :(得分:2)

我认为这是针对Oracle而不是MySQL,因为我的解决方案使用了一些魔术技巧,我很确定这些技巧在MySQL中不可用。第一个是Common Table Expression来获取一个我们可以使用多次的结果集。第二个是使用LEAD()分析函数来“预测”下一行中的值。

所以,这是查询:

with a as   ( select store_name
             , phone_number
             , status
             , start_date
             , lead (start_date, 1, trunc(sysdate)) over (partition by store_name
                                       order by start_date) as next_date
             , lead (phone_number, 1, null) over (partition by store_name
                                       order by start_date) as next_number
       from your_table 
       where start_date >= date '2003-01-01' ) 
select  a.store_name
      , a.phone_number
      , case  when a.next_date != trunc(sysdate) then 
                  a.status||' from '|| a.start_date ||' to '||to_char(a.next_date - 1)
               else a.status||' from '||a.start_date ||' to date'
              end  as status_text
from a
where a.store_name in (
                select store_name
                from a 
                where phone_number != next_number)
order by a.store_name, a.start_date
/

这是它的输出:

SQL> r
  1  with a as   ( select store_name
...
 22  order by a.store_name, a.start_date                
 23  /

STORE_NAME           PHONE_NUMBER STATUS_TEXT
-------------------- ------------ --------------------------------
abc                          1234 open from 30-DEC-11 to 03-JAN-12
abc                          3433 close from 04-JAN-12 to date

2 rows selected.

SQL> 

至于这句话:

  

“因此我还需要确保相关查询不会锁定   表很多时间“

在Oracle中无关紧要,因为读取不会阻止其他读取。也没有写到这一点。

答案 1 :(得分:0)

这将是

的内容
select * from table0 as q0 join
(
    select min(date) from table0 as q1 where q1.store_name = q0.store_name
) as q2 on q2.store_name = q0.store_name
left join
(
    select max(date) from table0 as q1 where q1.store_name = q0.store_name
) as q3 on q3.store_name = q0.store_name

这不太正确,因为我没有在我面前使用MySQL,但是它的内容就是这样。