Последовательная выборка
От: Аноним  
Дата: 05.06.09 08:09
Оценка:
Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)
Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
Спасибо
Re: Последовательная выборка
От: Аноним  
Дата: 05.06.09 08:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)

А>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
А>Спасибо

Забыл добавить — средствами MSSQL 2005
Re[2]: Последовательная выборка
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 05.06.09 08:36
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)

А>>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?

Реально — только параллельную...
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[3]: Последовательная выборка
От: Аноним  
Дата: 05.06.09 08:49
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>Здравствуйте, Аноним, Вы писали:


А>>>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)

А>>>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?

DM>Реально — только параллельную...


+1.
Для последовательной нужно еще третье число на входе.
Re: Последовательная выборка
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 05.06.09 09:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)

А>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
А>Спасибо

Конечно реально, при наличии CTE SQL полн по тьюрингу.

WITH seq(x) as
(
select 1 as x
UNION ALL
select x+1 from seq where x<10
)
select distinct * from seq

Вопрос только в быстродейтсвии.
Re[2]: Последовательная выборка
От: Аноним  
Дата: 05.06.09 11:12
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, Аноним, Вы писали:


А>>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)

А>>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
А>>Спасибо

G>Конечно реально, при наличии CTE SQL полн по тьюрингу.


G>
G>WITH seq(x) as
G>(
G>select 1 as x
G>UNION ALL
G>select x+1 from seq where x<10
G>)
G>select distinct * from seq
G>

G>Вопрос только в быстродейтсвии.


Спасибо, это то что нужно.
Re[2]: Последовательная выборка
От: avpavlov  
Дата: 08.06.09 10:28
Оценка: 1 (1)
G>
G>WITH seq(x) as
G>(
G>select 1 as x
G>UNION ALL
G>select x+1 from seq where x<10
G>)
G>select distinct * from seq
G>

G>Вопрос только в быстродейтсвии.

Отваливается, если требуется больше 100 чисел.

В своё время писал такое (при константных интервалах работает даже на MS SQL 2000).

IF EXISTS (SELECT * FROM sysobjects WHERE name = N'GetNumberInterval')
    DROP FUNCTION GetNumberInterval
GO

CREATE FUNCTION
    GetNumberInterval(@minBound INT, @maxBound INT)
RETURNS
    @number_interval TABLE (num INT)
AS BEGIN

    DECLARE @countToReturn INT
    SET @countToReturn = @maxBound - @minBound + 1
    
    DECLARE @iterations INT
    SET @iterations = CASE WHEN @countToReturn <= 0 THEN 1 ELSE CAST(CEILING(LOG10(@countToReturn)) AS INT) END
    
    INSERT 
        @number_interval
    VALUES 
        (0+@minBound)

    DECLARE @i INT
    SET @i = 0
    WHILE @i < @iterations BEGIN
        INSERT 
            @number_interval
        SELECT  
            (ni.num-@minBound)*10 + d.num + @minBound
        FROM 
            @number_interval ni 
            CROSS JOIN (
                SELECT 0 num
                UNION SELECT 1 
                UNION SELECT 2 
                UNION SELECT 3 
                UNION SELECT 4 
                UNION SELECT 5
                UNION SELECT 6
                UNION SELECT 7
                UNION SELECT 8
                UNION SELECT 9
            ) d
        WHERE
            (ni.num-@minBound)*10 + d.num + @minBound <= @maxBound
            AND (
                (
                    @i = 0 AND d.num > 0
                ) OR (
                    @i > 0 AND (ni.num-@minBound) >= POWER(10, @i-1)
                )
            )
    
        SET @i = @i+1
    END

    RETURN
END
GO

IF EXISTS (SELECT * FROM sysobjects WHERE name = N'GetDateInterval')
    DROP FUNCTION GetDateInterval
GO

CREATE FUNCTION
    GetDateInterval(@minBound DATETIME, @maxBound DATETIME)
RETURNS
    @date_interval TABLE (day DATETIME)
AS BEGIN

    DECLARE @startDateAsInt INT
    DECLARE @endDateAsInt INT

    SET @startDateAsInt = CAST(@minBound AS INT)
    SET @endDateAsInt = CAST(@maxBound AS INT)
    
    INSERT 
        @date_interval
    SELECT 
        CAST(num AS DATETIME) 
    FROM 
        dbo.GetNumberInterval(@startDateAsInt, @endDateAsInt) 

    RETURN
END
GO

SELECT * from dbo.GetNumberInterval(20, 120) d
SELECT * from GetDateInterval(getdate(), getdate()+10) i
Re[3]: Последовательная выборка
От: avpavlov  
Дата: 08.06.09 10:36
Оценка:
а на MS SQL 2005 соответственно можно уже джойнить динамическое число строк

select
    d1.code
from 
    (
        select 'A' code, 3 count
        union select 'B', 1 
        union select 'C', 2 
    ) d1
    outer apply dbo.GetNumberInterval(1, d1.count) d2 
order by
    d1.code
Re[3]: Последовательная выборка
От: Docker Канада  
Дата: 09.06.09 17:13
Оценка: 1 (1)
Здравствуйте, avpavlov, Вы писали:

G>>
G>>WITH seq(x) as
G>>(
G>>select 1 as x
G>>UNION ALL
G>>select x+1 from seq where x<10
G>>)
G>>select distinct * from seq
G>>

G>>Вопрос только в быстродейтсвии.

A> Отваливается, если требуется больше 100 чисел.


Ну, можно тогда так, и все снова работает:


WITH seq(x) as
(
select 1 as x
UNION ALL
select x+1 from seq where x<100000
)
select distinct * from seq
option (maxrecursion 0)
Re[4]: Последовательная выборка
От: avpavlov  
Дата: 10.06.09 08:37
Оценка:
D>
D>WITH seq(x) as
D>(
D>select 1 as x
D>UNION ALL
D>select x+1 from seq where x<100000
D>)
D>select distinct * from seq
D>option (maxrecursion 0)
D>


Да, так работает, но по сравнению с ф-цией есть недостатки
1) работает медленнее (у меня процентов на 40)
2) требуется не забывать про option (maxrecursion 0). Люди склонны забывать такие мелочи, протестируют на малом числе, в продакшн потом отвалится.
3) Использование WITH и OPTION может стать проблемой если используется какой-нибудь собственный генератор запросов (ну или, например, Hibernate)
4) если требуется генерировать интервал динамически (см. мой второй пример), то в условии "where x<100000" придётся задавать сразу очень большое число, чтобы покрыть любое необходимое значение.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.