【问题标题】:Forming a SQL query to compare results across rows形成一个 SQL 查询来比较跨行的结果
【发布时间】:2012-01-06 04:01:00
【问题描述】:

问题陈述:

选择所有商店名称、状态、电话号码、生效日期 其电话号码从 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

你能解释一下为什么以及小姐在哪里吗?

【问题讨论】:

  • @ManseUK - 您已删除 [mysql] 标记并忽略标题中对 MySQL 的引用。在开始编辑之前,请确保您的更改不会扭曲 OP 的意图。
  • @APC 道歉...这是我今天犯的 2 个编辑错误...。添加标签...虽然我真的不知道为什么它在标题或标签中?
  • @TopCoder - “我看到很多重复......你能解释一下原因吗”。您的数据包含大量重复。重复输入产生重复输出并不奇怪,现在是这样吗?至于 END_DATE 的奇怪之处,我的查询预计记录之间会有一天的宽限期。如果你真的有这样古怪的业务逻辑,那么你将不得不定制查询来应对它们。

标签: oracle


【解决方案1】:

我假设这是针对 Oracle 而不是 MySQL,因为我的解决方案使用了一些我很确定在 MySQL 中不可用的魔术技巧。第一个是公共表表达式,用于获取我们可以多次使用的结果集。第二种是使用 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 中无关紧要,因为读取不会阻塞其他读取。也没有写到那个。

【讨论】:

  • 谢谢!效果很好。我也有机会阅读了有关领导功能的信息。
  • 我发现结果存在一些问题。我编辑了这个问题,你能看看它,让我知道我错过了什么吗?
【解决方案2】:

这将类似于

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,但它是类似的东西。

【讨论】:

    猜你喜欢
    • 2011-10-11
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多