在as400数据库上的SQL中使用“order by”并在联合内部提取

在as400数据库上的SQL中使用“order by”并在联合内部提取,sql,ibm-midrange,Sql,Ibm Midrange,假设我有这张桌子 Table name: Traffic Seq. Type Amount 1 in 10 2 out 30 3 in 50 4 out 70 我需要的是得到前一个较小的值和下一个较大的值。所以,如果我有40作为一个值,我会得到 Table name: Traffic Seq. Type Amount 2 out 30 3

假设我有这张桌子

Table name: Traffic
Seq.     Type     Amount
1        in       10
2        out      30
3        in       50
4        out      70
我需要的是得到前一个较小的值和下一个较大的值。所以,如果我有40作为一个值,我会得到

Table name: Traffic
Seq.     Type     Amount
2        out      30
3        in       50
我已经试过用MYSQL做了,并且对结果非常满意

(select * from Traffic where
Amount < 40 order by Amount desc limit 1)
union
(select * from Traffic where
Amount > 40 order by Amount desc limit 1)
问题在于,当我试图将其转换为AS400可以接受的SQL语句时。看起来order by和fetch函数AS400没有限制函数,所以我们使用fetch,还是这样?当我将select语句与union一起使用时,不允许在select语句中使用。我总是得到一个关键字非预期的错误。这是我的声明

(select seq as sequence, type as status, amount as price from Traffic where
Amount < 40 order by price asc fetch first 1 rows only)
union
(select seq as sequence, type as status, amount as price  from Traffic where
Amount > 40 order by price asc fetch first 1 rows only)

谁能告诉我出了什么问题,应该怎么办?另外,如果您知道实现我期望结果的其他方法,请与我分享。

CTE如何?从内存中没有要测试的机器:

with 
  less as (select * from traffic where amount < 40),
  more as (select * from traffic where amount > 40)
select * from traffic
  where id = (select id from less where amount = (select max(amount from less))) 
     or id = (select id from more where amount = (select min(amount from more))) 

CTE怎么样?从内存中没有要测试的机器:

with 
  less as (select * from traffic where amount < 40),
  more as (select * from traffic where amount > 40)
select * from traffic
  where id = (select id from less where amount = (select max(amount from less))) 
     or id = (select id from more where amount = (select min(amount from more))) 

我可能从另一个角度看待这个问题。我看到了关于行之间日期-时间范围的其他问题,我想也许您可能要做的是确定某个值可能位于哪个范围内

如果使用这些范围将是一个重复出现的主题,那么您可能需要为其创建一个视图

create or replace view traffic_ranges as
  with sorted as
  ( select t.*
         , smallint(row_number() over (order by amount)) as pos
     from traffic t
  )
  select b.pos    range_seq
       , b.id     beg_id
       , e.id     end_id
       , b.typ    beg_type
       , e.typ    end_type
       , b.amount beg_amt
       , e.amount end_amt
    from sorted b
    join sorted e  on e.pos = b.pos+1
;
一旦你有了这个观点,得到你的答案就变得非常简单:

select * 
  from traffic_ranges
  where 40 is between beg_amt and end_amt
或者,若要仅获取一个范围,其中搜索金额恰好是基表中的金额,则需要选择是否将起始值或结束值作为范围的一部分,并排除其他值:

  where beg_amt < 40 and end_amt >= 40

这种方法的一个优点是性能。如果要查找多个值的范围,例如表或查询中的列,那么使用范围视图应该比必须聚合大于或小于每个搜索值的所有记录的查询具有更好的性能。

我可能从另一个角度看了这个问题。我看到了关于行之间日期-时间范围的其他问题,我想也许您可能要做的是确定某个值可能位于哪个范围内

如果使用这些范围将是一个重复出现的主题,那么您可能需要为其创建一个视图

create or replace view traffic_ranges as
  with sorted as
  ( select t.*
         , smallint(row_number() over (order by amount)) as pos
     from traffic t
  )
  select b.pos    range_seq
       , b.id     beg_id
       , e.id     end_id
       , b.typ    beg_type
       , e.typ    end_type
       , b.amount beg_amt
       , e.amount end_amt
    from sorted b
    join sorted e  on e.pos = b.pos+1
