在sql中,使用子查询多次查询的最佳语法

时间:2013-04-14 01:10:57

标签: sql postgresql subquery

来自表格

create table seeplai.item(
  itm_id  serial  primary key,
  itp_id  int     not null references seeplai.item_type,
  itm_sq  int2    not null default 10,
  ... )
create index item_itp_sq on seeplai.item( itp_id, itm_sq );

使用item记录作为基础,我希望找到具有相同itp_sq并且itp_id减少的最佳itm_sq。现在使用两个子查询,这在语法和逻辑上都是正确的,但感觉不对。

select  max(itm_sq)
into    v_prev_sq
from    seeplai.item itm
where   itm.itp_id = (select itp_id from seeplai.item where itm_id=p_itm_id)
and     itm.itm_sq < (select itm_sq from seeplai.item where itm_id=p_itm_id);

知道我使用了更好的方法,但它的语法已经溶解到了我心中的蜘蛛网中

5 个答案:

答案 0 :(得分:2)

要获得一个最大itm_sq小于您行中的<{1}}:

SELECT  i2.itm_sq
FROM    seeplai.item i
JOIN    seeplai.item i2 USING (itp_id)
WHERE   i.itm_id = p_itm_id
AND     i2.itm_sq < i.itm_sq 
ORDER   BY i2.itm_sq DESC
LIMIT   1;

要打破关系(多个行具有相同的itm_sq),您可以ORDER BY其他列。

这样您就不必重复使用任何东西。如果必须,可以使用子查询或CTE作为工具。


如果您需要以前的itm_sq 每个项目共享相同的itp_id窗口函数lag()(或lead()具有相反的顺序)将有助于:

SELECT  i2.*, lag(i2.itm_sq) OVER (ORDER BY i2.itm_sq) AS previous_itm_sq
FROM    seeplai.item i
JOIN    seeplai.item i2 USING (itp_id)
WHERE   i.itm_id = p_itm_id
ORDER   BY i2.itm_sq DESC;

答案 1 :(得分:1)

您需要将表格加入自身:

select max(itm_sq)
into v_prev_sq
from seeplai.item itm
join seeplai.item itm2 on itm.itm_tp = itm2.itm_tp and itm2.itm_id=p_itm_id
join seeplai.item itm3 on itm.itm_sq < itm3.itm_sq and itm3.itm_id=p_itm_id

这是您查询的“直接翻译”,但我认为这种简化也有效:

select max(itm_sq)
into v_prev_sq
from seeplai.item itm
join seeplai.item itm2
    on itm.itm_tp = itm2.itm_tp 
    and itm2.itm_id = p_itm_id
    and itm.itm_sq < itm2.itm_sq

答案 2 :(得分:0)

我不确定,但也许你可以使用PostgreSQL的WITH Queries (Common Table Expressions)

答案 3 :(得分:0)

也许您正在寻找常见的表格表达式? http://www.postgresql.org/docs/9.2/static/queries-with.html

虽然我认为实际上使用连接更容易实现...

select  max(itm_0.itm_sq)
into    v_prev_sq
from    seeplai.item itm_0,
join itm_1
on itm_0.itm_tp = itm_1.itm_tp
and itm_0.itm_sq < itm_1.itm_sq
and itm_0.itm_id = itm_1.p_itm_id
group by itm_1.p_itm_id

如果需要,可能会使用DISTINCT ON

答案 4 :(得分:-1)

只需将子查询的值存储在变量中:

declare @retVal varchar(20);
set @retVal = select itm_tp from seeplai.item where itm_id=p_itm_id

select  max(itm_sq)
into    v_prev_sq
from    seeplai.item itm
where   itm.itm_tp = @retVal
and     itm.itm_sq < @retVal;