SQL按版本号检索不同的行

时间:2014-08-29 01:52:54

标签: sql sql-server

我正在尝试在MSSQL中创建一个已保存的视图,该视图返回已接受的提案列表。我遇到的问题是,如果提案有多个版本,它会将所有行返回为已接受,即使它实际上只是最新版本有效。

每个提案记录的报价ID不同,但报价编号和名称相同。确定我们想要返回哪个Quote ID记录的方法是具有最新版本号的提案。只有少数引号具有版本号,大多数引号都是唯一的。

我不知道我是否可以通过分组数据来实现这一目标,因为我想收集许多字段(除了下面列出的字段),其中主要包含文本。

以下是我所指的数据格式的示例

Quote ID   |   Quote Number   |   Quote Name     | Version |

i3hfkdkj   |   101   |   John Smith Residence    |    1    |
fheifjdh   |   102   |   Big Apple Food Service  |    1    |
kdjfnf98   |   103   |   Starbucks Coffee        |    1    |
3498fhkd   |   101   |   John Smith Residence    |    2    |
jfh3bfi3   |   104   |   Susan Jane Apartment    |    1    |
9834jfkd   |   101   |   John Smith Residence    |    3    |

理想情况下,我希望查询只返回以下行

fheifjdh   |   102   |   Big Apple Food Service  |    1    |
kdjfnf98   |   103   |   Starbucks Coffee        |    1    |
jfh3bfi3   |   104   |   Susan Jane Apartment    |    1    |
9834jfkd   |   101   |   John Smith Residence    |    3    |

非常感谢您的帮助

以下是我当前保存的视图的语法,该视图正常工作,但上面列出的内容除外。

SELECT
dbo.Quote_Main.quote_readable_id,
dbo.Quote_Main.quote_name,
dbo.Quote_Main.account_name,
dbo.Quote_Main.contact_name,
dbo.Quote_Main.quote_status,
dbo.Quote_Main.delivered_date,
dbo.Quote_Customers.first_name,
dbo.Quote_Customers.last_name,
dbo.Quote_Customers.customer_source,
dbo.Quote_Main.idCRM_opportunity,
dbo.Quote_Main.idQuote_Main,
dbo.Quote_Items.item_notes_html AS QuoteScope,
dbo.Quote_Items.item_notes,
dbo.Quote_Main.version

FROM
dbo.Quote_Items
LEFT JOIN dbo.Quote_Main ON dbo.Quote_Items.idQuote_Main = dbo.Quote_Main.idQuote_Main
LEFT JOIN dbo.Quote_Customers ON dbo.Quote_Main.idQuote_Main = dbo.Quote_Customers.idQuote_Main
WHERE
dbo.Quote_Items.long_description = 'Proposal Scope' AND
dbo.Quote_Main.quote_status = 'Won' AND
dbo.Quote_Customers.usage_type = 'Quote To'

4 个答案:

答案 0 :(得分:2)

一种方法是使用not exists

select p.*
from proposals p
where not exists (select 1
                  from proposals p2
                  where p2.QuoteNumber = p.QuoteNumber and p2.version > p.version
                 );

您没有指定您正在使用的数据库,这应该基本上适用于视图的所有数据库。

编辑:

只需使用CTE:

with proposals as (
      <your query here>
     )
select p.*
from proposals p
where not exists (select 1
                  from proposals p2
                  where p2.QuoteNumber = p.QuoteNumber and p2.version > p.version
                 );

我会首先运行它以查看它是否具有合理的性能。如果没有,可能存在优化的余地。

答案 1 :(得分:1)

如果您使用的是SQL Server,则可以使用row_number()

select * 
from (
    select *, 
        row_number() over (partition by [Quote Number] order by Version desc) [rn]
    from Quotes
) x
where x.rn=1

这会为每一行分配一个数字 - 该数字按版本排序(降序),并为每个报价编号重置。子查询的结果如下所示:

Quote ID   | Quote#  |   Quote Name              | Version |  rn   |

i3hfkdkj   |   101   |   John Smith Residence    |    1    |   3   |
fheifjdh   |   102   |   Big Apple Food Service  |    1    |   1   |
kdjfnf98   |   103   |   Starbucks Coffee        |    1    |   1   |
3498fhkd   |   101   |   John Smith Residence    |    2    |   2   |
jfh3bfi3   |   104   |   Susan Jane Apartment    |    1    |   1   |
9834jfkd   |   101   |   John Smith Residence    |    3    |   1   |

然后我们只是过滤rn=1

子查询是必要的,因为row_number()不能直接在where子句中使用。

答案 2 :(得分:1)

根据要求,这是一个应用于答案中添加的查询的后续示例。

此查询的整体结构已从原来的更改中通过移动表dbo.Quote_Main向上优先,相反dbo.Quote_Items向下。

SELECT
      QM.quote_readable_id
    , QM.quote_name
    , QM.account_name
    , QM.contact_name
    , QM.quote_status
    , QM.delivered_date
    , QC.first_name
    , QC.last_name
    , QC.customer_source
    , QM.idCRM_opportunity
    , QM.idQuote_Main
    , QI.item_notes_html AS QuoteScope
    , QI.item_notes
    , QM.version

FROM dbo.Quote_Main QM
      INNER JOIN dbo.Quote_Customers
                  ON QM.idQuote_Main = QC.idQuote_Main
      LEFT OUTER JOIN (
                        SELECT
                              idQuote_Main
                            , item_notes_html
                            , item_notes
-- note 1
                            , ROW_NUMBER() OVER (PARTITION BY idQuote_Main
                                                 ORDER BY qi_version DESC) AS RN
-- note 2
                        WHERE long_description = 'Proposal Scope'
                        FROM dbo.Quote_Items
                      ) QI
                        ON QM.idQuote_Main = QI.idQuote_Main
                              AND QI.RN = 1
WHERE QM.quote_status = 'Won'
    AND QC.usage_type = 'Quote To'
;
  1. 此字段未指定,因此猜到qi_version,使用正确的字段
  2. 可能是where子句条件,或者可能在后续连接条件中使用,放置的影响会改变结果,所以请测试两者以选择最合适的选项。

答案 3 :(得分:-1)

只是堆积了一点

select quoteid,quotenum,quotename,ver from quotes q
where quotenum||ver = (select max(quotenum||ver) from quotes q2
                        where q.quotenum=q2.quotenum)