Generate a random number in the range 1 - 10 - sql

Since my approach for a test query which I worked on in this question did not work out, I'm trying something else now. Is there a way to tell pg's random() function to get me only numbers between 1 and 10?

If by numbers between 1 and 10 you mean any float that is >= 1 and < 10, then it's easy:
select random() * 9 + 1
This can be easily tested with:
# select min(i), max(i) from (
select random() * 9 + 1 as i from generate_series(1,1000000)
) q;
min | max
-----------------+------------------
1.0000083274208 | 9.99999571684748
(1 row)
If you want integers, that are >= 1 and < 10, then it's simple:
select trunc(random() * 9 + 1)
And again, simple test:
# select min(i), max(i) from (
select trunc(random() * 9 + 1) as i from generate_series(1,1000000)
) q;
min | max
-----+-----
1 | 9
(1 row)

To summarize and a bit simplify, you can use:
-- 0 - 9
select floor(random() * 10);
-- 0 - 10
SELECT floor(random() * (10 + 1));
-- 1 - 10
SELECT ceil(random() * 10);
And you can test this like mentioned by #user80168
-- 0 - 9
SELECT min(i), max(i) FROM (SELECT floor(random() * 10) AS i FROM generate_series(0, 100000)) q;
-- 0 - 10
SELECT min(i), max(i) FROM (SELECT floor(random() * (10 + 1)) AS i FROM generate_series(0, 100000)) q;
-- 1 - 10
SELECT min(i), max(i) FROM (SELECT ceil(random() * 10) AS i FROM generate_series(0, 100000)) q;

If you are using SQL Server then correct way to get integer is
SELECT Cast(RAND()*(b-a)+a as int);
Where
'b' is the upper limit
'a' is lower limit

(trunc(random() * 10) % 10) + 1

The correct version of hythlodayr's answer.
-- ERROR: operator does not exist: double precision % integer
-- LINE 1: select (trunc(random() * 10) % 10) + 1
The output from trunc has to be converted to INTEGER. But it can be done without trunc. So it turns out to be simple.
select (random() * 9)::INTEGER + 1
Generates an INTEGER output in range [1, 10] i.e. both 1 & 10 inclusive.
For any number (floats), see user80168's answer. i.e just don't convert it to INTEGER.

Example
SELECT RAND()*(min-max)+max

Actually I don't know you want to this.
try this
INSERT INTO my_table (my_column)
SELECT
(random() * 10) + 1
;

This stored procedure inserts a rand number into a table. Look out, it inserts an endless numbers. Stop executing it when u get enough numbers.
create a table for the cursor:
CREATE TABLE [dbo].[SearchIndex](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Cursor] [nvarchar](255) NULL)
GO
Create a table to contain your numbers:
CREATE TABLE [dbo].[ID](
[IDN] [int] IDENTITY(1,1) NOT NULL,
[ID] [int] NULL)
INSERTING THE SCRIPT :
INSERT INTO [SearchIndex]([Cursor]) SELECT N'INSERT INTO ID SELECT FLOOR(rand() * 9 + 1) SELECT COUNT (ID) FROM ID
CREATING AND EXECUTING THE PROCEDURE:
CREATE PROCEDURE [dbo].[RandNumbers] AS
BEGIN
Declare CURSE CURSOR FOR (SELECT [Cursor] FROM [dbo].[SearchIndex] WHERE [Cursor] IS NOT NULL)
DECLARE #RandNoSscript NVARCHAR (250)
OPEN CURSE
FETCH NEXT FROM CURSE
INTO #RandNoSscript
WHILE ##FETCH_STATUS IS NOT NULL
BEGIN
Print #RandNoSscript
EXEC SP_EXECUTESQL #RandNoSscript;
END
END
GO
Fill your table:
EXEC RandNumbers

Try This:
Select (ROW_NUMBER() OVER (ORDER BY ItemDesc ASC)+15000) as ID, ItemCode, ItemDesc

Using Postgres, here is how to generate random number between any 2 numbers, say, min and max:
Including min and Excluding max,
SELECT floor(random() * (max - min)) + min;
Including both min and max,
SELECT floor(random() * (max - min + 1)) + min;
So to get numbers between 1 and 10 (including 10),
min = 1, max = 10
SELECT floor(random() * (10 - 1 + 1)) + 1;
In general, you can use this formula to get random integer numbers between any min and max numbers.

