Cumulative sum with conditions - tsql

I tried to get cumulative sums throught column week (and if is possible, then get result ordered by column Datum$ADTE) in my query:
select
A.Castka "Amount",
'Cashflow' as N,
A.Datum$DATE "Datum",
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"
from iGateCashflow A
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
In where clause are conditions, whichs will be edited througt external form.
I would like to get result like this (better without Amount column)
week N Amount Result
44 Cashflow 150 150
45 Cashflow 200 350
46 Cashflow 300 650
47 Cashflow 350 1000
I tried something like this, but I can't achieve my expected result:
select
sum(y.Amount),
Y.N,
Y.Week
from (
select
A.Castka "Amount",
'Cashflow' as N,
A.Datum$DATE "Datum",
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"
from iGateCashflow A
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
) X
join (
select
A.Castka "Amount",
'Cashflow' as N,
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"
from iGateCashflow A
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
) Y on Y.Week <= X.Week
group by
Y.N,
Y.Week
order by
Y.Week

I think there's more your question than what you showed. But use this as an idea (you'll need to add in WHERE conditions, etc)
SELECT *,
SUM(Amount) OVER (ORDER BY [week])
FROM iGateCashflow

Better to use OVER Clause to get Sum partition by Week and order by Date, please refer to
Over Clause

Maybe try something like this
select
cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week",
sum(B.Castka) "Total amount"
from iGateCashflow A
inner join iGateCashflow B
on A.BusTransaction_ID = B.BusTransaction_ID
and A.Vyjasneno = B.Vyjasneno
and B.week <= A.week --> if week is a calculated field, include the calculation here for both 'week's
where
1 = 1
and A.BusTransaction_ID = '1D00000101'
and A.Vyjasneno = 'A'
and cast(datepart(week ,convert(date, dbo.ib_DateToString(Napocteno$DATE, 'dd.mm.yyyy'), 104)) as varchar(4))
= 44
group by cast(A.Rok as varchar(4)) + '-' + cast(A.Tyden as varchar(4)) "Week"

Related

DAX counts rows between 2 dates

