【问题标题】:SQL server select oldest records where width column is within specific range of each otherSQL Server选择宽度列在彼此特定范围内的最旧记录
【发布时间】:2015-08-20 01:33:21
【问题描述】:

有如下格式的表格

   vend_plate_no |  width       |   received_date
   --------------|--------------|---------------    
   PE9334-1      |  60          |   March 16, 2015
   PE9334-2      |  60          |   March 16, 2015
   PE9334-3      |  60          |   March 16, 2015
   PE9545-1      |  60          |   March 20, 2015
   PE9545-2      |  60          |   March 20, 2015
   PE9530-1      |  60.375      |   March 10, 2015
   PE9530-2      |  60.375      |   March 10, 2015
   PE9530-3      |  60.375      |   March 10, 2015
   DP5603-5      |  61.3        |   April 29, 2015
   PF2207-1      |  61.375      |   May 26, 2015
   PF2207-2      |  61.375      |   May 26, 2015
   PF2207-3      |  61.375      |   May 26, 2015
   PF2207-4      |  61.375      |   May 26, 2015
   PF2208-1      |  61.375      |   May 26, 2015
   PF2208-2      |  61.375      |   May 26, 2015
   PF2208-3      |  61.375      |   May 26, 2015
   PF2208-4      |  61.375      |   May 26, 2015

我可以选择宽度在 y 英寸以内的最早的 x 条记录吗?我无法指定底部和顶部宽度值,因为我的数据集的宽度值比我上面提供的示例数据集多得多,所以我必须能够搜索整个宽度列(从最旧的记录开始),直到找到宽度相差 0.25 英寸或 0.25 英寸的特定行数。例如,我可以选择 9 个最旧的记录,它们之间的宽度在 0.25 英寸以内吗?鉴于这些条件,使用上述数据集的结果集如下:

vend_plate_no | width       |   received_date
--------------|-------------|---------------    
DP5603-5      |  61.3       |   April 29, 2015
PF2207-1      |  61.375     |   May 26, 2015
PF2207-2      |  61.375     |   May 26, 2015
PF2207-3      |  61.375     |   May 26, 2015
PF2207-4      |  61.375     |   May 26, 2015
PF2208-1      |  61.375     |   May 26, 2015
PF2208-2      |  61.375     |   May 26, 2015
PF2208-3      |  61.375     |   May 26, 2015
PF2208-4      |  61.375     |   May 26, 2015

但是,如果我选择 5 个最旧的记录,它们之间的宽度在 0.25 英寸以内,那么使用本文顶部数据集的结果集将是:

vend_plate_no | width        |  received_date
--------------|--------------|---------------   
PE9334-1      | 60           |  March 16, 2015
PE9334-2      | 60           |  March 16, 2015
PE9334-3      | 60           |  March 16, 2015
PE9545-1      | 60           |  March 20, 2015
PE9545-2      | 60           |  March 20, 2015

这可能吗?

【问题讨论】:

  • 到目前为止你尝试了什么??
  • 你的宽度列的单位是什么??英寸?
  • 同一vend_plate_no可以有多条记录吗?
  • vend_plate_no 列值对于所有记录都是唯一的。是的,宽度列以英寸为单位,最多保留 3 位小数,四舍五入到千分之一英寸。

标签: sql sql-server


【解决方案1】:

我认为这会产生您想要的结果。希望我已将其分解为足够多的 CTE,以便您可以在这里看到我的思维过程。

declare @t table (vend_plate_no varchar(19), width decimal(18,3), received_date date)
insert into @t (vend_plate_no,width,received_date) values
('PE9334-1',60,'20150316'),('PE9334-2',60,'20150316'),('PE9334-3',60,'20150316'),
('PE9545-1',60,'20150320'),('PE9545-2',60,'20150320'),('PE9530-1',60.375,'20150310'),
('PE9530-2',60.375,'20150310'),('PE9530-3',60.375,'20150310'),('DP5603-5',61.3  ,'20150429'),
('PF2207-1',61.375,'20150526'),('PF2207-2',61.375,'20150526'),('PF2207-3',61.375,'20150526'),
('PF2207-4',61.375,'20150526'),('PF2208-1',61.375,'20150526'),('PF2208-2',61.375,'20150526'),
('PF2208-3',61.375,'20150526'),('PF2208-4',61.375,'20150526')

declare @SetSize int
declare @Tolerance decimal(18,3)

select @SetSize = 9, @Tolerance = 0.25

;With Numbered as (
    select *,ROW_NUMBER() OVER (ORDER BY received_date) rn
    from @t
), SetNumbers as (
    select 1 as nn union all select nn+1
    from SetNumbers where nn < @SetSize
), Groups as (
    select *,(rn - nn) + 1 as GroupNumber
    from Numbered cross join SetNumbers
), Collected as (
    select COUNT(*) as cnt,GroupNumber,MIN(width) as minWidth,MAX(width) as MaxWidth
    from Groups group by GroupNumber
    having COUNT(*) >= @SetSize and MAX(width) - MIN(width) <= @Tolerance
), Earliest as (
    select top 1 GroupNumber from Collected order by GroupNumber
)
select vend_plate_no,width,received_date
from
    Groups g
        inner join
    Earliest e
        on g.GroupNumber = e.GroupNumber

也就是说,Numbered 首先将行号分配给行,以便我们可以轻松识别组。 SetNumbers 生成从1@SetSize 的数字集。

然后我们将这两个 CTE 连接到 Groups 中并生成 GroupNumber 值 - 这可能是最棘手的部分。 GroupNumber 本质上是行的行号 (rn),当前行可能是集合的一部分,以满足要求。

用这些 GroupNumbers 武装自己后,我们现在可以基于这些 (Collected) 组合行,并询问自己(通过 HAVING)该特定行组是否满足要求。

最后,我们剥离最早的此类匹配组 (Earliest) 并将其与 Groups 集合组合回来,该集合是一组仍包含感兴趣的原始列的行。

结果:

vend_plate_no       width                                   received_date
------------------- --------------------------------------- -------------
DP5603-5            61.300                                  2015-04-29
PF2207-1            61.375                                  2015-05-26
PF2207-2            61.375                                  2015-05-26
PF2207-3            61.375                                  2015-05-26
PF2207-4            61.375                                  2015-05-26
PF2208-1            61.375                                  2015-05-26
PF2208-2            61.375                                  2015-05-26
PF2208-3            61.375                                  2015-05-26
PF2208-4            61.375                                  2015-05-26

如果我们将@SetSize 更改为 5,结果:

vend_plate_no       width                                   received_date
------------------- --------------------------------------- -------------
PE9334-1            60.000                                  2015-03-16
PE9334-2            60.000                                  2015-03-16
PE9334-3            60.000                                  2015-03-16
PE9545-1            60.000                                  2015-03-20
PE9545-2            60.000                                  2015-03-20

【讨论】:

  • 哇,达米安,你成功了!非常感谢,解决了一个巨大的问题并提供了大量的教育!这很好用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多