Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10)
Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
Спасибо
Re: Последовательная выборка
От:
Аноним
Дата:
05.06.09 08:15
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10) А>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора? А>Спасибо
Здравствуйте, Аноним, Вы писали:
А>>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10) А>>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
Реально — только параллельную...
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[3]: Последовательная выборка
От:
Аноним
Дата:
05.06.09 08:49
Оценка:
Здравствуйте, DarkMaster, Вы писали:
DM>Здравствуйте, Аноним, Вы писали:
А>>>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 1 и 10) А>>>Необходимо сгенерить последовательную выборку. Реально ли это сделать без цикла или курсора?
DM>Реально — только параллельную...
+1.
Для последовательной нужно еще третье число на входе.
Здравствуйте, Аноним, Вы писали:
А>Доброго времени суток. Есть такая задача: на входе в процедуру два числа(к примеру 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>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
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" придётся задавать сразу очень большое число, чтобы покрыть любое необходимое значение.