web-dev-qa-db-ja.com

一定の間隔での明確なランダム時間の生成

午前8時から午前8時の間にランダムな時間を生成しようとしていますPM各行はデータセットから選択されますが、常にsameランダムな値を取得します各行–私はそれを異なる各行

テーブルスキーマとデータ:

╔══════╦════════════════╗
║  ID  ║  CREATED_DATE  ║
╠══════╬════════════════╣
║ ID/1 ║   26/04/2014   ║
║ ID/2 ║   26/04/2014   ║
║ ID/3 ║   26/04/2014   ║
║ ID/4 ║   26/04/2014   ║
║ ID/5 ║   26/04/2014   ║
╚══════╩════════════════╝

СurrentSQLステートメント:

SELECT [ID]
     , MyFunction.dbo.AddWorkDays(14, [CREATED_DATE]) AS [New Date]
     , CONVERT(VARCHAR, DATEADD(MILLISECOND, CAST(43200000 * Rand() AS INT), CONVERT(TIME, '08:00')), 114) AS [New Time]
FROM [RandomTable]

現在の結果(同じ[New Time]列の各行の時間):

╔══════╦════════════════╦════════════════╗
║  ID  ║    New Date    ║    New Time    ║
╠══════╬════════════════╬════════════════╣
║ ID/1 ║   10/05/2014   ║    09:41:43    ║
║ ID/2 ║   10/05/2014   ║    09:41:43    ║
║ ID/3 ║   10/05/2014   ║    09:41:43    ║
║ ID/4 ║   10/05/2014   ║    09:41:43    ║
║ ID/5 ║   10/05/2014   ║    09:41:43    ║
╚══════╩════════════════╩════════════════╝

望ましい結果(異なる[New Time]列の各行の時間):

╔══════╦════════════════╦════════════════╗
║  ID  ║    New Date    ║    New Time    ║
╠══════╬════════════════╬════════════════╣
║ ID/1 ║   10/05/2014   ║    09:41:43    ║
║ ID/2 ║   10/05/2014   ║    15:05:23    ║
║ ID/3 ║   10/05/2014   ║    10:01:05    ║
║ ID/4 ║   10/05/2014   ║    19:32:45    ║
║ ID/5 ║   10/05/2014   ║    08:43:15    ║
╚══════╩════════════════╩════════════════╝

これを修正する方法についてのアイデアはありますか?上記はすべてサンプルデータです。私の実際のテーブルには約2800レコードがあります(それが誰かの提案に違いをもたらすかどうかはわかりません)。

29
AMC

元の質問の解釈:

質問は次のように述べています。

  • ランダム午前8時から午前8時までの時間を生成PM(つまり、12時間のウィンドウ)
  • 異なる必要があります行ごとに(つまり、すべての行で一意)
  • 実際のテーブルには約2800のレコードがあります

ここで、次の点を考慮に入れてください。

  • サンプルデータは単一の日付のみを示しています
  • 24時間で86,400秒、つまり12時間で43,200秒

次の領域にはいくつかのあいまいさがあります。

  • 真にランダムな値がすべての行で異なることを保証できないことを考えると、「異なるすべての行 "」のコンテキスト内で正確にランダムなものは何ですか。実際、truly乱数could理論的にはすべての行でsameになります。では、「ランダム」または「異なる」に重点が置かれているのでしょうか。それとも、(実際にはランダムではなくランダムに見えるようにするために)実際には異なるが順番に並べられていないことについて話しているのでしょうか?
  • 2800行を超える場合はどうなりますか? 100万行ある場合はどうなりますか?
  • 43,200を超える行が存在する可能性がある場合、「異なる行ごとに」を処理する方法(すべての行で一意にすることはできないため)?
  • 日付は変わるのでしょうか?もしそうなら、私たちは本当に「行ごとに異なる日付ごと」について話しているのですか?
  • 「行ごとに異なる日付ごと ":
    • 各日付の時刻は、同じ非連続パターンに従うことができますか?または、パターンは日付ごとに異なる必要がありますか?
    • 特定の日付で43,200行を超えることはありますか?その場合、時間は一意にすることができます43,200行の各セットごと