DECLARE #lower INT = 1
,#upper INT = 6
,#randnum INT
,#date DATE = getdate()
,#endofcurrentmonth DATE
,#loopdate DATE
,#loop INT
,#loopmax INT
,#innerloop INT
,#innerloopmax INT
,#value DATE
IF object_id('tempdb..#tmp_DateRange') IS NOT NULL
DROP TABLE #tmp_DateRange
CREATE TABLE #tmp_DateRange (
ID INT identity(1, 1) PRIMARY KEY NOT NULL
,[Date] DATE
)
IF object_id('tempdb..#tmp_RandomData') IS NOT NULL
DROP TABLE #tmp_RandomData
CREATE TABLE #tmp_RandomData (
ID INT identity(1, 1) PRIMARY KEY NOT NULL
,[BidDateWon] DATE
,[BidWon] BIT
)
SELECT #endofcurrentmonth = dateadd(mm, datediff(MM, 0, dateadd(MM, 1, #date)), 0) - 1
SELECT #loopdate = dateadd(mm, - 9, dateadd(dd, 1 - datepart(dd, #date), #date))
WHILE #loopdate <= #endofcurrentmonth
BEGIN
INSERT INTO #tmp_DateRange ([Date])
VALUES (#loopdate)
SET #loopdate = dateadd(dd, 1, #loopdate)
END
SELECT #loop = 0
,#loopmax = max(ID)
FROM #tmp_DateRange
WHILE #loop < #loopmax
BEGIN
SELECT #randnum = round(((#upper - #lower - 1) * rand() + #lower), 0)
SET #loop = #loop + 1
SET #innerloopmax = #randnum
SET #innerloop = 0
IF #randnum % 2 = 0
BEGIN
SET #value = (
SELECT [date]
FROM #tmp_DateRange
WHERE ID = #loop
)
END
ELSE
BEGIN
SET #value = NULL
END
WHILE #innerloop <= #innerloopmax
BEGIN
SET #innerloop = #innerloop + 1
INSERT INTO #tmp_RandomData (BidDateWon)
VALUES (#value)
END
END
UPDATE #tmp_RandomData
SET BidWon = 1
WHERE BidDateWon IS NOT NULL
SELECT *
FROM #tmp_RandomData
=CALCULATE(COUNTROWS(Fact_SalesSummaries),
DATESINPERIOD(Fact_SalesSummaries[BidWonDate],
LASTDATE(Fact_SalesSummaries[BidWonDate]),
-3, MONTH),
Fact_SalesSummaries[BidWonDate] <> BLANK())
I have tried search and different ways to counts rows that have dates between 2 different dates it calculates the rows as 1 and not more than that in the formula.
This is meant to be a rolling 3-month count of records from date back 3 months to be able to calculate an average with a count of all records.
Example in SQL would look like this.
select MonthBlended, yearblended, BidWonDate, BidWonFlag,
(select count(*) from Fact_SalesSummaries
where convert(date, cast(MonthBlended as varchar(2))+ '/01/' + cast(YearBlended as varchar(4)), 101) between
dateadd(mm, -3, convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101))
and convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101)
and BidWonDate is not null
) as CountWONPrior3Month,
(select count(*) from Fact_SalesSummaries
where convert(date, cast(MonthBlended as varchar(2))+ '/01/' + cast(YearBlended as varchar(4)), 101) between
dateadd(mm, -3, convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101))
and convert(date, cast(t1.MonthBlended as varchar(2))+ '/01/' + cast(t1.YearBlended as varchar(4)), 101)
) as CountALLPrior3Month
from Fact_SalesSummaries t1
BidWonDate BidWon CountWonPrior3Month CountAllPrior3Month
----------------------- ------ ------------------- -------------------
2014-07-17 00:00:00.000 1 618 1048
2014-07-17 00:00:00.000 1 618 1048
2014-07-17 00:00:00.000 1 618 1048
2014-07-17 00:00:00.000 1 618 1048
NULL 0 618 1048
NULL 0 618 1048
NULL 0 618 1048
NULL 0 618 1048
2014-07-17 00:00:00.000 1 618 1048
NULL 0 618 1048
NULL 0 618 1048
2014-07-11 00:00:00.000 1 618 1048
Well trying this in a measure does work but does not calculate correctly any help would be greatly appreciated.
I included a sql script that will give you a random data sample that will match the data I have. Run the script and it will generate a random dates or nulls that you can run the dax expression against. Thanks for any help.
I'm new to DAX and PowerBI,
as i've understood the calculate function, i think your second parameter is what's causing u the error, the second param must be a filter, you are not fitering anything in your case, you are just returning a range of dates,
i'm really trying to be helful even know i might be getting it wrong, anyway wouldnt hurt if you try it :D
Counting the number of records from the current date going back 3 months can be done with the following measure.
enumerator =
CALCULATE (
COUNTROWS ( Fact_SalesSummaries ),
DATESINPERIOD (
'Fact_SalesSummaries'[BidDateWon],
LASTDATE ( 'Fact_SalesSummaries'[BidDateWon] ),
3,
MONTH
),
Fact_SalesSummaries[BidDateWon] <> BLANK ()
)
The fact your lost bids dont have dates makes it difficult to get this accurate, because you have to rely on the ordinal (and hopefully contiguous) numbering of the ID's to create the denominator.
denominator =
CALCULATE (
MAX ( Fact_SalesSummaries[ID] ) - MIN ( Fact_SalesSummaries[ID] )
+ 1,
DATESINPERIOD (
'Fact_SalesSummaries'[BidDateWon],
LASTDATE ( 'Fact_SalesSummaries'[BidDateWon] ),
-3,
MONTH
)
)
If you had dates in the rows where the bidwon=false, you could use the same calclation as the enumerator, just removing the last filter.

