1

SOの質問は、私を次の質問に導きました。

テーブルに16行ある場合、ランダムに配置された番号1、2、3、4、5、...、16のフィールドをテーブルに追加します。つまり、行1の「RndVal」フィールドに次のようになります。 2、次に行2の場合は5になる可能性があります。つまり、16個の整数のそれぞれが繰り返しなしで1回出現する必要があります。

次の機能が機能しないのはなぜですか?理想的には、これが機能することを確認してから、代替ソリューションを確認したいと思います。

これにより、テーブルが正常に作成されます。

IF OBJECT_ID('tempdb..#A') IS NOT NULL BEGIN DROP TABLE #A END
IF OBJECT_ID('tempdb..#B') IS NOT NULL BEGIN DROP TABLE #B END
IF OBJECT_ID('tempdb..#C') IS NOT NULL BEGIN DROP TABLE #C END
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL BEGIN DROP TABLE #myTable END

CREATE TABLE #B (B_ID INT)
CREATE TABLE #C (C_ID INT)

INSERT INTO #B(B_ID) VALUES
    (10),
    (20),
    (30),
    (40)
INSERT INTO #C(C_ID)VALUES
    (1),
    (2),
    (3),
    (4)

CREATE TABLE #A 
    (
    B_ID INT
    , C_ID INT
    , RndVal INT
    )

INSERT INTO #A(B_ID, C_ID, RndVal)  
SELECT 
        #B.B_ID
        , #C.C_ID
        , 0 
FROM #B CROSS JOIN #C; 

次に、以下を使用してランダム列を追加しようとしています。ロジックは、1から16までの乱数を追加し、ループ内で他の数値と重複しているものを効果的に上書きすることです。

SELECT 
    ROW_NUMBER() OVER(ORDER BY B_ID) AS Row
    , B_ID
    , C_ID
    , RndVal
INTO #myTable
FROM #A

DECLARE @rowsRequired INT = (SELECT COUNT(*) CNT FROM #myTable)
DECLARE @i INT = (SELECT @rowsRequired - SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable)--0


DECLARE @end INT = 1
WHILE @end > 0 
    BEGIN

            SELECT @i = @rowsRequired -  SUM(CASE WHEN RndVal > 0 THEN 1 ELSE 0 END) FROM #myTable
            WHILE @i>0
                BEGIN

                    UPDATE x
                    SET x.RndVal = FLOOR(RAND()*@rowsRequired)
                    FROM #myTable x
                    WHERE x.RndVal = 0 

                    SET @i = @i-1
                END 

         --this is to remove possible duplicates
            UPDATE c 
            SET c.RndVal = 0 
            FROM 
                #myTable c
                INNER JOIN 
                    (
                    SELECT RndVal
                    FROM #myTable
                    GROUP BY RndVal 
                    HAVING COUNT(RndVal)>1
                    ) t
                    ON 
                        c.RndVal = t.RndVal

         SET @end = @@ROWCOUNT

    END

TRUNCATE TABLE #A
INSERT INTO #A
SELECT 
    B_ID
    , C_ID
    , RndVal
FROM #myTable

元のテーブルに6行ある場合、結果は次のようになります。

B_ID|C_ID|RndVal
----------------
    |    | 5 
    |    | 4
    |    | 1
    |    | 6
    |    | 3
    |    | 2
4

3 に答える 3

2

率直に言って、あなたのコードがわかりません

これにより、各行が乱数で更新されます。1からテーブル内の行数までの繰り返しのない数値です。

UPDATE T
SET SomeCol = T2.X
FROM
   MyTable T
   JOIN
   (
   SELECT
      KeyCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
   FROM 
      MyTable
   ) T2 ON T.KeyCol = T2.KeyCol 

これはより簡潔ですが、期待どおりに機能するかどうかをテストすることはできません

UPDATE T
SET SomeCol = X
FROM
   (
   SELECT
      SomeCol, ROW_NUMBER() OVER (ORDER BY NEWID()) AS X
   FROM 
      MyTable
   ) T
于 2012-07-24T17:47:43.447 に答える
1

TOP(1)(最初のRndVal = 0レコードを更新する必要があるため)と+1(ゼロマークは何も意味しないため)を更新に追加すると、物事が動き始めます。しかし、非常にゆっくりです(私のかなり時代遅れのラップトップでは約40秒)。これは、#myTableが生成された乱数でいっぱいになると、欠落している番号を取得する可能性が低くなるためです。通常、重複し、最初からやり直す必要があります。

UPDATE top (1) x
SET x.RndVal = FLOOR(RAND()*@rowsRequired) + 1
FROM #myTable x
WHERE x.RndVal = 0 

もちろん、@gbnには完全に有効な解決策があります。

于 2012-07-24T18:08:15.877 に答える
0

これは基本的に前の回答と同じですが、コードに固有です。

;WITH CTE As
(
    SELECT B_ID, C_ID, RndVal, 
    ROW_NUMBER() OVER(ORDER BY NewID()) As NewOrder
    FROM #A
)

UPDATE  CTE
SET     RndVal = NewOrder

SELECT * FROM #A ORDER BY RndVal
于 2012-07-24T17:58:22.503 に答える