上記の情報を前提として、リクエストを解釈する方法はいくつかあります。

  1. 「ランダム」の強調:日付と行数は関係ありません。他の回答に示されている3つの方法のいずれかを使用して、一意である可能性が高いが、保証ではない真にランダムな時間を生成します。
    • @notulysses:Rand(CAST(NEWID() AS VARBINARY)) * 43200
    • @スティーブフォード:ABS(CHECKSUM(NewId()) % 43201)
    • @ウラジーミルバラノフ:CAST(43200000 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) as int)
  2. 「行ごとに異なる」を強調し、常に<= 43,200行:行数が使用可能な秒数を超えない場合は、簡単に実行できます。同じ日付または異なる日付に関係なく、すべての行で一意の時刻を保証し、ランダムに順序付けられているように見えます。
  3. 「行ごとに異なる」を強調すると、43,200行を超える可能性があります:行数が使用可能な秒数を超える可能性がある場合、そうではありませんall行全体の一意性を保証することは可能ですが、特定の日付に43,200行を超える行がない場合は、特定の日付の行全体の一意性を保証することもできます。

したがって、私は次のような考えに基づいて答えました。

  • OPの行数が2800を超えない場合でも、同様のランダム性の必要性に直面している他のほとんどの人は、より大きなデータセットを使用できる可能性が高くなります(つまり、任意の数で100万行になる可能性があります)日付の:1、5000など)
  • サンプルデータは、5行すべてに同じ日付を使用するのが非常に単純であるか、この特定のケースではすべての行に日付が同じであっても、他のほとんどの場合、発生する可能性は低くなります。
  • 一意性はランダム性よりも優先されます
  • 各日付の秒の「一見ランダムな」順序付けにパターンがある場合、ランダム性の外観を与えるために、日付全体でシーケンスの開始に少なくとも変化するオフセットが必要です(日付が順番に並べられている場合)。日付の小さなグループ間。

回答:

状況に固有の時間が必要な場合、真にランダムな値を生成する方法ではそれを保証できません。 @Vladimir Baranovによる_CRYPT_GEN_RANDOM_の使用は本当に好きですが、一意の値のセットを生成することはほぼ不可能です。

_DECLARE @Table TABLE (Col1 BIGINT NOT NULL UNIQUE);

INSERT INTO @Table (Col1)
    SELECT CONVERT(BIGINT, CRYPT_GEN_RANDOM(4))
    FROM [master].sys.objects so
    CROSS JOIN [master].sys.objects so2
    CROSS JOIN [master].sys.objects so3;
    -- 753,571 rows
_

ランダムな値を8バイトに増やすことはうまくいくようです:

_DECLARE @Table TABLE (Col1 BIGINT NOT NULL UNIQUE);

INSERT INTO @Table (Col1)
    SELECT CONVERT(BIGINT, CRYPT_GEN_RANDOM(8))
    FROM [master].sys.objects so
    CROSS JOIN [master].sys.objects so2
    CROSS JOIN [master].sys.objects so3;
    -- 753,571 rows
_

もちろん、2番目まで生成している場合、それらは86,400個しかありません。以下が時折機能するため、スコープを縮小すると役立つようです。

_DECLARE @Table TABLE (Col1 BIGINT NOT NULL UNIQUE);

INSERT INTO @Table (Col1)
    SELECT TOP (86400) CONVERT(BIGINT, CRYPT_GEN_RANDOM(4))
    FROM [master].sys.objects so
    CROSS JOIN [master].sys.objects so2
    CROSS JOIN [master].sys.objects so3;
_

ただし、一意性が必要な場合は少し注意が必要です毎日(これは、すべての日で一意であるのではなく、このタイプのプロジェクトの合理的な要件のようです)。しかし、乱数ジェネレーターは、新しい日にリセットすることを知りません。

単にランダムに見えるだけでよい場合は、次のことを行わなくても、日付ごとに一意性を保証できます。

  • ループ/カーソル構成
  • すでに使用されている値をテーブルに保存する
  • Rand()NEWID()、またはCRYPT_GEN_RANDOM()を使用する

次のソリューションでは、この回答で学習した モジュラ逆数 (MMI)の概念を使用しています。 SQL Serverで一見ランダムな一意の数値IDを生成する 。もちろん、その質問には、ここにあるような厳密に定義された値の範囲はなく、1日あたり86,400個しかありませんでした。そこで、86400の範囲(「モジュロ」として)を使用し、 オンライン計算機 でいくつかの「互いに素」の値(「整数」として)を試して、MMIを取得しました。

  • 13(MMI = 39877)
  • 37(MMI = 51373)
  • 59(MMI = 39539)

