Преобразование последовательных чисел в один столбец с отсутствующими значениями в SQL - PullRequest
1 голос
/ 28 марта 2019

У меня есть список идентификаторов образцов для сайта в формате: Sitename, Sample Number, так что для данного сайта существует n номеров образцов.Например, данные могут быть:

site1 | 1
site1 | 2

и т. Д. С произвольным n.

Используя следующий пример в качестве аналогичного примера, эти данные ниже получат ответ из последнего оператора select:

CREATE TABLE #SiteWithId(SiteId VARCHAR(50), SampleNumber INT)

INSERT INTO #SiteWithId
(
    SiteId,
    SampleNumber
)
values 
(   'test', -- SiteId - varchar(50)
    1  -- SampleNumber - int
    ),
    ('test',2),
    ('test',3),
    ('test',4),
    ('test',6),
    ('test',7)

    SELECT * FROM #SiteWithId
    DROP TABLE #SiteWithId
    --the answer
    SELECT 'test', '1-4,6-7'

Обратите внимание, что отсутствующий элемент создает разрыв в окончательном ответе.

Я знаю, что могу перебрать набор данных в C # и создать такой элемент.Но кто-нибудь знает, чтобы создать такое значение, используя только SQL, чтобы я мог просто выложить необходимые значения для отчета?Я думаю, что я мог бы также сделать цикл в SQL, но я боюсь, что это будет невозможно масштабировать, поскольку это не совсем то, что SQL для этого.

Есть ли лучший способ сделать это, кроме цикла в SQLили c #?

1 Ответ

5 голосов
/ 28 марта 2019

Вот решение, которое опирается на оконные функции. Разница между SampleNumber записи и ее ROW_NUMBER() в группах записей, имеющих одинаковый SiteName, дает вам группу, к которой она принадлежит. Затем внешний запрос агрегирует каждую группу:

SELECT SiteName, CONCAT(MIN(SampleNumber), '-', MAX(SampleNumber)) SampleRange
FROM (
    SELECT 
        SiteName, 
        SampleNumber, 
        ROW_NUMBER() OVER(PARTITION BY SiteName ORDER BY SampleNumber) rn
    FROM mytable
) x
GROUP BY SiteName, (SampleNumber - rn)

Демонстрация на DB Fiddle :

Пример данных:

SiteName | SampleNumber
:------- | -----------:
site1    |            1
site1    |            2
site1    |            3
site1    |            5
site1    |            6
site1    |            8
site1    |            9
site1    |           10

Результаты:

SiteName | SampleRange
:------- | :----------
site1    | 1-3        
site1    | 5-6        
site1    | 8-10       

Если вы хотите объединить все диапазоны каждого сайта в одну запись, вы можете добавить другой уровень агрегирования и использовать STRING_AGG() (доступно с SQL Server 2017):

SELECT SiteName, STRING_AGG(SampleRange,',') SampleRange
FROM (
    SELECT SiteName, CONCAT(MIN(SampleNumber), '-', MAX(SampleNumber)) SampleRange
    FROM (
        SELECT 
            SiteName, 
            SampleNumber, 
            ROW_NUMBER() OVER(PARTITION BY SiteName ORDER BY SampleNumber) rn
        FROM mytable
    ) x
    GROUP BY SiteName, (SampleNumber - rn)
) y
GROUP BY SiteName

Демо

SiteName | SampleRange 
:------- | :-----------
site1    | 1-3,5-6,8-10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...