Простой SQL: Как рассчитать уникальные, непрерывные числа для дубликатов в наборе? - PullRequest
3 голосов
/ 19 мая 2011

Допустим, я создаю таблицу с полем int Page, int Section и int ID, где поле страницы варьируется от 1 до 8, а поле раздела - от 1 до 30 для каждой страницы.Теперь предположим, что две записи имеют дубликаты страницы и раздела.Как можно изменить нумерацию этих двух записей, чтобы последовательность нумерации страниц и разделов была непрерывной?

select page, section
from #fun
group by page, section having count(*) > 1

показывает дубликаты:

page 1 section 3
page 2 section 3

стр. 1, раздел 4 и стр. 2, раздел 4не хватает.Есть ли способ без использования курсора для поиска и перенумерации позиций в SQL 2000, который не поддерживает Row_Number ()?

Это значение ниже, конечно, дает точно такое же число, как в разделе:

select page, section,
    (select count(*) + 1 
     from #fun b 
     where b.page = a.page and b.section < a.section) as rownum
from #fun a

Я мог бы создать сводную таблицу со значениями от 1 до 100, но к чему бы я присоединился?

Что я хочу сделать, это примерно так:

update p set section = (expression that gets 4)
from #fun p
where (expression that identifies duplicate sections by page)

Ответы [ 2 ]

1 голос
/ 19 мая 2011

У меня нет сервера 2000, чтобы проверить это, но я думаю, что он должен работать.

Создание тестовых таблиц / данных:

CREATE TABLE #fun
(Id INT IDENTITY(100,1)
,page INT NOT NULL
,section INT NOT NULL
)


INSERT #fun (page, section)
SELECT 1,1
UNION ALL SELECT 1,3    UNION ALL SELECT 1,2
UNION ALL SELECT 1,3    UNION ALL SELECT 1,5
UNION ALL SELECT 2,1    UNION ALL SELECT 2,2
UNION ALL SELECT 2,3    UNION ALL SELECT 2,5
UNION ALL SELECT 2,3

Теперь обработка:

-- create a worktable
CREATE TABLE #fun2
(Id INT IDENTITY(1,1)
,funId INT
,page INT NOT NULL
,section INT NOT NULL
)

-- insert data into the second temp table ordered by the relevant columns
-- the identity column will form the basis of the revised section number
INSERT  #fun2 (funId, page, section)
SELECT  Id,page,section
FROM    #fun
ORDER BY page,section,Id

-- write the calculated section value back where it is different
UPDATE  p
SET     section = y.calc_section
FROM    #fun AS p 
JOIN
        (
            SELECT  f2.funId, f2.id - x.adjust calc_section
            FROM    #fun2 AS f2
            JOIN    (
                        -- this subquery is used to calculate an offset like
                        -- PARTITION BY in a 2005+ ROWNUMBER function
                        SELECT MIN(Id) - 1 adjust, page
                        FROM #fun2
                        GROUP BY page
                    ) AS x
            ON      f2.page = x.page
        ) AS y
ON      p.Id = y.funId
WHERE   p.section <> y.calc_section


SELECT * FROM #fun order by page, section
0 голосов
/ 19 мая 2011

Отказ от ответственности : У меня нет SQL Server для тестирования.

Если я правильно вас понимаю, если вы знали ROW_NUMBER ваших #fun записей, разделенных на (page, section) дубликатов, вы можете использовать это относительное ранжирование для увеличения "раздела":

    UPDATE p
       SET section = section + (rownumber - 1)
      FROM #fun AS p
INNER JOIN ( -- SELECT id, ROW_NUMBER() OVER (PARTITION BY page, section) ...
            SELECT id, COUNT(1) AS rownumber
              FROM #fun a
         LEFT JOIN #fun b
                   ON a.page = b.page AND a.section = b.section AND a.id <= b.id
          GROUP BY a.id, a.page, a.section) d
            ON p.id = d.id
      WHERE rownumber > 1

Это не относится к случаю, когда количество дубликатов заставит вас превысить верхний предел, равный 30. Это также может создать новых дубликатов, если, если разделы с более высокими номерами на странице уже существуют, то есть один экземпляр (pg 1, sec 3) становится (pg 1, sec 4), который уже существовал, но вы можете запускать UPDATE несколько раз, пока не будет дубликатов.

А затем добавить уникальный индекс на (page, section).

...