如何从n个链接元组中选择最大值

发布于 2024-12-09 20:21:36 字数 1366 浏览 1 评论 0原文

我正在尝试从 sql server 数据库中的任何 n 个链接元组中选择最大 id - 我们正在为应用程序中的某些数据集编写升级脚本,并且需要知道基于数据的最高可用升级是什么目前版本是。例如,使用以下简化表“版本”:

oldVersionId   newVersionId
1              2
2              3
3              4
10             11

我们知道我们是版本 1,并且希望获得可以升级到的最高版本;在这种情况下将返回 4,而不是 11。在任何给定时间,我们都可以有 0-n 个可用的可升级版本。我不是一个 sql 专家,只能考虑使用可变数量的链式选择进行查询:

select newVersion from versions where oldVersionId = (select newVersion from versions where oldVersionId = 1)

但它不是一个 n 编号的搜索,并且如果元素数量大于或小于给定的数量,则不会正确返回。 sql 是否能够执行这样的查询,我应该考虑哪些元素/关键字来编写查询?

解决方案:

你每天都会学到新东西 - 我需要这两个答案的混合。事实证明,sql 可以使用树状子/父链接来查询数据集,我在 OO 语言中更习惯这种链接。

在 sql server 中,您可以使用别名表设置递归树遍历调用。您需要一个锚点,然后是递归位。第一个调用是锚点,我可以使用表中的任何值或值列表等。第二个 select 调用只是说使用表的其余部分进行扫描。

语法如下:

--Create the new alias (s)
;with s (oldVersionId, newVersionId) as 
(
    --set up the anchor node, 
    select oldVersionId, newVersionId from @t
    where oldVersionId = 1

    -- join it to the rest of the table, denoting that we only want nodes 
    -- where the old version is represented as a new version later
    union all
    select t.oldVersionId, t.newVersionId from @t as t
    inner join s on t.oldVersionId = s.newVersionId
)
--Return the max value from the nodes I collected
select max(s.newVersionId) from s

I'm trying to select the max id from any n number linked tuples in a sql server db - we are writing an upgrade script for some data sets within an app, and need to know what the highest upgrade available is based on what the data's version is currently. For example, using the following simplified table 'versions':

oldVersionId   newVersionId
1              2
2              3
3              4
10             11

We know we are version 1, and want to get the highest version out there that we can upgrade to; which would return 4 in this case, and not 11. We can have 0-n number of upgradable versions available at any given time. I'm not an sql wiz, and could only think to query using a variable number of chained selects:

select newVersion from versions where oldVersionId = (select newVersion from versions where oldVersionId = 1)

But it not an n numbered search, and won't return correctly if the number of elements is greater or less then the given. Is sql capable of performing such a query, and what elements / keywords should I be looking at to write one?

Solution:

You learn something new every day - I needed a hybrid of the two answers. Turns out sql can query a dataset using the tree-like child/parent linking that I'm way more comfortable with in OO languages.

In sql server you can set up a recursive tree walking call using a aliased table. You need an anchor and then the recursive bit. The first call is the anchor, I can use any value in the table, or a list of values, etc. The second select call just says to use the rest of the table to scan against.

Here is the syntax:

--Create the new alias (s)
;with s (oldVersionId, newVersionId) as 
(
    --set up the anchor node, 
    select oldVersionId, newVersionId from @t
    where oldVersionId = 1

    -- join it to the rest of the table, denoting that we only want nodes 
    -- where the old version is represented as a new version later
    union all
    select t.oldVersionId, t.newVersionId from @t as t
    inner join s on t.oldVersionId = s.newVersionId
)
--Return the max value from the nodes I collected
select max(s.newVersionId) from s

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

眼眸里的那抹悲凉 2024-12-16 20:21:36

这是使用 CTE 的解决方案 - 当我们在 oldVersionId = newVersionId 上有下一个匹配时循环遍历数据:

declare @t table (
    oldVersionId int,
    newVersionId int )

