从同一个表SQL Server中选择对应的行

时间:2017-12-06 12:57:40

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

我想根据另一栏

获得一些专栏

示例表:

| BlilCode | BlilShortName | BatchWeigth | BillVersion | BlilMaxTime |
+----------+---------------+-------------+-------------+-------------+
| 5502     | aaa           | 1.00        | 1           | 360         |
| 5502     | aaa           | 2.00        | 2           | 240         |
| 5510     | bbb           | -32.94      | 2           | 360         |
| 5510     | bbb           | 1.00        | 1           | 360         |
| 5510     | bbb           | 36.37       | 3           | 3600        |

但我希望获得BillVersion每个BlilCode最大的行

预期结果

| BlilCode | BlilShortName | BatchWeigth | BillVersion | BlilMaxTime |
+----------+---------------+-------------+-------------+-------------+
| 5502     | aaa           | 2.00        | 2           | 240         |
| 5510     | bbb           | 36.37       | 3           | 3600        |

我目前的查询是:

SELECT    
    [BlilCode], [BlilShortName], 
    BatchWeigth, (BillVersion) AS BillVersion, [BlilMaxTime]
FROM 
    [CVfeedDB].[dbo].[constants.Blil]  
WHERE 
    BlilActive = 1 AND BatchWeigth IS NOT NULL
ORDER BY 
    BlilCode

2 个答案:

答案 0 :(得分:2)

您的结果表明您想要:

select db.*
from (select db.*,
             row_number() over (partition by shortname order by billversion desc) as seqnum
      from db
     ) db
where seqnum = 1;

如果您基于blilcode,那么结果将有三行而不是两行。

注意:在此之后编辑了问题,因此适当的查询将是:

select db.*
from (select db.*,
             row_number() over (partition by blilcode order by billversion desc) as seqnum
      from db
     ) db
where seqnum = 1;

答案 1 :(得分:2)

我对你的描述并不是很聪明,但是,使用以下查询可以实现结果

select your_table.*
from your_table 
join
(
  select BlilShortName, max(billversion) bmax
  from your_table
  group by BlilShortName
) t on your_table.billversion = t.bmax and your_table.BlilShortName = t.BlilShortName

根据我的经验,与总是使用顺序扫描的row_number解决方案相比,在某些情况下可能会更快。

表现奖励

由于有关于效率的讨论,我敢于添加简单的测试

IF OBJECT_ID('dbo.GTable', 'U') IS NOT NULL  DROP TABLE dbo.GTable
SELECT TOP 1000000
      NEWID() id, 
      ABS(CHECKSUM(NEWID())) % 100 group_id, 
      ABS(CHECKSUM(NEWID())) % 10000 orderby
 INTO GTable
FROM    sys.sysobjects
CROSS JOIN sys.all_columns

SET STATISTICS TIME on
-- GROUP BY version
select t1.*
from gtable t1
join
    (
      SELECT group_id, max(orderby) gmax
      from gtable
      group by group_id
    ) t2 on t1.group_id = t2.group_id and t1.orderby = t2.gmax

-- WINDOW FUNCTION version
select t.id, t.group_id, t.orderby
from
(
select *, 
       dense_rank() over (partition by group_id order by orderby desc) rn
from gtable 
) t
where t.rn = 1

如果我在我的服务器上运行它,那么GROUP BY版本的性能比窗口函数版本好两倍多。而且,如果我创建索引

CREATE NONCLUSTERED INDEX ix_gtable_groupid_orderby
    ON [dbo].[GTable] (group_id,orderby) INCLUDE (id)

然后性能甚至超过三倍,而窗口函数解决方案的性能是相同的,因为它使用顺序扫描,尽管索引。