Как выбрать максимальное значение из n числа связанных кортежей - PullRequest
1 голос
/ 13 октября 2011

Я пытаюсь выбрать максимальный идентификатор из любого числа n связанных кортежей в базе данных sql server - мы пишем скрипт обновления для некоторых наборов данных в приложении, и нам нужно знать, на чем основано максимальное доступное обновлениекакая версия данных в настоящее время.Например, используя следующую упрощенную таблицу «версии»:

oldVersionId   newVersionId
1              2
2              3
3              4
10             11

Мы знаем, что мы версия 1, и хотим получить самую высокую версию, которую мы можем обновить;который в этом случае вернул бы 4, а не 11. У нас может быть 0-n доступных для обновления версий в любой момент времени.Я не sql wiz, и мог бы подумать только о том, чтобы запросить с использованием переменного числа связанных цепочек:

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

Но это не пронумерованный поиск, и он не вернется правильно, если количество элементовбольше или меньше, чем данное.Способен ли sql выполнить такой запрос, и какие элементы / ключевые слова мне нужно искать, чтобы написать один?

Решение:

Вы узнаете что-то новое каждый день -Мне нужен был гибрид двух ответов.Оказывается, что sql может запрашивать набор данных, используя древовидную связь между дочерними и родительскими объектами, с которой мне гораздо удобнее работать на языках OO.

На сервере sql вы можете настроить рекурсивный обход по дереву с использованием таблицы с псевдонимами.,Вам нужен якорь, а затем рекурсивный бит.Первый вызов - это привязка, я могу использовать любое значение в таблице или список значений и т. Д. Второй вызов 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

Ответы [ 4 ]

2 голосов
/ 13 октября 2011

Вот решение с 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(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)
0 голосов
/ 13 октября 2011

Вам фактически нужно идентифицировать последний узел в связанном списке - мне кажется, вам лучше всего использовать рекурсивные функции 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
0 голосов
/ 13 октября 2011

Ваша проблема почти такая же, как и Как получить родительского элемента от дочернего в SQL SERVER 2005

Я думаю, что тот же CTE будет работать для вас.

0 голосов
/ 13 октября 2011

Эту проблему можно решить, написав рекурсивные запросы для обхода рекурсивных иерархий в таблице.

http://www.mssqltips.com/sqlservertip/1520/recursive-queries-using-common-table-expressions-cte-in-sql-server/

http://msdn.microsoft.com/en-us/library/ms186243.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...