insert into @t values (1,2)
insert into @t values (2,3)
insert into @t values (3,4)
insert into @t values (10,11)
insert into @t values (11,12)
insert into @t values (14,15)

declare @startVer int
set @startVer = 1

;with s (oldVersionId, newVersionId) as 
(
    select top 1 oldVersionId, newVersionId from @t
    where oldVersionId = @startVer
    union all
    select t.oldVersionId, t.newVersionId from @t as t
    inner join s on t.oldVersionId = s.newVersionId
)
select max(s.newVersionId) 
from s
option (maxrecursion 0)

这是没有 CTE 的解决方案 - 搜索 newVersionId 等于 1(第一个版本)的最后一条记录加上对此的增量更新的总和版本:

select max(t1.newVersionId)
from @t t1
where t1.oldVersionId >= @startVer
and t1.newVersionId = @startVer + (
    select sum(newVersionId - oldVersionId) 
    from @t 
    where 
        oldVersionId >= @startVer and 
        oldVersionId < t1.newVersionId)

Here is the solution with CTE - loop thru data while we have next match on oldVersionId = newVersionId:

declare @t table (
    oldVersionId int,
    newVersionId int )

insert into @t values (1,2)
insert into @t values (2,3)
insert into @t values (3,4)
insert into @t values (10,11)
insert into @t values (11,12)
insert into @t values (14,15)

declare @startVer int
set @startVer = 1

;with s (oldVersionId, newVersionId) as 
(
    select top 1 oldVersionId, newVersionId from @t
    where oldVersionId = @startVer
    union all
    select t.oldVersionId, t.newVersionId from @t as t
    inner join s on t.oldVersionId = s.newVersionId
)
select max(s.newVersionId) 
from s
option (maxrecursion 0)

And here is solution without CTE - search for the last record which has newVersionId equals to 1 (1st version) plus the sum of imcremental updates to this version:

select max(t1.newVersionId)
from @t t1
where t1.oldVersionId >= @startVer
and t1.newVersionId = @startVer + (
    select sum(newVersionId - oldVersionId) 
    from @t 
    where 
        oldVersionId >= @startVer and 
        oldVersionId < t1.newVersionId)
攒眉千度 2024-12-16 20:21:36

您实际上需要识别链接列表中的最终节点 - 在我看来,您最好的选择是使用 CTE 的递归功能来获取“最大”版本,但我对 CTE 不够熟悉,无法获得它在职的。

下面得到了正确的答案,但只是因为我知道这个特定的虚拟表事先需要多少个链接;因此,并不理想。

CREATE TABLE #temp (
oldversionID SMALLINT,
newversionID SMALLINT )

INSERT INTO #temp
VALUES (1,2)
INSERT INTO #temp
VALUES (2,3)
INSERT INTO #temp
VALUES (3,4)
INSERT INTO #temp
VALUES (10,11);


select t1.oldversionID, t3.newversionID from #temp t1
inner join #temp t2
on t1.newversionId = t2.oldversionID
inner join #temp t3
on t2.newversionId = t3.oldversionID

You effectively need to identify the final node in a linked list--seems to me your best bet would be to use the recursive features of CTEs to get to your 'max' version, but I'm not familiar enough with CTEs to get it working.

The following gets to the right answer, but only because I know how many links this particular dummy table will require beforehand; thus, not ideal.

CREATE TABLE #temp (
oldversionID SMALLINT,
newversionID SMALLINT )

INSERT INTO #temp
VALUES (1,2)
INSERT INTO #temp
VALUES (2,3)
INSERT INTO #temp
VALUES (3,4)
INSERT INTO #temp
VALUES (10,11);


select t1.oldversionID, t3.newversionID from #temp t1
inner join #temp t2
on t1.newversionId = t2.oldversionID
inner join #temp t3
on t2.newversionId = t3.oldversionID
安静 2024-12-16 20:21:36

您的问题与 How让父级在 SQL SERVER 2005 中获得子级

我认为相同的 CTE 也适合您。

Your problem is pretty much same as How to get the parent given a child in SQL SERVER 2005

I think same CTE will work for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文