powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Повторить строку N раз
17 сообщений из 17, страница 1 из 1
Повторить строку N раз
    #33201025
luminofer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нужно повторить строку из таблицы N раз. N хранится в записи таблицы. Как построить запрос без курсора?
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
drop table #t
drop table #r
create table #t (c1 int, qty int)
insert into #t values ( 1 , 2 )
insert into #t values ( 3 , 4 )
insert into #t values ( 4 , 1 )

create table #r (c1 int)
-- нужно получить: #r
-- 1
-- 1
-- 3
-- 3
-- 3
-- 3
-- 4
-- т.е. выводится столбец c1 qty раз

declare @c int, @q int

declare x cursor for
  select c1,qty from #t 

open x

while ( 1 = 1 ) begin
  fetch next from x into @c, @q
  if (@@fetch_status = - 1 ) break

  declare @i int
  set @i =  0 
  while (@i<@q) begin
    insert into #r
    select @c
    set @i=@i+ 1 
  end 
end

close x
deallocate x

select * from #r

...
Рейтинг: 0 / 0
Повторить строку N раз
    #33201245
LexusR
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
declare @t table  (c1 int, qty int)
insert into @t values ( 1 , 2 )
insert into @t values ( 3 , 4 )
insert into @t values ( 4 , 1 )

select t.c1
from @t t
join master.dbo.spt_values n on (n.number<t.qty)
where type='P'


...
Рейтинг: 0 / 0
Повторить строку N раз
    #33201476
luminofer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
лихо, респект.
но неспортивно.
а если больше 255 записей, еще одну системную табличку искать?
...
Рейтинг: 0 / 0
Повторить строку N раз
    #33201504
Фотография Ray D
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
свою сделать. полезная штука
...
Рейтинг: 0 / 0
Повторить строку N раз
    #33202613
vap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
declare @ind as int
set @ind =  0 
while ( 1  =  1 ) begin
	insert into #r
	select c1 from #t where @ind < qty
	if @@rowcount =  0  break

	set @ind = @ind +  1 
end

select * from #r order by  1 
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Повторить строку N раз
    #39932028
Фотография SIMPLicity_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Тоже искал.
Вот (через рекурсию, MSSQL 2005 и последующие выпуски):

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
declare @Stuff as Table ( Name VarChar(10), Number Int )
insert into @Stuff ( Name, Number ) values ( 'foo', 1 ), ( 'bar', 3 ), ( 'baz', 2 )

select * from @Stuff

; with Repeat ( Name, Number, Counter ) as (
  select Name, Number, 1
    from @Stuff
    where Number > 0
  union all
  select Name, Number, Counter + 1
    from Repeat
    where Counter < Number
  )
select *
  from Repeat
  order by Name, Counter -- Group by name.
  option ( maxrecursion 0 )



( Взято отсюда )

Исходный набор:
NameNumberfoo1bar3baz2

и результат:
NameNumberCounterbar31bar32bar33baz21baz22foo11
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932042
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SIMPLicity_
Вот (через рекурсию, MSSQL 2005 и последующие выпуски):

Как показывает практика, в реальных ситуациях при большой нагрузке и/или при больших объёмах данных рекурсия вносит существенные издержки в выполнение запроса. Для решения такой задачи обычно действуют наиболее тривиальным способом: заводят таблицу-сиквенс с единственным полем, и с индексом по этому полю.

И да, в master..spt_values не 255, а 2048 записей с типом 'P'. Но её не рекомендуется использовать по другим причинам.
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932054
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SIMPLicity_
Вот (через рекурсию, MSSQL 2005 и последующие выпуски):
Если записей в spt_values не хватает, а свою таблицу завести нельзя, можно spt_values скроссджойнить. Но не рекурсию же делать!
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932069
Фотография a_voronin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SIMPLicity_,

Изобретателям велосипедов

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
declare @Stuff as Table ( Name VarChar(10), Number Int )
insert into @Stuff ( Name, Number ) values ( 'foo', 19 ), ( 'bar', 34 ), ( 'baz', 25 )

;
WITH A AS 
(
	SELECT * FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) A(N)
)
select s.* from @Stuff s
CROSS APPLY 
(
	SELECT TOP (s.Number) NULL AS N FROM A A1, A A2, A A3, A A4, A A5, A A6
) n
	
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932089
Alexander Us
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SIMPLicity_,

Как вариант, (если не запрещено) создать SQL CLR функции в отдельной базе, например "Tools", для повседневной жизни.

Вот некоторые, например:
Код: sql
1.
2.
3.
4.
5.
6.
7.
fn_num(@from bigint, @to bigint) --таблица значений от ... до...