SQL Server - WHERE Date Range & GROUP BY MonthName

I have 2 same queries (to return "MonthName Year" and count) as below, but only the date range in the WHERE condition is different. Query 1 gets only the June month count, while Query 2 gets count from Apr to Jul, where the Jun month count (in Query 2) is not same as June month count from Query 1. Please advise.
Query 1:
SELECT DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate) AS MonthNumber, COUNT(1) AS InquiryCount
, Cast(Datename(MONTH,SubmissionDate) + ' ' + Datename(YEAR,SubmissionDate) AS DATETIME) AS tmp
FROM [dbo].[InvestigationDetails] (nolock)
WHERE SubmissionDate>= '06/01/2016'
AND SubmissionDate <= '06/30/2016'
GROUP BY DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate), DateName(Year, SubmissionDate)
ORDER BY tmp ASC
Query 2:
SELECT DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate) AS MonthNumber, DateName(Year, SubmissionDate), COUNT(1) AS InquiryCount
, Cast(Datename(MONTH,SubmissionDate) + ' ' + Datename(YEAR,SubmissionDate) AS DATETIME) AS tmp
FROM [dbo].[InvestigationDetails] (nolock)
WHERE SubmissionDate>= '04/01/2016'
AND SubmissionDate <= '07/31/2016'
GROUP BY DATENAME(MONTH, SubmissionDate) + ' ' + DateName(Year, SubmissionDate), DateName(Year, SubmissionDate)
ORDER BY tmp ASC
Thanks,
Jay
SubmissionDate must be of type DATETIMEand thus, you are missing all values for your last day, 06/30/2016, since this equates to 06/30/2016 00:00:00. This means any records that have SubmissionDate with a time > 00:00:00 on 6/30/2016 will be excluded. For example, 6/30/2016 12:44:22 wouldn't be included in your results with your current logic.
Use one of these instead:
AND SubmissionDate < '07/01/2016'
AND SubmissionDate <= '06/30/2016 23:59:59.999'
The first method is preferred since you will get all records before 7/1/2016, which includes 6/30/2016 23:59:59.999. Of course, you should be aware of how precise DATETIME can be in SQL Server. Run the code below to see what I mean.
declare #dt datetime2 = getdate()
select #dt --more precise with datetime2
select getdate() --not as precise

SQL Server 2008 R2 - convert all datetime parts (as ints) into a datetime column