私はCTEでROW_NUMBER()を使用し、1日の各秒に値を割り当てる手段として_CREATED_DATE_でパーティション化(つまりグループ化)しています。

ただし、秒0、1、2、...などで生成された値はランダムに表示されますが、異なる日をまたいで、その特定の秒は同じ値にマップされます。したがって、2番目のCTE( "WhichSecond"という名前)は、日付をINT(1900-01-01からの順次オフセットに変換する)に変換してから、101を掛けることにより、各日付の開始点をシフトします。

_DECLARE @Data TABLE
(
  ID INT NOT NULL IDENTITY(1, 1),
  CREATED_DATE DATE NOT NULL
);

INSERT INTO @Data (CREATED_DATE) VALUES ('2014-10-05');
INSERT INTO @Data (CREATED_DATE) VALUES ('2014-10-05');
INSERT INTO @Data (CREATED_DATE) VALUES ('2014-10-05');
INSERT INTO @Data (CREATED_DATE) VALUES ('2014-10-05');
INSERT INTO @Data (CREATED_DATE) VALUES ('2014-10-05');
INSERT INTO @Data (CREATED_DATE) VALUES ('2015-03-15');
INSERT INTO @Data (CREATED_DATE) VALUES ('2016-10-22');
INSERT INTO @Data (CREATED_DATE) VALUES ('2015-03-15');

;WITH cte AS
(
  SELECT tmp.ID,
         CONVERT(DATETIME, tmp.CREATED_DATE) AS [CREATED_DATE],
         ROW_NUMBER() OVER (PARTITION BY tmp.CREATED_DATE ORDER BY (SELECT NULL))
                      AS [RowNum]
  FROM   @Data tmp
), WhichSecond AS
(
  SELECT cte.ID,
         cte.CREATED_DATE,
         ((CONVERT(INT, cte.[CREATED_DATE]) - 29219) * 101) + cte.[RowNum]
                      AS [ThisSecond]
  FROM   cte
)
SELECT parts.*,
       (parts.ThisSecond % 86400) AS [NormalizedSecond], -- wrap around to 0 when
                                                         -- value goes above 86,400
       ((parts.ThisSecond % 86400) * 39539) % 86400 AS [ActualSecond],
       DATEADD(
                 SECOND,
                 (((parts.ThisSecond % 86400) * 39539) % 86400),
                 parts.CREATED_DATE
              ) AS [DateWithUniqueTime]
FROM WhichSecond parts
ORDER BY parts.ID;
_

戻り値:

_ID  CREATED_DATE  ThisSecond  NormalizedSecond  ActualSecond  DateWithUniqueTime
1   2014-10-05    1282297     72697             11483         2014-10-05 03:11:23.000
2   2014-10-05    1282298     72698             51022         2014-10-05 14:10:22.000
3   2014-10-05    1282299     72699              4161         2014-10-05 01:09:21.000
4   2014-10-05    1282300     72700             43700         2014-10-05 12:08:20.000
5   2014-10-05    1282301     72701             83239         2014-10-05 23:07:19.000
6   2015-03-15    1298558      2558             52762         2015-03-15 14:39:22.000
7   2016-10-22    1357845     61845             83055         2016-10-22 23:04:15.000
8   2015-03-15    1298559      2559              5901         2015-03-15 01:38:21.000
_

午前8時から午後8時までの時間のみを生成する場合は、いくつかの小さな調整を行うだけで済みます。

  1. 範囲(「モジュロ」として)を86400からその半分に変更します:43200
  2. MMIを再計算します(「整数」と同じ「互いに素」の値を使用できます):39539(以前と同じ)
  3. _28800_をDATEADDの2番目のパラメーターに8時間のオフセットとして追加します

その結果、1行だけに変更されます(他の行は診断用であるため)。

_-- second parameter of the DATEADD() call
28800 + (((parts.ThisSecond % 43200) * 39539) % 43200)
_

予測しにくい方法で毎日シフトする別の方法は、「WhichSecond」CTEで_CREATED_DATE_のINT形式を渡すことによってRand()を利用することです。 Rand(x)は渡されたyの同じ値に対して同じ値xを返しますが、渡されたyの異なる値に対して異なる値xを返すため、これにより各日付ごとに安定したオフセットが得られます。意味:

Rand(1)= y1
Rand(2)= y2
Rand(3)= y3
Rand(2)= y2

