5

テーブルの写真を持っています

photos.id
photos.user_id
photos.order

A) 単一のクエリを使用して、すべての写真をユーザーごとにグループ化し、順序 1,2,3..N を更新することは可能ですか?

B) ひねりを加えると、一部の写真に既に注文値が関連付けられている場合はどうなるでしょうか? 新しい photos.order が繰り返されないようにし、既存の注文よりも低い注文または高い注文を (可能な限り) 満たすようにします。

私の唯一の考えは、これでスクリプトを実行し、それをループしてすべてを「並べ替える」ことですか?

photos.id int(10)
photos.created_at datetime
photos.order int(10)
photos.user_id int(10)

現在、データは次のようになっている可能性があります

user_id = 1
photo_id = 1
order = NULL

user_id = 2
photo_id = 2
order = NULL

user_id = 1
photo_id = 3
order = NULL

望ましい結果は

user_id = 1
photo_id = 1
order = 1

user_id = 2
photo_id = 2
order = 1

user_id = 1
photo_id = 3
order = 2
4

2 に答える 2

12

A)

各行でインクリメントし、各 user_ID でリセットする変数を使用して、行数を取得できます。

SELECT  ID,
        User_ID,
        `Order`
FROM    (   SELECT  @r:= IF(@u = User_ID, @r + 1,1) AS `Order`,
                    ID,
                    User_ID,
                    @u:= User_ID
            FROM    Photos,
                    (SELECT @r:= 1) AS r,
                    (SELECT @u:= 0) AS u
            ORDER BY User_ID, ID
        ) AS Photos

SQL Fiddle の例

B)

私の最初の解決策はOrder、行番号を追加する並べ替えに追加することでした。したがって、OrderGets が最初にその順序で並べ替えられたものはすべて、順序付けシステムにギャップがなく、1 から始まる場合にのみ機能します。

SELECT  ID,
        User_ID,
        RowNumber AS `Order`
FROM    (   SELECT  @r:= IF(@u = User_ID, @r + 1,1) AS `RowNumber`,
                    ID,
                    User_ID,
                    @u:= User_ID
            FROM    Photos,
                    (SELECT @i:= 1) AS r,
                    (SELECT @u:= 0) AS u
            ORDER BY User_ID, `Order`, ID
        ) AS Photos
ORDER BY `User_ID`, `Order`

Orderフィールドを使用した例

ギャップのある注文

最終的に、シーケンスにギャップがあってもソート順を維持する方法を見つけました。

SELECT  ID, User_ID, `Order`
FROM    Photos
WHERE   `Order` IS NOT NULL
UNION ALL
SELECT  Photos.ID,
        Photos.user_ID,
        Numbers.RowNum
FROM    (   SELECT  ID,
                    User_ID,
                    @r1:= IF(@u1 = User_ID,@r1 + 1,1) AS RowNum,
                    @u1:= User_ID 
            FROM    Photos,
                    (SELECT @r1:= 0) AS r,
                    (SELECT @u1:= 0) AS u
            WHERE   `Order` IS NULL
            ORDER BY User_ID, ID
        ) AS Photos
        INNER JOIN
        (   SELECT  User_ID,
                    RowNum,
                    @r2:= IF(@u2 = User_ID,@r2 + 1,1) AS RowNum2,
                    @u2:= User_ID 
            FROM    (   SELECT  DISTINCT p.User_ID, o.RowNum
                        FROM    Photos AS p,
                                (   SELECT  @i:= @i + 1 AS RowNum
                                    FROM    INFORMATION_SCHEMA.COLLATION_CHARACTER_SET_APPLICABILITY,
                                            ( SELECT @i:= 0) AS i
                                ) AS o
                        WHERE   RowNum <= (SELECT COUNT(*) FROM Photos P1 WHERE p.User_ID = p1.User_ID)
                        AND     NOT EXISTS
                                (   SELECT  1
                                    FROM    Photos p2
                                    WHERE   p.User_ID = p2.User_ID
                                    AND     o.RowNum = p2.`Order`
                                )
                        AND     p.`Order` IS NULL
                        ORDER BY User_ID, RowNum
                    ) AS p,
                    (SELECT @r2:= 0) AS r,
                    (SELECT @u2:= 0) AS u
            ORDER BY user_ID, RowNum
        ) AS numbers
            ON Photos.User_ID = numbers.User_ID
            AND photos.RowNum = numbers.RowNum2
ORDER BY User_ID, `Order`

ただし、ご覧のとおり、これはかなり複雑です。orderこれは、価値のあるものを価値のないものとは別に扱うことによって機能します。order一番上のクエリは、値のないすべての写真を各ユーザーの ID 順にランク付けするだけです。一番下のクエリは、クロス結合を使用して、ユーザー ID ごとに 1 から n までの順次リストを生成します (各 User_ID のエントリ数まで)。したがって、次のようなデータセットを使用します。

ID  User_ID Order
1   1       NULL
2   2       NULL
3   1       NULL
4   1       1
5   1       3
6   2       2
7   2       3

それは生成します

UserID  RowNum
1       1
1       2
1       3
1       4
2       1
2       2
2       3

次にNOT EXISTS、 null 以外の Photos で既に使用されているすべての組み合わせを削除するために使用しorder、 User_ID で分割された RowNum の順にランク付けします。

UserID  RowNum  Rownum2
1       2       1
1       4       2
2       1       1

次に、RowNum2 値を from サブクエリで得られた rownum 値と照合して、正しい値を得ることができorderます。長くなりましたが、うまくいきます。

SQL Fiddle の例

于 2012-06-11T16:18:36.613 に答える
0

私のために働いた。バージョンのグループ化を 4 つのフィールド (ホスト、フォルダー、ファイル名、ステータス)ずつインクリメントし、1 で並べ替える ( downloadedAtTicks ) 必要がありました。これは私のSELECTです

SET @status := NULL;
SET @version := NULL;
SELECT
  id,
  host,
  folder,
  fileName,
  status,
  downloadedAtTicks,
  version,
  IF(IF(status IS NULL, 0, status) = @status, @version := @version + 1, @version := 0) AS varVersion,
  @status := IF(status IS NULL, 0, status) AS varStatus
FROM csvsource
ORDER BY host, folder, fileName, status, downloadedAtTicks;

そして、これは私の更新です

SET @status := NULL;
SET @version := NULL;
UPDATE
    csvsource csv,
    (SELECT
       id,
       IF(IF(status IS NULL, 0, status) = @status, @version := @version + 1, @version := 0) AS varVersion,
       @status := IF(status IS NULL, 0, status) AS varStatus
     FROM csvsource
     ORDER BY host, folder, fileName, status, downloadedAtTicks) AS sub
SET
  csv.version = sub.varVersion
WHERE csv.id = sub.id;
于 2018-11-28T15:25:05.693 に答える