I have a table that has the datetime pieces (year, month, day, hour, minute, second, millisecond) stored as integers. I'd like to concatenate them into a single datetime column.
I've tried various approaches but none work - there seems to be no simple way to put these items together?
You can convert each part to a varchar and concatenate them together in the format of an ISO datetime string. Then use Convert to convert the string to a DateTime.
Here is an example. You would need to replace each hard coded integer with the name of the column from your table.
SELECT CONVERT(DATETIME, CAST(2016 AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(8 AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(13 AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(16 AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(32 AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(07 AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(64 AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable
Or with column names (assumed)
SELECT CONVERT(DATETIME, CAST(yt.Year AS VARCHAR(4)) -- year
+ '-' + CAST('0' + CAST(yt.Month AS VARCHAR(2)) AS VARCHAR(2)) -- month
+ '-' + RIGHT('0' + CAST(yt.Day AS VARCHAR(2)), 2) -- day of month
+ 'T' + RIGHT('0' + CAST(yt.Hours AS VARCHAR(2)), 2) -- hours (I assume its military time (24 hours))
+ ':' + RIGHT('0' + CAST(yt.Minutes AS VARCHAR(2)), 2) -- minutes
+ ':' + RIGHT('0' + CAST(yt.Seconds AS VARCHAR(2)), 2) -- seconds
+ '.' + RIGHT('000' + CAST(yt.Milliseconds AS VARCHAR(3)), 3)) AS MyDate -- milliseconds
FROM yourTable yt
One more note. Microsoft recommends that you use DateTime2 instead of DateTime to persist date time values starting with Sql Server 2008 (which you tagged in your question).
Prior to sql server 2012, you can use a series of nested DATEADD() functions to mimic DATETIMEFROMPARTS() function
Create and populate sample data (In your next question, please save us this step)
DECLARE #T as table
(
cYear int,
cMonth int,
cDay int,
cHour int,
cMinute int,
cSecond int,
cMillisecond int
)
INSERT INTO #T VALUES(2016, 6, 22, 16, 34, 25, 3)
The query:
SELECT *,
DATEADD(MILLISECOND, cMillisecond,
DATEADD(SECOND, cSecond,
DATEADD(MINUTE, cMinute,
DATEADD(HOUR, cHour,
DATEADD(DAY, cDay -1,
DATEADD(MONTH, cMonth - 1,
DATEADD(YEAR, cYear - 2000, '2000-01-01')
)
)
)
)
)
) As TheDate
FROM #T
Results:
cYear cMonth cDay cHour cMinute cSecond cMillisecond TheDate
----- ------ ---- ----- ------- ------- ------------- -----------------------
2016 6 22 16 34 25 3 2016-06-22 16:34:25.003
Note that the base date I'm using is January 1st 2000, therefor you need to subtract 2000 from the year, 1 from the month and 1 from the days.

TSQL SELECT data within range of year and month

I'm trying to query data within a range of start year and month and end year and month. But SQL returnes onty the year and the month chosen. Can anyone identify the problem with my approach.
Thanks!
ALTER PROCEDURE xxx
(#JaarBegin AS int
, #JaarEind AS int
, #MaandBegin AS int
, #MaandEind AS int)
AS
BEGIN
WITH
CTE AS
(
SELECT [D_Medewerker_ID]
,[Gebruikersnaam]
,[Naam]
,[Afdelingscode]
,CONVERT(date, [Datum_uit_dienst]) AS DatumIn
,CONVERT(date, [Datum_in_dienst]) AS DatumUit
FROM [DM].[dm].[D_Medewerker] AS M
),
CTE2 AS(
SELECT F.[D_Functie_ID]
,[Generieke_Functie]
,[Specifieke_Functie]
,Fo.[D_Medewerker_ID]
FROM [DM].[dm].[D_Functie] AS F
JOIN dm.dm.F_FormatieBezetting AS Fo
ON F.D_Functie_ID = Fo.D_Functie_ID
)
SELECT DISTINCT CTE.[Gebruikersnaam]
, CTE.Naam
, CTE.Afdelingscode
, CTE.DatumIn
, CTE.DatumUit
, CTE2.Generieke_Functie
, CTE2.Specifieke_Functie
FROM CTE
JOIN CTE2
ON CTE.D_Medewerker_ID = CTE2.D_Medewerker_ID
WHERE DATEPART(year,CTE.DatumUit) BETWEEN #JaarBegin AND #JaarEind
AND DATEPART(MONTH, CTE.DatumUit) >= #MaandBegin AND DATEPART(MONTH, CTE.DatumUit) <= #MaandEind
ORDER BY CTE.DatumUit DESC;
END
You need to convert the int values you get to a date value.
In Sql server 2012 or later, you can use the built-in function DATEFROMPARTS to do this:
WHERE CTE.DatumUit >= DATEFROMPARTS ( #JaarBegin , #MaandBegin , 1 )
AND CTE.DatumUit < DATEADD(MONTH, 1, DATEFROMPARTS ( #JaarEind , #MaandBegin , 1 ))
If you are working with an earlier version of sql server, you need to build a string that represents the date (using iso format yyyy-mm-dd) and then cast it to date:
WHERE CTE.DatumUit >= CAST(RIGHT('0000' + CAST(#JaarBegin as varchar(4)), 4) + '-' + RIGHT('00' + CAST(#MaandBegin as varchar(2)), 2) +'-01' as datetime)
AND CTE.DatumUit < DATEADD(MONTH, 1, CAST(RIGHT('0000' +CAST(#JaarEind as varchar(4)), 4) + '-' + RIGHT('00' + CAST(#MaandBegin as varchar(2)), 2) +'-01' as datetime))

How to generate larger sets of lottery numbers efficiently

I am a beginner with SQL and I was looking for more experiences with SQL hence I decided to design a procedure to generate X amount of random lotto picks. The lottery here in my area allows you to pick 5 numbers from 1-47 and 1 "mega" number from 1-27. The trick is the "mega" number could repeat with the 5 numbers previously, i.e. 1, 2, 3, 4, 5, mega 1.
I created the following procedure to generate 10 million lottery picks, and it took 12 hours and 57 minutes for the process to finish. While my friends tested the same thing with java and it took seconds. I was wondering if there's any improvements I can make to the code or if there's any mistakes that I've made? I'm new at this hence I am trying to learn better approaches etc, all comments welcome.
USE lotto
DECLARE
#counter INT,
#counter1 INT,
#pm SMALLINT,
#i1 SMALLINT,
#i2 SMALLINT,
#i3 SMALLINT,
#i4 SMALLINT,
#i5 SMALLINT,
#sort int
SET #counter1=0
TRUNCATE TABLE picks
WHILE #counter1<10000000
BEGIN
TRUNCATE TABLE sort
SET #counter = 1
WHILE #counter < 6
BEGIN
INSERT INTO sort (pick)
SELECT CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT)
IF (SELECT count(distinct pick) FROM sort)<#counter
BEGIN
TRUNCATE TABLE sort
SET #counter=1
END
ELSE IF (SELECT COUNT(DISTINCT pick) FROM sort)=#counter
BEGIN
SET #counter = #counter + 1
END
END
SET #sort = 0
WHILE #sort<5
BEGIN
UPDATE sort
SET sort=#sort
WHERE pick = (SELECT min(pick) FROM sort WHERE sort is null)
SET #sort=#sort + 1
END
SET #i1 = (SELECT pick FROM sort WHERE sort = 0)
SET #i2 = (SELECT pick FROM sort WHERE sort = 1)
SET #i3 = (SELECT pick FROM sort WHERE sort = 2)
SET #i4 = (SELECT pick FROM sort WHERE sort = 3)
SET #i5 = (SELECT pick FROM sort WHERE sort = 4)
SET #pm = (CAST(((27+ 1) - 0) * RAND() + 1 AS TINYINT))
INSERT INTO picks(
First,
Second,
Third,
Fourth,
Fifth,
Mega,
Sequence
)
Values(
#i1,
#i2,
#i3,
#i4,
#i5,
#pm,
#counter1
)
SET #counter1 = #counter1+1
END
I generated 10000 rows in 0 sec. I did it i another way. Hope this will help you
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 10000 )
SELECT
(ABS(CHECKSUM(NewId())) % 47 + 1) AS First,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Second,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Third,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fourth,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fifth,
(ABS(CHECKSUM(NewId())) % 27 + 1) AS Mega,
Nbrs.n AS Sequence
FROM
Nbrs
OPTION ( MAXRECURSION 0 )
10000 rows 0 sec
100000 rows 1 sec
1000000 rows 13 sec
10000000 rows 02 min 21 sec
Or with cross joins
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
Nbrs(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT
(ABS(CHECKSUM(NewId())) % 47 + 1) AS First,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Second,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Third,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fourth,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Fifth,
(ABS(CHECKSUM(NewId())) % 27 + 1) AS Mega,
Nbrs.n AS Sequence
FROM Nbrs
WHERE N <= 10000000;
10000 rows 0 sec
100000 rows 1 sec
1000000 rows 14 sec
10000000 rows 03 min 29 sec
I should also mention that the reason I am using
(ABS(CHECKSUM(NewId())) % 47 + 1)
is that it returns a random number per row. The solution with
CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT)
return the same random number for each row if you select them in one go. To test this run this example:
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 5 )
SELECT
CAST(((47+ 1) - 0) * RAND() + 1 AS TINYINT) AS Random,
(ABS(CHECKSUM(NewId())) % 47 + 1) AS RadomCheckSum,
Nbrs.n AS Sequence
FROM Nbrs
Ok. So I did see your comment and I have a solution for that as well. If you really want to order the numbers. The complexity of the algorithm elevates and that also means that the time of the algorithm increases. But i still think it is doable. But not in the same neat way.
--Yeah declaring a temp table for just the random order number
DECLARE #tbl TABLE(value int)
--The same function but with the number of the random numbers
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 5 )
INSERT INTO #tbl
(
value
)
SELECT
Nbrs.n AS Sequence
FROM Nbrs
;WITH Nbrs ( n ) AS (
SELECT CAST(1 as BIGINT) UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 100000 )
SELECT
tblOrderRandomNumbers.[1] AS First,
tblOrderRandomNumbers.[2] AS Second,
tblOrderRandomNumbers.[3] AS Third,
tblOrderRandomNumbers.[4] AS Fourth,
tblOrderRandomNumbers.[5] AS Fifth,
(ABS(CHECKSUM(NewId())) % 27 + 1) AS Mega,
Nbrs.n AS Sequence
FROM
Nbrs
--This cross join. Joins with the declared table
CROSS JOIN
(
SELECT
[1], [2], [3], [4], [5]
FROM
(
SELECT
Random,
ROW_NUMBER() OVER(ORDER BY tblRandom.Random ASC) AS RowNumber
FROM
(
SELECT
(ABS(CHECKSUM(NewId())) % 47 + 1) AS Random
FROM
#tbl AS tblNumbers
) AS tblRandom
)AS tblSortedRadom
--A pivot makes the rows to columns. Using the row index over order of the random number
PIVOT
(
AVG(Random)
FOR RowNumber IN ([1], [2], [3], [4],[5])
) as pivottable
) AS tblOrderRandomNumbers
OPTION ( MAXRECURSION 0 )
But still i manage to do it in a little time
10000 Rows : 0 sec
100000 Rows : 4 sec
1000000 Rows : 43 sec
10000000 Rows : 7 min 9 sec
I Hope this help
I wrote this script just out of curiousity. It should do better than your script, but I cant tell for sure.
Beware that I use a declared table, and if you use a real table performance should be better when generating larger amounts of rows.
I generated 10000 rows on about 13 seconds, that counts to about 3.5 hours to generate 10 000 000 rows. Still far worse than the Java-case you described.
set nocount on
go
declare #i int = 1
declare #t table(nr1 int, nr2 int, nr3 int, nr4 int, nr5 int, mega int, seq int)
while #i <= 10000
begin
;with numbers(nr)
as
(
select 1
union all
select nr+1
from numbers
where nr < 47
)
,mega(nr)
as
(
select 1
union all
select nr+1
from mega
where nr < 27
)
,selectednumbers(nr)
as
(
select top 5 nr
from numbers
order by newid()
)
,selectedmega(mega)
as
(
select top 1 nr
from mega
order by newid()
)
,tmp
as
(
select *
,row_number() over(order by nr) as rownr
from selectednumbers
)
insert into #t
select max(nr1) as nr1
,max(nr2) as nr2
,max(nr3) as nr3
,max(nr4) as nr4
,max(nr5) as nr5
,(select mega from selectedmega) as mega
,#i as seq
from (
select case when rownr = 1 then nr else 0 end as nr1
,case when rownr = 2 then nr else 0 end as nr2
,case when rownr = 3 then nr else 0 end as nr3
,case when rownr = 4 then nr else 0 end as nr4
,case when rownr = 5 then nr else 0 end as nr5
from tmp
) x
set #i = #i + 1
end
select * from #t