0

ユーザーが特定のファイルを過去または現在の日付に割り当てることができるシステムがあります。制限は、ユーザーごとに1日あたり1つのファイルしかアップロードできないことです。ユーザーがファイルをアップロードする場合、日付フィールドはデフォルトで現在の日付に設定されている必要があり、その日付が使用できない場合は、過去の最初の使用可能な日付がDESC順に表示されます。以下は、関連するフィールド名です。

file_id (INT - INDEX - AUTO INCREMENT)
user_id (INT - may index this)
upload_date (INT - stores date as a unix timestamp)

私が実際に見つけた唯一の解決策は、それらすべてをDESCの日付順に配列に組み込み、空のスロットが見つかるまでループすることです。ただし、ユーザーが過去1000日間を埋めていた場合、これは実際に速度の問題を引き起こす可能性があると思います。簡単な解決策を見落としているような気がします。

注意:何らかの理由で、日付はUnixタイムスタンプとして保存されていますが、これは欠点を理解しており、現時点では修正する必要はありません。

4

2 に答える 2

1

使用されていない最新の日付を取得するには:

select user_id, max(date) - 1
from (select ud.*,
             (select max(date) from upload_date ud2 where ud2.user_id = ud.user_id and ud2.date < ud.date
            ) as prevdate
      from upload_date ud
     ) ud
where date(from_unixtime(ud.prevdate)) <>  date(from_unixtime(ud.date)) - 1 or
      ud.prevdate is null
group by user_id

このクエリは、最初に、相関サブクエリを使用して、特定の日の前の日付を取得します。次に、時刻の値を日付に変換し、前の日付にギャップがある行を選択します。日付の最大値から1を引いたものが、探している日付です。

このSQLはテストされていないため、構文エラーが発生する可能性があります。

于 2013-02-07T00:16:43.417 に答える
1

これにアプローチする1つの方法は、従来の「欠落している行を返す」クエリを使用することです。基本的に、データベースから返される「欠落している」行を取得するには、「欠落している」行を生成する方法が必要です。

このようなクエリを作成するには、次のように開始できます。

SELECT MAX(t.upload_date)
  FROM mytable t
 WHERE t.upload_date <= NOW() 
   AND t.user = 'someuser'

これにより、最初の日付が取得されます。これから逆方向に作業します。

「1日1回」の要件の場合、少なくともこのクエリでは、upload_dateを深夜に切り捨てる必要があります。今のところ、UNIXタイムスタンプの処理の詳細にとらわれることなく、アプローチを説明するために、SELECTリストの式はすでに切り捨てられていると想定します。

前のクエリで取得した最初の日付から開始して、日付の降順リストを生成するには...

SELECT s.upload_date - INTERVAL n.d DAY AS available_date
  FROM ( SELECT MAX(t.upload_date) AS upload_date
           FROM mytable t
          WHERE t.upload_date <= NOW() 
            AND t.user = 'someuser'
       ) s
 CROSS
  JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
         UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 
         UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 
       ) n
 ORDER BY n.d DESC

その結果、結合防止パターンを使用して、まだ使用されていない日付を見つけることができます。これはLEFTJOINであり、一致する行をスローする述語です。

SELECT s.upload_date - INTERVAL n.d DAY AS available_date
  FROM ( SELECT MAX(t.upload_date) AS upload_date
           FROM mytable t
          WHERE t.upload_date <= NOW() 
            AND t.user = 'someuser'
       ) s
 CROSS
  JOIN ( SELECT 0 AS d UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
         UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 
         UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 
       ) n
  LEFT
  JOIN mytable u
    ON u.upload_date = s.upload_date - INTERVAL n.d DAY
   AND u.user = 'someuser'
 WHERE u.upload_date IS NULL 
 ORDER BY n.d DESC
 LIMIT 1

これは9日だけを振り返ります。さらに日を振り返るには、nとしてエイリアスされたインラインビューを拡張して、より多くの連続する整数を返します。(整数のボートロード全体を取得するためにクロス結合で遊ぶことができるいくつかのトリックがあります。)

残っているのは、「一致する」基準(MySQL DATEデータ型で機能する)に取り組んでいることだけです。

    ON u.upload_date = s.upload_date - INTERVAL n.d DAY

このようなものに:

    ON u.upload_date >= UNIX_TIMESTAMP(FROM_UNIXTIME(s.upload_date)-INTERVAL n.d+1 DAY)
   AND u.upload_date <  UNIX_TIMESTAMP(FROM_UNIXTIME(s.upload_date)-INTERVAL n.d DAY)

そして、整数のタイムスタンプ値をいじって、MySQLDATEを取得します...

 SELECT DATE(FROM_UNIXTIME(s.upload_date)) - INTERVAL n.d DAY AS available_date
于 2013-02-07T00:16:52.790 に答える