Firebird从表中选择一个不同的字段

时间:2018-01-18 15:25:54

标签: sql firebird greatest-n-per-group

我昨天问的问题已经简化,但我意识到我必须报告整个故事。 我必须将4个不同表中的4个数据提取到Firebird 2.5数据库中,以下查询有效:

SELECT 
PRODUZIONE_T t.CODPRODUZIONE, 
PRODUZIONE_T.NUMEROCOMMESSA as numeroco,
    ANGCLIENTIFORNITORI.RAGIONESOCIALE1, 
    PRODUZIONE_T.DATACONSEGNA, 
    PRODUZIONE_T.REVISIONE,
    ANGUTENTI.NOMINATIVO, 
    ORDINI.T_DATA,
FROM PRODUZIONE_T
LEFT OUTER JOIN ORDINI_T ON PRODUZIONE_T.CODORDINE=ORDINI_T.CODORDINE 
INNER JOIN ANGCLIENTIFORNITORI ON ANGCLIENTIFORNITORI.CODCLIFOR=ORDINI_T.CODCLIFOR 
LEFT OUTER JOIN ANGUTENTI ON ANGUTENTI.IDUTENTE = PRODUZIONE_T.RESPONSABILEUC
ORDER BY right(numeroco,2) DESC, left(numeroco,3) desc 
rows 1 to 500;

但是由于REVISIONE列,查询返回了两倍(或更多)。 如何仅选择具有最大REVISIONE值的单个NUMEROCOMMESSA行?

3 个答案:

答案 0 :(得分:2)

这应该有效:

select COD, ORDER, S.DATE, REVISION 
FROM TAB1
JOIN 
(
   select ORDER, MAX(REVISION) as REVISION
   FROM TAB1
   Group By ORDER
) m on m.ORDER = TAB1.ORDER and m.REVISION = TAB1.REVISION

答案 1 :(得分:2)

你去了 - http://sqlfiddle.com/#!6/ce7cf/4

示例数据(正如您在原始问题中设置的那样):

create table TAB1 (
  cod integer primary key,
  n_order varchar(10) not null,
  s_date date  not null,
  revision integer not null );

alter table tab1 add constraint UQ1 unique (n_order,revision);  

insert into TAB1 values ( 1, '001/18', '2018-02-01', 0 );
insert into TAB1 values ( 2, '002/18', '2018-01-31', 0 );
insert into TAB1 values ( 3, '002/18', '2018-01-30', 1 );

查询:

select * 
from tab1 d
join ( select n_ORDER, MAX(REVISION) as REVISION
       FROM TAB1
       Group By n_ORDER ) m
  on m.n_ORDER = d.n_ORDER and m.REVISION = d.REVISION

建议:

  1. Google并阅读经典书籍:"了解SQL"作者:Martin Gruber
  2. 阅读Firebird SQL参考:https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25.html
  3. 这是使用Firebird 3中引入的窗口函数的另一个解决方案 - http://sqlfiddle.com/#!6/ce7cf/13

    我手边没有Firebird 3,所以实际上无法检查是否会出现突然的不兼容性,请在家里进行:-D

    SELECT * FROM
    (
       SELECT
         TAB1.*,
         ROW_NUMBER() OVER (
             PARTITION BY n_order 
             ORDER BY revision DESC
          ) AS rank
       FROM TAB1
    ) d
    WHERE rank = 1
    

    阅读文档

    三者中的哪一个(包括Gordon的一个)解决方案将更快取决于特定的数据库 - 真实数据,现有索引,索引的选择性。

    虽然窗口函数可以进行无连接查询,但我不确定实际数据会更快,因为它可能只是忽略order+revision cortege上的索引并执行全扫描< / em>相反,在应用rank=1条件之前。虽然第一个解决方案最有可能使用索引来获取最大值而不实际读取表中的每一行。

    Firebird支持邮件列表提出了一种突破循环的方法,只使用一个查询:诀窍是同时使用Windows函数和CTE(公用表表达式):http://sqlfiddle.com/#!18/ce7cf/2

    WITH TMP AS (
      SELECT 
       *,
       MAX(revision) OVER (
             PARTITION BY n_order 
           ) as max_REV
      FROM TAB1
    )
    SELECT * FROM TMP
    WHERE revision = max_REV
    

答案 2 :(得分:1)

如果您想要Firebird中的最大修订号:

select t.*
from tab1 t
where t.revision = (select max(t2.revision) from tab1 t2 where t2.order = t.order);

对于性能,您需要tab1(order, revision)上的索引。有了这样的指数,绩效应该与任何其他方法竞争。