2回目にRand(2)が呼び出されたときでも、最初に呼び出されたときに返したのと同じ_y2_の値が返されました。

したがって、「WhichSecond」CTEは次のようになります。

_(
  SELECT cte.ID,
         cte.CREATED_DATE,
         (Rand(CONVERT(INT, cte.[CREATED_DATE])) * {some number}) + cte.[RowNum]
                      AS [ThisSecond]
  FROM   cte
)
_
12
Solomon Rutzky

Rand()だけを使用しているときに発生した問題[〜#〜] op [〜#〜]は、評価ごとに1回発生します。クエリ

ドキュメント :から

seedが指定されていない場合、SQL Serverデータベースエンジンはseed値をランダムに割り当てます。指定されたseed値の場合、返される結果は常に同じです。

以下で説明するアプローチでは、最適化が削除され、この動作が抑制されるため、Rand()が評価されます行ごとに1回

_dateadd( second
       , Rand(cast(newid() as varbinary)) * 43200
       , cast('08:00:00' as time) )
_
  • newid() タイプの一意の値を生成します uniqueidentifier ;
  • 値はcastで変換され、疑似ランダムを生成するための Rand([seed]) 関数でseedとして使用されますfloat0から1までの値、およびseedは常に一意であるため、戻り値も一意です。

SQLFiddle

25
potashin

または、次を使用することもできます。

_SELECT DATEADD(s, ABS(CHECKSUM(NewId()) % 43201), CAST('08:00:00' AS Time))
_

ABS(CHECKSUM(NewId()) % 43201)は、_0_と_43200_の間の乱数を生成します。 ここでの議論 を参照してください。

SQLフィドル

MS SQL Server 2008スキーマセットアップ

クエリ1

_SELECT DATEADD(s, ABS(CHECKSUM(NewId()) % 43201), CAST('08:00:00' AS Time)) AS [RandomTime]
FROM 
( VALUES (1), (2), (3), (4), (5)
) Y(A)
CROSS JOIN
( VALUES (1), (2), (3), (4), (5)
) Z(A)
_

結果

_|    RANDOMTIME    |
|------------------|
| 16:51:58.0000000 |
| 10:42:44.0000000 |
| 14:01:38.0000000 |
| 13:33:51.0000000 |
| 18:00:51.0000000 |
| 11:29:03.0000000 |
| 10:21:14.0000000 |
| 16:38:27.0000000 |
| 09:55:37.0000000 |
| 13:21:13.0000000 |
| 11:29:37.0000000 |
| 10:57:49.0000000 |
| 14:56:42.0000000 |
| 15:33:11.0000000 |
| 18:49:45.0000000 |
| 16:23:28.0000000 |
| 09:00:05.0000000 |
| 09:20:01.0000000 |
| 11:26:23.0000000 |
| 15:26:23.0000000 |
| 10:38:44.0000000 |
| 11:46:30.0000000 |
| 16:00:59.0000000 |
| 09:29:18.0000000 |
| 09:09:19.0000000 |
_
15
Steve Ford

いくつかの方法があります。

  • 事前に乱数を使用してテーブルを生成し、必要に応じて使用します。または、このデータを 信頼できるソース から取得します。
  • NEWID 関数を使用してRandのシードを提供するさまざまな組み合わせ。 NEWID値の配布についての保証はないため、注意して使用する必要があります。多かれ少なかれ均一に分散させるための最良の方法の1つは、CHECKSUMRand(CHECKSUM(NEWID()))を使用することです。この方法の良いところは、SQL Server2000以降でNEWID関数が使用できることです。
  • NEWIDの代わりに、たとえば、ある列のMD5をRandのシードとして使用します:Rand(CHECKSUM(HASHBYTES('MD5', CAST(SomeID AS varbinary(4)))))または単に行番号:Rand(CHECKSUM(HASHBYTES('MD5', CAST(ROW_NUMBER() OVER(ORDER BY ...) AS varbinary(4)))))。このメソッドは、少なくともSQL Server2005以降で使用できます。NEWIDメソッドとの主な違いは、ランダムシーケンスを完全に制御できることです。 NEWIDが返すものを制御することはできず、同じ番号からランダムシーケンスを再開することもできません。たとえば、_PARTITION BY_を使用して同じ行番号のセットを指定すると、同じ乱数のセットが得られます。同じ乱数シーケンスを数回使用する必要がある場合に役立つことがあります。 2つの異なるシードに対して同じ乱数を取得することが可能です。 1から1,000,000までの行番号でテストしました。それらの_MD5_はすべて異なります。 _MD5_のCHECKSUMは、122回の衝突を引き起こします。このRandCHECKSUMは、246回の衝突を引き起こします。 1から100,000までの行番号でテストした場合、CHECKSUMには1回の衝突があり、Randには3回の衝突がありました。
  • もう1つの可能性は、好みのアルゴリズムを使用して乱数を生成する独自のユーザー定義関数をT-SQLに実装することです。この場合、すべてを完全に制御できます。通常、疑似ランダムジェネレーターは、呼び出しの間に内部状態を格納する必要があるため、このデータを格納する専用のテーブルが作成される可能性があります。
  • CLRを使用してユーザー定義関数を記述できます。この場合、独自のジェネレーターを実装するか、 Random classRNGCryptoServiceProvider class などの.NETに組み込まれている関数を使用できます。 。
  • 最後に、SQL Server 2008以降、組み込み関数 _CRYPT_GEN_RANDOM_ があります。

最後の方法について詳しく説明します。これは、SQL Server2008以降にとって非常に優れたソリューションだと思うからです。 _CRYPT_GEN_RANDOM_は、1回だけ呼び出されるRandとは対照的に、結果セットの各行に対して呼び出されます。

CRYPT_GEN_RANDOM(Transact-SQL)

Crypto API(CAPI)によって生成された暗号化乱数を返します。出力は、指定されたバイト数の16進数です。

さらに、_CRYPT_GEN_RANDOM_は、Randよりもはるかに優れたランダム値を提供する必要があります。配布と暗号強度の点で優れています。例:

_(CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5)
_

これにより、4つのランダムバイトがvarbinaryとして生成されます。最初にそれらを明示的にintにキャストする必要があります。次に、結果は0から1の間の浮動小数点数に変換されます。

したがって、元のクエリは次のようになります。

_SELECT ID AS [ID]
     , MyFunction.dbo.AddWorkDays(14, S.CREATED_DATE) AS [New Date]
     , CONVERT(VARCHAR, DATEADD(MILLISECOND, 
     CAST(43200000 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) as int),
     CONVERT(TIME, '08:00')), 114) AS [New Time]