;
一旦你有了这个观点,得到你的答案就变得非常简单:

select * 
  from traffic_ranges
  where 40 is between beg_amt and end_amt
或者,若要仅获取一个范围,其中搜索金额恰好是基表中的金额,则需要选择是否将起始值或结束值作为范围的一部分,并排除其他值:

  where beg_amt < 40 and end_amt >= 40

这种方法的一个优点是性能。如果要查找多个值的范围,例如表或查询中的一列,那么使用范围视图应该比必须聚合大于或小于每个搜索值的所有记录的查询具有更好的性能。

以下是我使用CTE和union进行的查询,灵感来自Buck Calabro的答案。他和沃伦特都是SQL天才,值得称赞

我不会接受我自己的答案。这是不公平的。呵呵

 with 
apple(seq, type, amount) as (select seq, type, amount from traffic where amount < 40 
order by amount desc fetch first 1 rows only),
banana(seq, type, amount) as (select seq, type, amount from traffic where
amount > 40 fetch first 1 rows only)
 select * from apple
union
 select * from banana
它有点慢,但我可以接受,因为我只在程序中使用它一次


这只是一个样本。实际的查询有点不同。

以下是我使用CTE和union的查询,灵感来自Buck Calabro的回答。他和沃伦特都是SQL天才,值得称赞

我不会接受我自己的答案。这是不公平的。呵呵

 with 
apple(seq, type, amount) as (select seq, type, amount from traffic where amount < 40 
order by amount desc fetch first 1 rows only),
banana(seq, type, amount) as (select seq, type, amount from traffic where
amount > 40 fetch first 1 rows only)
 select * from apple
union
 select * from banana
它有点慢,但我可以接受,因为我只在程序中使用它一次


这只是一个样本。实际查询有点不同。

如果表中正好有40个或您要查找的任何数字,您希望得到什么结果?是否可能有相同数量的行?然后呢?@WarrenT:其他程序确保该值不等于该金额。但是,谢谢你。这让我想到了未来可能出现的问题。对于你的第二个问题,重复的金额是可以的,只要我可以得到更小和更大的金额。谢谢因此,您在回答1时说,在上面的示例中,您永远不会使用30或50作为您使用40的搜索词。如果40或您要查找的任何数字恰好在您的表中,您希望得到什么结果?是否可能有相同数量的行?然后呢?@WarrenT:其他程序确保该值不等于该金额。但是,谢谢你。这让我想到了未来可能出现的问题。对于你的第二个问题,重复的金额是可以的,只要我可以得到更小和更大的金额。谢谢所以你在回答1时说,在上面的例子中,你永远不会使用30或50作为你的搜索词,而你使用了40?是的,这很有效,巴克。很好,因为当时没有一个盒子可以测试-CTE=公共表表达式?我一直从not expected获取此错误关键字。有效令牌:,。。顺便说一句,您缺少一个圆括号来封装您的id=select。。。是的,CTE是常用的表表达式。我编辑了答案以添加
右括号。我没有一台测试机器来测试它,所以它是从内存中获得的——你需要稍微修改一下。这提醒了我:您运行的是哪个版本的IBM i?如果有多行具有相同的数量,则此查询可能返回超过2行。但是如果要求只返回两行,那么我们需要更多的信息来决定选择哪一行。是的,这是有效的,巴克。很好,因为当时没有一个盒子可以测试-CTE=公共表表达式?我一直从not expected获取此错误关键字。有效令牌:,。。顺便说一句,您缺少一个圆括号来封装您的id=select。。。是的,CTE是常用的表表达式。我编辑了答案,添加了右括号。我没有一台测试机器来测试它,所以它是从内存中获得的——你需要稍微修改一下。这提醒了我:您运行的是哪个版本的IBM i?如果有多行具有相同的数量,则此查询可能返回超过2行。但是如果要求只返回两行,那么我们需要更多的信息来确定选择哪一行。