fn_Format1(@format nvarchar(4000), @arg0 sql_variant) --фомтатирование строки
...
fn_Format4(@format nvarchar(4000), @arg0 sql_variant, @arg1 sql_variant, @arg2 sql_variant, @arg3 sql_variant)

fn_RoundDateTime(@DateTime datetime, @IntervalType nvarchar(3), @IntervalValue int) RETURNS DATETIME --округление времени




Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace MySQLCLR
{
    public partial class Utils
    {
  
        #region FormatString
        //http://fotiasqlclr.codeplex.com/SourceControl/changeset/view/99885#830436
        //http://www.fotia.co.uk/Blog/2009/05/indispensable-sql-clr-functions.html 
        //
        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
        public static SqlString Format1(SqlString format, object arg0)
        {
            return format.IsNull ? SqlString.Null : string.Format(format.Value, SqlToNetType(arg0));
        }

        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
        public static SqlString Format2(SqlString format, object arg0, object arg1)
        {
            return format.IsNull ? SqlString.Null : string.Format(format.Value, SqlToNetType(arg0), SqlToNetType(arg1));
        }

        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
        public static SqlString Format3(SqlString format, object arg0, object arg1, object arg2)
        {
            return format.IsNull ? SqlString.Null : string.Format(format.Value, SqlToNetType(arg0), SqlToNetType(arg1), SqlToNetType(arg2));
        }

        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
        public static SqlString Format4(SqlString format, object arg0, object arg1, object arg2, object arg3)
        {
            return format.IsNull ? SqlString.Null : string.Format(format.Value, SqlToNetType(arg0), SqlToNetType(arg1), SqlToNetType(arg2), SqlToNetType(arg3));
        }
         
        private static object SqlToNetType(object sqlValue)
        {
            var nullabe = sqlValue as INullable;
            if ((nullabe == null) || (nullabe.IsNull))
                return null;

            if (sqlValue is SqlString)
                return ((SqlString)sqlValue).Value;
            if (sqlValue is SqlInt16)
                return ((SqlInt16)sqlValue).Value;
            if (sqlValue is SqlInt32)
                return ((SqlInt32)sqlValue).Value;
            if (sqlValue is SqlInt64)
                return ((SqlInt64)sqlValue).Value;
            if (sqlValue is SqlSingle)
                return ((SqlSingle)sqlValue).Value;
            if (sqlValue is SqlDouble)
                return ((SqlDouble)sqlValue).Value;
            if (sqlValue is SqlDateTime)
                return ((SqlDateTime)sqlValue).Value;
            if (sqlValue is SqlMoney)
                return ((SqlMoney)sqlValue).Value;
            if (sqlValue is SqlDecimal)
                return ((SqlDecimal)sqlValue).Value;
            if (sqlValue is SqlBoolean)
                return ((SqlBoolean)sqlValue).Value;
            if (sqlValue is SqlByte)
                return ((SqlByte)sqlValue).Value;
            if (sqlValue is SqlGuid)
                return ((SqlGuid)sqlValue).Value;
            if (sqlValue is SqlXml)
                return ((SqlXml)sqlValue).Value;
            return sqlValue;
        }
        #endregion

        #region Datetime
        [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
        public static SqlDateTime RoundDateTime(SqlDateTime Value, SqlString IntervalType, SqlInt32 IntervalValue)
        {
            if (Value.IsNull || IntervalType.IsNull || IntervalType.IsNull)
                return new SqlDateTime();

            String ITyp  = IntervalType.Value.ToUpper();
            DateTime fdy; //first day of year            
            DateTime curDay;
            Int32 diffDays1;
            Int32 diffDays2;

            switch (ITyp)
            {
                case "SE":
                    return new DateTime(Value.Value.Year,  Value.Value.Month, Value.Value.Day, Value.Value.Hour, Value.Value.Minute, Value.Value.Second / IntervalValue.Value * IntervalValue.Value );
                case "MI":
                    return new DateTime(Value.Value.Year, Value.Value.Month, Value.Value.Day, Value.Value.Hour, Value.Value.Minute / IntervalValue.Value * IntervalValue.Value, 0);
                case "HO":
                    return new DateTime(Value.Value.Year, Value.Value.Month, Value.Value.Day, Value.Value.Hour / IntervalValue.Value * IntervalValue.Value, 0, 0);
               
                case "DA":
                case "DA1":
                    fdy = new DateTime(Value.Value.Year, 1, 1);
                    curDay = new DateTime(Value.Value.Year, Value.Value.Month, Value.Value.Day);
                    diffDays1 = (Int32)curDay.Subtract(fdy).TotalDays;
                    diffDays2 = diffDays1 /  IntervalValue.Value * IntervalValue.Value;
                    return fdy.AddDays(diffDays2);

                case "DA2":                   
                    fdy = new DateTime(Value.Value.Year, 1, 1);
                    DateTime mo1wo;
                    if (fdy.DayOfWeek==DayOfWeek.Sunday)
                        mo1wo=fdy.AddDays(-6);
                    else
                       mo1wo = fdy.AddDays(-1*((int)fdy.DayOfWeek - 1));
 
                    curDay = new DateTime(Value.Value.Year, Value.Value.Month, Value.Value.Day);
                    diffDays1 = (Int32)curDay.Subtract(mo1wo).TotalDays;
                    diffDays2 = diffDays1 / IntervalValue.Value * IntervalValue.Value;
                    return mo1wo.AddDays(diffDays2);          
                              
                case "MO":
                    return new DateTime(Value.Value.Year, (Value.Value.Month-1) / IntervalValue.Value * IntervalValue.Value+1, 1, 0, 0, 0);
                case "YE":
                    return new DateTime(Value.Value.Year / IntervalValue.Value * IntervalValue.Value, 1, 1, 0, 0, 0);
              
                default:
                    return new SqlDateTime();
                   
            }                      
        }

        #endregion

        [SqlFunction(Name = "fn_Num", DataAccess = DataAccessKind.None, FillRowMethodName = "GetTableRowFnNum", IsDeterministic = true)]
        public static IEnumerable fn_Num(SqlInt64 ValueFrom, SqlInt64 ValueTo)
        {
            List<Int64> ret = new List<Int64>();
            if ( !ValueFrom.IsNull && !ValueTo.IsNull )
            {
             Int64 i;
             for (i = ValueFrom.Value; i <= ValueTo.Value ; i++) ret.Add(i); 
            }
                      
            return ret;
        }

        public static void GetTableRowFnNum(object o, out Int64 Value)
        {
            Value = (Int64)o;            
        }

    }
      
}



Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
CREATE ASSEMBLY SqlUtils1
FROM '......\SqlUtils1.dll' 
WITH PERMISSION_SET = SAFE
GO

CREATE FUNCTION fn_num(@from bigint, @to bigint)
RETURNS TABLE(N bigint)
AS EXTERNAL NAME SqlUtils1.[MySQLCLR.Utils].fn_Num;
GO  

CREATE FUNCTION fn_Format1(@format nvarchar(4000), @arg0 sql_variant) RETURNS NVARCHAR(4000)
AS EXTERNAL NAME SqlUtils1.[MySQLCLR.Utils].Format1
go
CREATE FUNCTION fn_Format2(@format nvarchar(4000), @arg0 sql_variant, @arg1 sql_variant) RETURNS NVARCHAR(4000)
AS EXTERNAL NAME SqlUtils1.[MySQLCLR.Utils].Format2
go
CREATE FUNCTION fn_Format3(@format nvarchar(4000), @arg0 sql_variant, @arg1 sql_variant, @arg2 sql_variant) RETURNS NVARCHAR(4000)
AS EXTERNAL NAME SqlUtils1.[MySQLCLR.Utils].Format3
go
CREATE FUNCTION fn_Format4(@format nvarchar(4000), @arg0 sql_variant, @arg1 sql_variant, @arg2 sql_variant, @arg3 sql_variant) RETURNS NVARCHAR(4000)
AS EXTERNAL NAME SqlUtils1.[MySQLCLR.Utils].Format4
go

CREATE FUNCTION fn_RoundDateTime(@DateTime datetime, @IntervalType nvarchar(3), @IntervalValue int) RETURNS DATETIME
AS EXTERNAL NAME SqlUtils1.[MySQLCLR.Utils].RoundDateTime
go


...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932090
Фотография court
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GetNums by I.Ben-Gan
там же и сравнение с рекурсией
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932105
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Таблица, функция, рекурсия
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
use tempdb;
set ansi_nulls, quoted_identifier, xact_abort on;
go

create table dbo.N (n int not null primary key);
insert into dbo.N
select top (1000000)
 row_number() over (order by 1/0)
from
 master.dbo.spt_values a cross join
 master.dbo.spt_values b;
go

create function dbo.fnSequentialNumbers
(
 @n int
)
returns table
as
return (
 with
  l1(x) as (select 1 from (values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) t(d)),
  l2(x) as (select 1 from l1 a cross join l1 b),
  l3(x) as (select 1 from l2 a cross join l2 b),
  l4(x) as (select 1 from l3 a cross join l3 b),
  l5(x) as (select 1 from l4 a cross join l4 b),
  l6(x) as (select 1 from l5 a cross join l5 b)
 select top (@n) row_number() over (order by 1/0) as n from l6
)
go

create function dbo.fnSequentialNumbersRecursive
(
 @n int
)
returns table
as
return (
 with t(n) as
 (
  select 1
  union all
  select n + 1 from t where n < @n
 )
 select n from t
)
go

create table #t (id int, n int);
insert into #t values (1, 100000), (2, 100000), (3, 100000);

declare @c int = 5;

while @c > 0
 begin
  exec sys.sp_executesql N'/*q1*/declare @id int, @n int; select @id = id, @n = n.n from #t t join dbo.N n on n.n <= t.n option (maxdop 1);';
  exec sys.sp_executesql N'/*q2*/declare @id int, @n int; select @id = id, @n = n.n from #t t cross apply dbo.fnSequentialNumbers(t.n) n option (maxdop 1);';
  exec sys.sp_executesql N'/*q3*/declare @id int, @n int; select @id = id, @n = n.n from #t t cross apply dbo.fnSequentialNumbersRecursive(t.n) n option (maxdop 1, maxrecursion 0);';

  set @c -= 1;
 end;

select
 d.descr, qs.total_elapsed_time / qs.execution_count
from
 sys.dm_exec_query_stats qs cross apply
 sys.dm_exec_sql_text(qs.plan_handle) t cross apply
 (select a.descr from (values ('table', '/*q1*/%'), ('function', '/*q2*/%'), ('recursion', '/*q3*/%')) a(descr, m) where t.text like a.m) d(descr)
order by
 qs.total_elapsed_time;
go

drop function dbo.fnSequentialNumbers, dbo.fnSequentialNumbersRecursive;
drop table dbo.N, #t;
go



2019function52727table54523recursion2926188


2008R2table41464function46407recursion1657534
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932114
nullin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
invm, а так?
Код: sql
1.
2.
3.
4.
5.
create function dbo.fnSequentialNumbersCompatibility130(@n int)
returns table
as
return (select row_number() over (order by (select null)) as n 
          from string_split(stuff(replicate(convert(varbinary(max), ' '), @n), 1, 1, ''), ' '));

...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932613
Фотография SIMPLicity_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны
SIMPLicity_
Вот (через рекурсию, MSSQL 2005 и последующие выпуски):

Как показывает практика, в реальных ситуациях при большой нагрузке и/или при больших объёмах данных рекурсия вносит существенные издержки в выполнение запроса. Для решения такой задачи обычно действуют наиболее тривиальным способом: заводят таблицу-сиквенс с единственным полем, и с индексом по этому полю.

И да, в master..spt_values не 255, а 2048 записей с типом 'P'. Но её не рекомендуется использовать по другим причинам.


Там были то ли дыры в нумерации, то ли дубли,- в первой тысячи, кажется,- за давностию, простите , не помню. Писал тут когда-то да лень искать. Мне приведённый вариант понравился - я на его основе курсор сделал. Это служебный сервер для внешних (по отношению к нагруженному серверу) обработок. Соответственно, тут его "тормознутость" даже чуть в плюс. Между итерациями большого курсора всё равно леплю waitfor delay 2-3 секунды,- что бы основные процессы успевали "проср@ться" . Можно, конечно, и без этого, но тут иду чисто по пути наименьшего сопротивления. Да и параллельным обработкам тоже как-то надо жить (почти как CSMA/CD ,- только выражено в товарной форме) ....
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932614
Фотография SIMPLicity_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
a_voronin
SIMPLicity_,

Изобретателям велосипедов

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
declare @Stuff as Table ( Name VarChar(10), Number Int )
insert into @Stuff ( Name, Number ) values ( 'foo', 19 ), ( 'bar', 34 ), ( 'baz', 25 )

;
WITH A AS 
(
	SELECT * FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) A(N)
)
select s.* from @Stuff s
CROSS APPLY 
(
	SELECT TOP (s.Number) NULL AS N FROM A A1, A A2, A A3, A A4, A A5, A A6
) n
	



Спасибо! Как лучший вариант, в принципе. Про допустимость SELECT TOP (s.Number) забыл, есличестно
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39932615
Фотография SIMPLicity_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Господа!, спасибо за варианты!

Просто убийственно!
PS У меня нет столько строк, что бы почувствовать существенную разницу во времени генерации.
PPS Точнее - не должно быть! Ну..., надеюсь, что не будет. Но теперь появилась мысль проверять сей факт
...
Рейтинг: 0 / 0
Повторить строку N раз
    #39933672
assmsk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
create table #t (c1 int, qty int)
insert into #t values (1,2)
insert into #t values (3,4)
insert into #t values (4,1)
create table #r (c1 int)

DECLARE @SQL VARCHAR(MAX)
SET  @SQL = 'SELECT * FROM (VALUES ' + STUFF((SELECT  REPLICATE(',('+CAST(c1 AS VARCHAR)+')',qty) FROM #t FOR XML PATH('')),1,1,'') + ') CTE (val)'
INSERT #r
EXEC(@SQL)
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Повторить строку N раз
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]