FROM RandomTable
_

これは、コピーアンドペーストして試すのが簡単なスタンドアロンの例です(@Steve Fordによる別の回答からのクエリを使用しました):

_SELECT DATEADD(millisecond, 
    CAST(43200000 * (CAST(CRYPT_GEN_RANDOM(4) as int) / 4294967295.0 + 0.5) as int), 
    CAST('08:00:00' AS Time)) AS [RandomTime]
FROM 
    ( VALUES (1), (2), (3), (4), (5)
    ) Y(A)
    CROSS JOIN
    ( VALUES (1), (2), (3), (4), (5)
    ) Z(A)
_

結果は次のとおりです。

_RandomTime
10:58:24.7200000
19:40:06.7220000
11:04:29.0530000
08:57:31.6130000
15:03:14.9470000
09:15:34.9380000
13:46:43.1250000
11:27:00.8940000
14:42:23.6100000
15:07:56.2120000
11:39:09.8830000
08:16:44.3960000
14:23:38.4820000
17:28:31.7440000
16:29:31.4320000
09:09:15.0210000
12:31:09.8370000
11:23:09.8430000
15:35:45.5480000
17:42:49.3390000
08:07:05.4930000
18:17:16.2980000
11:49:08.2010000
10:20:21.7620000
15:56:58.6110000
_

添加

元の質問を読んだとき、生成されたすべての乱数が一意であることを確認する必要があるとは思いませんでした。質問の「異なる」という単語は、単純なSELECT Rand()を使用したときに表示される結果の各行に同じ番号が表示されるのとは正反対の漠然としたものとして解釈しました。衝突する乱数が少なくても問題ない場合が多いと思います。多くの場合、それは実際には正しい動作です。

したがって、私の理解では、一意の乱数のシーケンスが必要な場合、それはある意味で次のタスクと同等です。いくつかの値/行のセットがあります。たとえば、一意のIDのセット、1日の86400秒すべて、または特定の日の2800行です。これらの値/行をシャッフルしたいと思います。これらの行をランダムな順序で再配置します。

指定された行のセットをシャッフルするには、乱数を_ORDER BY_する必要があります(これらの乱数には、ここで妥当な量の衝突がある可能性があります)。乱数は、どのような方法でも生成できます。このようなもの:

