简体   繁体   English

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

[英]Using “order by” and fetch inside a union in SQL on as400 database

Let's say I have this table 假设我有这张桌子

Table name: Traffic
Seq.     Type     Amount
1        in       10
2        out      30
3        in       50
4        out      70

What I need is to get the previous smaller and next larger amount of a value. 我需要获得的值的上一个较小和下一个较大的值。 So, if I have 40 as a value, I will get... 所以,如果我有40作为价值,我将得到...

Table name: Traffic
Seq.     Type     Amount
2        out      30
3        in       50

I already tried doing it with MYSQL and quite satisfied with the results 我已经尝试使用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)

The problem lies when I try to convert it to a SQL statement acceptable by AS400. 问题出在我尝试将其转换为AS400可接受的SQL语句时。 It appears that the order by and fetch function (AS400 doesn't have a limit function so we use fetch, or does it?) is not allowed inside the select statement when I use it with a union. 当我将其与联合使用时,似乎不允许在select语句内部使用order by and fetch函数(AS400没有限制函数,所以我们使用fetch还是使用fetch?)。 I always get a keyword not expected error. 我总是得到一个关键字意外错误。 Here is my statement; 这是我的声明;

(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)

Can anyone please tell me what's wrong and how it should be? 谁能告诉我哪里出了问题以及应该怎么办? Also, please share if you know other ways to achieve my desired result. 另外,如果您知道其他达到我期望的结果的方法,请分享。

How about a CTE? CTE怎么样? From memory (no machine to test with): 从内存(无机器可测试):

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))) 

I looked at this question from possibly another point of view. 我从另一个角度看了这个问题。 I have seen other questions about date-time ranges between rows, and I thought perhaps what you might be trying to do is establish what range some value might fall in. 我还看到了有关行之间日期时间范围的其他问题,我想也许您可能想做的是确定某个值可能属于的范围。

If working with these ranges will be a recurring theme, then you might want to create a view for it. 如果使用这些范围将是重复出现的主题,那么您可能要为其创建一个视图。

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
;

Once you have this view, it becomes very simple to get your answer: 一旦有了此视图,就很容易得到答案:

select * 
  from traffic_ranges
  where 40 is between beg_amt and end_amt

Or to get only one range where the search amount happens to be an amount in your base table, you would want to pick whether to include the beginning value or ending value as part of the range, and exclude the other: 或仅获取一个搜索量恰好是基表中某个量的范围,您可能想要选择是将起始值还是终止值作为范围的一部分,而排除另一个:

  where beg_amt < 40 and end_amt >= 40

One advantage of this approach is performance. 这种方法的一个优势是性能。 If you are finding the range for multiple values, such as a column in a table or query, then having the range view should give you significantly better performance than a query where you must aggregate all the records that are more or less than each search value. 如果要查找多个值的范围(例如表或查询中的列),则具有范围视图的性能应比查询要好得多,在查询中,必须汇总大于或小于每个搜索值的所有记录。

Here's my query using CTE and union inspired by Buck Calabro's answer. 这是我使用CTE和union的查询,灵感来自Buck Calabro的答案。 Credits go to him and WarrenT for being SQL geniuses! 感谢他和WarrenT成为SQL天才!

I won't be accepting my own answer. 我不会接受自己的答案。 That will be unfair. 那将是不公平的。 hehe 呵呵

 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

It's a bit slow but I can accept that since I'll only use it once in the progam. 这有点慢,但是我可以接受,因为我在程序中只使用了一次。

This is just a sample. 这只是一个示例。 The actual query is a bit different. 实际查询有些不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM