Возможные способы получить групповую запись Last / Max в иерархическом запросе? - PullRequest
0 голосов
/ 20 декабря 2010

Предполагая, что у меня есть таблица, подобная этой:

CREATE TABLE user_delegates (
    [id] INT IDENTITY(1,1) NOT NULL,
    [user_from] VARCHAR(10) NOT NULL,
    [user_to] VARCHAR(10) NOT NULL,
    CONSTRAINT [PK_user_delegates] PRIMARY KEY CLUSTERED ([id] ASC),
    CONSTRAINT [UK_user_delegates] UNIQUE ([user_from] ASC)
)

Таким образом, пользователь A имеет право делегировать доступ к своей системе другому пользователю B. Когда он это сделает, он не сможетдоступ к системе больше - пользователь B должен будет «прервать» это делегирование, прежде чем он сможет снова использовать систему ...

НО также учтите, что, если пользователь B делегирует доступ пользователю C, пользователь C также начнет выдавать себя за пользователя A и т. Д.

(я знаю, это похоже на кошмар безопасности - пожалуйста, давайте просто забудем об этом, хорошо?: -))

Также рассмотрим эти записи:

INSERT INTO user_delegates([user_from], [user_to]) values ('ANTHONY', 'JOHN')
INSERT INTO user_delegates([user_from], [user_to]) values ('JOHN', 'JOHN')
INSERT INTO user_delegates([user_from], [user_to]) values ('KARL', 'JOSHUA')
INSERT INTO user_delegates([user_from], [user_to]) values ('JOSHUA', 'PIOTR')
INSERT INTO user_delegates([user_from], [user_to]) values ('PIOTR', 'HANS')

Итак, мне нужно найти last (что означает активное) делегирование для каждого пользователя.

Я пришелк решению, которое я решил не показать здесь (если все не игнорируют меня, что всегда возможно).Все, что я могу сказать, это то, что это довольно длинный ответ, и, безусловно, похоже на использование пушки для уничтожения блох ...

Но как бы вы это сделали?Рассмотрим любое соответствующее расширение SQL Server и обратите внимание, что мы ищем ответ, который был бы элегантным и с хорошей производительностью ...

Кстати, это ожидаемый набор результатов:

id          user_from  user_to   
----------- ---------- ----------
1           ANTHONY    JOHN      
2           JOHN       JOHN      
3           KARL       HANS      
4           JOSHUA     HANS      
5           PIOTR      HANS      

(5 row(s) affected)

И заранее спасибо!

1 Ответ

1 голос
/ 20 декабря 2010
WITH    q (user_initial, user_from, user_to, link) AS
        (
        SELECT  user_id, user_id, user_id, link
        FROM    users
        UNION ALL
        SELECT  user_initial, q.user_to, ud.user_to, link + 1
        FROM    q
        JOIN    user_delegates ud
        ON      ud.user_from = q.user_to
        )
SELECT  *
FROM    (
        SELECT  *, ROW_NUMBER() OVER (PARTITION BY user_initial ORDER BY link DESC) rn
        FROM    q
        )
WHERE   rn = 1
...