_ROW_NUMBER() OVER ([optional PARTITION BY ...] ORDER BY CRYPT_GEN_RANDOM(4)) 
_

または文字通り

_SELECT ...
FROM ...
ORDER BY CRYPT_GEN_RANDOM(4)
_

どこでどのように使用されるかによって異なります。

7

これをテストします:

 Declare @t table(ID int,CREATED_DATE datetime)
insert into @t values
 (1 ,  '04/26/2014'),
 (2 ,  '04/26/2014'),
 (3 ,  '04/26/2014'),
 (4 ,  '04/26/2014')

 ;WITH CTE AS
 (
   SELECT *,CONVERT(VARCHAR, DATEADD(SECOND, Rand(CAST(NEWID() AS VARBINARY)) * 43200, 
   CAST('08:00:00' AS TIME)),114) AS [New Time] FROM @t WHERE ID=1
   UNION ALL
   SELECT *,CONVERT(VARCHAR, DATEADD(SECOND, Rand(CAST(NEWID() AS VARBINARY)) * 43200, 
   CAST('08:00:00' AS TIME)), 114)  FROM @t WHERE ID>1 AND ID<=5
 )
 SELECT * FROM CTE
3
KumarHarsh

これは、時間の生成方法をもう少し制御できる別のオプションです。ランダムな時間の間隔を指定できます。また、Rand関数も使用しません。

DECLARE @StartTime  VARCHAR(10) = '08:00',
        @EndTime    VARCHAR(10) = '20:00',
        @Interval   INT = 5 --(In Seconds)

WITH times AS(
    SELECT CONVERT(TIME, @StartTime) AS t
    UNION ALL
    SELECT DATEADD(SECOND, @Interval, t)
    FROM times
    WHERE t < @EndTime
)

SELECT *, 
(SELECT TOP 1 t FROM times WHERE d.Id > 0 ORDER BY NEWID())
FROM #data d
option (maxrecursion 0)

補足:
上記のサブクエリでWHERE句を削除した場合(WHERE d.Id > 0)、すべての行に同じ時間値が返されます。つまり、最初に使用したのと同じ問題です。

2
Spock

すべて、

私は自分の質問に対する答えを共有したいと思いました。詳細をどこで見つけたか正確に思い出せません-それはsgeddesによって提供されたリンクの1つを経由したものだと思います。

次のクエリを使用して、午前8時から午後7時55分までのランダムな時間を取得しました(おおよそ)

SELECT convert(varchar,CONVERT(varchar, DATEADD(ms, dbo.MyRand(335 ,830) * 86400, 0), 114),114)

MyRand関数は以下のとおりです。

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
CREATE FUNCTION dbo.myRand(@Min INT, @Max INT) RETURNS decimal(18,15) AS
BEGIN
DECLARE @BinaryFloat BINARY(8)
SELECT @BinaryFloat = CAST(Id AS BINARY) FROM vwGuid

DECLARE
@PartValue TINYINT,
@Mask TINYINT,
@Mantissa FLOAT,
@Exponent SMALLINT,
@Bit TINYINT,
@Ln2 FLOAT,
@BigValue BIGINT,
@RandomNumber FLOAT

SELECT
@Mantissa = 1,
@Bit = 1,
@Ln2 = LOG(2),
@BigValue = CAST(@BinaryFloat AS BIGINT),
@Exponent = (@BigValue & 0x7ff0000000000000) / EXP(52 * @Ln2)

WHILE @Part <= 8
BEGIN
SELECT
@PartValue = CAST(SUBSTRING(@BinaryFloat, @Part, 1) AS TINYINT),
@Mask =

WHILE @Mask > 0
BEGIN
IF @PartValue & @Mask > 0
SET @Mantissa = @Mantissa + EXP(-@Bit * @Ln2)

SELECT
@Mask = @Mask / 2
END
END

SET @RandomNumber = CASE @Exponent WHEN 0 THEN 0 ELSE CAST(@Exponent AS FLOAT) / 2047 END

RETURN CAST((@RandomNumber * (@Max - @Min)) + @Min AS DECIMAL(18,15))

END
GO
END

これがお役に立てば幸いです。私は上記の返信の多くを読んでいないので、誰かがより良い答えを持っている場合はお詫びします-これは単に私がそれを解決した方法です。

ありがとう

0
AMC