Related

SQL Server - Generate 6 float values that MAX - MIN = parameter

I need to generate 6 float values with 1 decimal in the best way and performance possible where:
MAX(value) - MIN(value) = #parameter
I have this code:
BEGIN
DECLARE #parameter float = 0.6
WHILE #validated = 0
BEGIN
IF #count < 6
BEGIN -- fill table with 6 random values from 0 to 2 (with 1 decimal)
INSERT INTO #tempdata ([value])
SELECT ROUND(RAND()*(2-0),1);
SET #count = #count + 1
END
IF #count = 6 -- if temp table has 6 values then do the validation
BEGIN
SELECT #result = (MAX(value) - MIN(value)) FROM #tempdata
IF(#result = #parameter)
BEGIN
PRINT 'MATCH PARAMETER'
SET #validated = 1
END
ELSE
BEGIN
DELETE #tempdata
SET #counter = 0
END
END
END
END
This is working but sometimes it takes 10 or 20 seconds and should be faster.
For example if #parameter value is: 0.8 then we need 6 numbers between 0 and 2 where the MAX - MIN match that, for example:
0.7
1.1
0.6
0.9
1.5
1.2
MAX(1.5) - MIN(0.7) = 0.8
Any clue?
Do the following:
Generate 6 random numbers between 0 and 1
Normalize the values to be between 0 and 0.8 (or whatever)
Add something back in if you don't want them to all start at 0
In SQL:
select x,
max(x) over () - min(x) over () as starting_at_0,
min(x) over () + 0.8 * (x - min(x) over ()) / (max(x) over () - min(x) over ()) as the_value_you_want
from (values (rand(checksum(newid()))),
(rand(checksum(newid()))),
(rand(checksum(newid()))),
(rand(checksum(newid()))),
(rand(checksum(newid()))),
(rand(checksum(newid())))
) v(x);
Here is a db<>fiddle.
Cast to numeric(2, 1), if you want only one decimal point.
EDIT:
I tend to forget that this also works:
select x,
max(x) over () - min(x) over () as starting_at_0,
min(x) over () + 0.8 * (x - min(x) over ()) / (max(x) over () - min(x) over ()) as the_value_you_want
from (values (rand()),
(rand()),
(rand()),
(rand()),
(rand()),
(rand())
) v(x);
(See here.)
SQL Server treats rand() in a special way. Each call to rand() is evaluated before the query is run. So, rand() has the same value on multiple rows in the result set. However, it has different values in different columns.
with randvals(rval) as
(
select rand()
union all
select rand()
union all
select rand()
union all
select rand()
union all
select rand()
union all
select rand()
),
arandvals(rval, xrval, mrval) as
(
select rval, max(rval) over() as xrval, min(rval) over() as mrval
from randvals
)
select cast(0.8 * rval / (xrval - mrval) as numeric(3,2))
from arandvals

How to select only armstrong numbers from the list?

I want is to select Armstrong numbers from the list below list I have searched of solution of this question bu unable to find in SQL-Server:
Numbers
121
113
423
153
541
371
I am sure most of you know what's the Armstrong number and how to calculate though I am describing is for the simplicity : sum of the cubes of its digits is equal to the number itself i.e.
1*1*1 + 5*5*5 + 3*3*3 = 153
3*3*3 + 7*7*7 + 1*1*1 = 371
Please help me on this as I am also trying but seeking for quick solution. It will be very helpful to me. Thanks in advance.
Obviously static processing during each query is not correct approach but we can create function like this and
create function dbo.IsArmstrongNumber(#n int)
returns int as
begin
declare #retValue int = 0
declare #sum int = 0
declare #num int = #n
while #num > 0
begin
set #sum += (#num%10) * (#num%10) * (#num%10)
set #num = #num/10
end
IF #sum = #n
set #retValue = 1
return #retValue
end
Pre-processing and selecting in IN clause is better
select * from #Numbers where dbo.IsArmstrongNumber(n) = 1
select 153 x into #temp;
insert #temp values(371);
insert #temp values(541);
with cte as (select x, substring(cast(x as nvarchar(40)) ,1,1) as u, 1 as N FROM #temp
union all
select x, substring(cast(x as nvarchar(40)),n+1,1) as u , n+1 from cte where len(cast(x as nvarchar(40))) > n
)
select x from cte group by x having SUM(POWER(cast(u as int),3)) = x
drop table #temp;
here is the mark 2 - you can change the #ORDER to explore power of 4,5 etc
declare #order int = 3;
declare #limit int = 50000;
with nos as (select 1 no
union all
select no + 1 from nos where no < #limit),
cte as (select no as x, substring(cast(no as nvarchar(40)) ,1,1) as u, 1 as N FROM nos
union all
select x, substring(cast(x as nvarchar(40)),n+1,1) as u , n+1 from cte where len(cast(x as nvarchar(40))) > n
)
select x from cte group by x having SUM(POWER(cast(u as int),#order)) = x
option (maxrecursion 0);
This is a quick mod to my sum of digits UDF
Declare #Table table (Numbers int)
Insert into #Table values
(121),
(113),
(423),
(153),
(541),
(371)
Select * from #Table where [dbo].[udf-Stat-Is-Armstrong](Numbers)=1
Returns
Numbers
153
371
The UDF
CREATE Function [dbo].[udf-Stat-Is-Armstrong](#Val bigint)
Returns Bit
As
Begin
Declare #RetVal as bigint
Declare #LenInp as bigint = len(cast(#Val as varchar(25)))
;with i AS (
Select #Val / 10 n, #Val % 10 d
Union ALL
Select n / 10, n % 10
From i
Where n > 0
)
Select #RetVal = IIF(SUM(power(d,#LenInp))=#Val,1,0) FROM i;
Return #RetVal
End
You can use the following to find Armstrong numbers using Sql functions:
WITH Numbers AS(
SELECT 0 AS number UNION ALL SELECT number + 1 FROM Numbers WHERE number < 10000)
SELECT number AS ArmstrongNumber FROM Numbers
WHERE
number = POWER(COALESCE(SUBSTRING(CAST(number AS VARCHAR(10)),1,1),0),3)
+ POWER(COALESCE(SUBSTRING(CAST(number AS VARCHAR(10)),2,1),0),3)
+ POWER(COALESCE(SUBSTRING(CAST(number AS VARCHAR(10)),3,1),0),3)
OPTION(MAXRECURSION 0)

SQL - positive part function (x)^+

I want to get positive part of a number x in sql. It means that the result is x if x>0 and zero otherwise. I mean to use it after an aggregate function.
select 1 as num, 200 as weight into #table
insert into #table values
(8, 100),
(10, 200),
(11, -300),
(20, -100);
Till now I have been using the following:
select sum(num * weight)/sum(weight) as Result,
IIf(sum(num * weight)/sum(weight)>0, sum(num * weight)/sum(weight), 0) as PositivePartResult
from #table
But it is not clear as the function gets longer. Is there a built-in function to get the same result without repetition of the formula?
Another way of writing same query is:
select Result,
case when Result > 0 Then Result else 0 end as PositivePartResult
from
(
select sum(num * weight)/sum(weight) as Result
from #table
)T
You could either calculate the value inline or, if you'll be doing this frequently, create a user defined function:
create function PositiveValue( #N as Int )
returns Int as
begin
return ( Sign( #N ) + 1 ) / 2 * #N;
end;
go
declare #Samples as Table ( N Int );
insert into #Samples ( N ) values ( -42 ), ( -1 ), ( 0 ), ( 1 ), ( 42 );
select N, ( Sign( N ) + 1 ) / 2 * N as PositiveValue1, dbo.PositiveValue( N ) as PositiveValue2
from #Samples;
-- drop function dbo.PositiveValue;

Recursive UNION ALL to parse string taking very long

I am trying to speed up this recursive UNION ALL as shown below, but I cannot think how to do it. Maybe a while loop but I am not sure. The movement data is stored as one long string of encoded movement data and the script recursively calls the select statement to parse/extract this data and then it is all casted.
I would really like to understand more about speeding up recursive union all's or finding another way. I don't believe indexing is a problem so this is not really a possible solution.
"RouteData" is the long string that is parsed by fixed length intervals.
Here is a sample of the encoded data:
ScenarioPID : 3
LegID :1
RoutePart : 0x0000000000000000000100000000000000000000000000
RouteData : 0x40323AAAAAAAAAAB00013FA6FFD663CCA3310000001F00403 ... (goes on)
cnt : 37
sequence : 1
StartTime : 8828
The final output data looks like this for one track.
ScenarioPID LegID sequence TrackID Offset TimeOffset Length StartTime
3 1 1 1 0 0 6300 8828
3 1 2 1 0.0449 31 6300 8828
3 1 3 1 0.8942 325 6300 8828
3 1 4 1 0.9736 356 6300 8828
3 1 5 1 1 369 6300 8828
USE nss_demo;
DECLARE #scenario1 INT;
DECLARE #DAY_START INT;
DECLARE #DAY_END INT;
DECLARE #TRAIN_TYPE VARCHAR(50);
DECLARE #TRACK_TYPE VARCHAR(50);
SET #scenario1 = 3;
SET #DAY_START = 0;
SET #DAY_END = 7;
SET #TRAIN_TYPE = 'Empty Train';
SET #TRACK_TYPE = 'East Track';
DECLARE #KM_START INT;
DECLARE #KM_END INT;
SET #KM_START = 0;
SET #KM_END = 200;
WITH movement
AS (SELECT m.scenariopid,
m.legid,
Substring(routedata, 1, 23) AS RoutePart,
Substring(routedata, 24, Len(routedata) - 23) AS RouteData,
Len(routedata) / 23 - 1 AS cnt,
1 AS sequence,
m.starttime
FROM output.movement m
WHERE scenariopid = #scenario1
AND m.starttime BETWEEN ( #DAY_START * 86400 ) AND
( #DAY_END * 86400 )
UNION ALL
SELECT scenariopid,
legid,
Substring(m1.routedata, 1, 23) AS RoutePart
,
Substring(m1.routedata, 24,
Len(m1.routedata) - 23) AS RouteData,
Len(m1.routedata) / 23 - 1 AS cnt,
sequence + 1 AS sequence,
m1.starttime
FROM movement m1
WHERE m1.cnt > 0),
casttable
AS (SELECT tt.scenariopid,
tt.legid,
tt.sequence,
tt.trackid,
tt.offset,
tt.timeoffset,
tr.[length],
tt.starttime
FROM (SELECT scenariopid,
legid,
sequence,
Cast(trackidbin AS SMALLINT) AS TrackID,
Sign(Cast(offsetbin AS BIGINT)) *
( 1.0 +
( Cast(offsetbin AS BIGINT) & 0x000FFFFFFFFFFFFF ) *
Power(Cast(2 AS FLOAT), -52) )
*
Power(Cast(2 AS FLOAT), ( Cast(offsetbin AS BIGINT) &
0x7ff0000000000000
) /
0x0010000000000000
- 1023) AS Offset,
Cast(timebin AS INT) AS TimeOffset,
starttime AS StartTime
FROM (SELECT legid,
scenariopid,
sequence,
Substring(routepart, 9, 2) AS TrackIDBin,
Substring(routepart, 11, 8) AS OffsetBin,
Substring(routepart, 19, 4) AS TimeBin,
starttime
FROM movement) t) tt
INNER JOIN input.track tr
ON tr.trackid = tt.trackid
AND tr.scenariopid = tt.scenariopid)
SELECT *
FROM casttable
ORDER BY legid,
sequence
OPTION (maxrecursion 20000)
Use a Numbers Table (zero-based assumed below) to create CTE movement like this:
WITH movement
AS (SELECT m.scenariopid,
m.legid,
Substring(routedata, n.N*23 + 1, 23) AS RoutePart,
n.N AS cnt,
-- 1 AS sequence, -- use a row_number function here instead, as per your vendor.
m.starttime
FROM output.movement m
JOIN Numbers n
on n < Len(routedata) / 23
WHERE scenariopid = #scenario1
AND m.starttime BETWEEN ( #DAY_START * 86400 ) AND
( #DAY_END * 86400 )
),
-- etc.
If you don't have a static Numbers Table, my answer here demonstrates how to create one dynamically in a CTE.

SQL Data Sampling

We have had a request to provide some data to an external company.
They require only a sample of data, simple right? wrong.
Here is their sampling criteria:
Total Number of records divided by 720 (required sample size) - this gives sampling interval (if result is a fraction, round down to next whole number).
Halve the sampling interval to get the starting point.
Return each record by adding on the sampling interval.
EXAMPLE:
10,000 Records - Sampling interval = 13 (10,000/720)
Starting Point = 6 (13/2 Rounded)
Return records 6, 19 (6+13), 32 (19+13), 45 (32+13) etc.....
Please can someone tell me how (if) something like this is possible in SQL.
If you have use of ROW_NUMBER(), then you can do this relatively easily.
SELECT
*
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY a, b, c, d) AS record_id,
*
FROM
yourTable
)
AS data
WHERE
(record_id + 360) % 720 = 0
ROW_NUMBER() gives all your data a sequential identifier (this is important as the id field must both be unique and NOT have ANY gaps). It also defines the order you want the data in (ORDER BY a, b, c, d).
With that id, if you use Modulo (Often the % operator), you can test if the record is the 720th record, 1440th record, etc (because 720 % 720 = 0).
Then, if you offset your id value by 360, you can change the starting point of your result set.
EDIT
After re-reading the question, I see you don't want every 720th record, but uniformly selected 720 records.
As such, replace 720 with (SELECT COUNT(*) / 720 FROM yourTable)
And replace 360 with (SELECT (COUNT(*) / 720) / 2 FROM yourTable)
EDIT
Ignoring the rounding conditions will allow a result of exactly 720 records. This requires using non-integer values, and the result of the modulo being less than 1.
WHERE
(record_id + (SELECT COUNT(*) FROM yourTable) / 1440.0)
%
((SELECT COUNT(*) FROM yourTable) / 720.0)
<
1.0
declare #sample_size int, #starting_point int
select #sample_size = 200
select top (#sample_size) col1, col2, col3, col4
from (
select *, row_number() over (order by col1, col2) as row
from your_table
) t
where (row % ((select count(*) from your_table) / #sample_size)) - (select count(*) from your_table) / #sample_size / 2) = 0
It's going to work in SQL Server 2005+.
TOP (#variable) is used to limit rows (where condition because of integers rounding might not be enough, may return more rows then needed) and ROW_NUMBER() to number and order rows.
Working example: https://data.stackexchange.com/stackoverflow/query/62315/sql-data-sampling below code:
declare #tab table (id int identity(1,1), col1 varchar(3), col2 varchar(3))
declare #i int
set #i = 0
while #i <= 1000
begin
insert into #tab
select 'aaa', 'bbb'
set #i = #i+1
end
declare #sample_size int
select #sample_size = 123
select ((select count(*) from #tab) / #sample_size) as sample_interval
select top (#sample_size) *
from (
select *, row_number() over (order by col1, col2, id desc) as row
from #tab
) t
where (row % ((select count(*) from #tab) / #sample_size)) - ((select count(*) from #tab) / #sample_size / 2) = 0
SQL server has in-built function for it.
SELECT FirstName, LastName
FROM Person.Person
TABLESAMPLE (10 PERCENT) ;
You can use rank to get a row-number. The following code will create 10000 records in a table, then select the 6th, 19th, 32nd, etc, for a total of 769 rows.
CREATE TABLE Tbl (
Data varchar (255)
)
GO
DECLARE #i int
SET #i = 0
WHILE (#i < 10000)
BEGIN
INSERT INTO Tbl (Data) VALUES (CONVERT(varchar(255), NEWID()))
SET #i = #i + 1
END
GO
DECLARE #interval int
DECLARE #start int
DECLARE #total int
SELECT #total = COUNT(*),
#start = FLOOR(COUNT(*) / 720) / 2,
#interval = FLOOR(COUNT(*) / 720)
FROM Tbl
PRINT 'Start record: ' + CAST(#start as varchar(10))
PRINT 'Interval: ' + CAST(#interval as varchar(10))
SELECT rank, Data
FROM (
SELECT rank()
OVER (ORDER BY t.Data) as rank, t.Data AS Data
FROM Tbl t) q
WHERE ((rank + 1) + #start) % #interval = 0