2017-01-13 9 views
0
Background 

私のデータベースは、ユーザーとその変更するユーザー名を追跡しています。それぞれの実際の人は、時間の経過と共に多くのユーザー名を持つことができますが、1つだけが「最新」(現在のもの)です。これは、最新の日付と最新の日付を持つことで実現されます。最新のものであれば、toDateはNULLで、最新の列が1に設定されています。残念ながら、データは破損しています。最新フラグ。 もう1つのバグは、あるべきではないにしてもnullであるtoDateがあることです。データベースの不良データを修正してください。最新のフラグ

Question 

最新のフラグを1に設定/更新する必要がある行を見つけるにはどうすればよいですか? (今のところ2番目のバグは心配する必要はありませんが、最新のフラグを更新するための正しい行を見つけるのは難しいかもしれません)。

正しいSELECTは、次の例では行5と8(ただし行6は返さない)を返します。

Example 

PersonId = 1は正しい人です。 PERSONID = 2 5行に最新= 1が欠落していPERSONID = 3(行6に第二のバグ(toDateまで= null)を有し、第2のバグを回避するために行の最新= 1~8

が欠落しています行5)は、修正する必要のある行のfromDateが常に大きい(新しい)ことがわかります。

私が参加するために試みたが、私は右のそれを得ることができませんでした...ここで

は表「ユーザー」である:

+----+--------+----------+------------+------------+--------+ 
| id | name | personId | fromDate | toDate  | latest | 
+----+--------+----------+------------+------------+--------+ 
| 1 | Perold |  1 | 2016-12-01 | 2016-12-31 |  0 | 
| 2 | Pernew |  1 | 2016-12-31 | NULL  |  1 | 
| 3 | Body |  2 | 2016-01-01 | 2016-12-01 |  0 | 
| 4 | Bo  |  2 | 2016-12-01 | 2016-12-31 |  0 | 
| 5 | Bonew |  2 | 2016-12-31 | NULL  |  0 | <-- Wrong latest 
| 6 | Joe |  3 | 2016-01-01 | NULL  |  0 | <-- Wrong toDate, correct latest 
| 7 | Joey |  3 | 2016-12-01 | 2016-12-31 |  0 | 
| 8 | Jo  |  3 | 2016-12-31 | NULL  |  0 | <-- Wrong latest 
+----+--------+----------+------------+------------+--------+ 
+0

これはMySQL用ですか? – Strawberry

+0

はい、申し訳ありません。私はMySQL 5.7を使ってImを書いていたはずです。 – Miyagi

答えて

0

私は最終的に自分自身を考え出しました。ここに最終結果があります。私は参加しましたが、他のソリューションの助けを借りてそれを行いました。

SELECT u1.id 
    FROM USERS u1 
    INNER JOIN users u2 ON u2.id = u1.id AND u2.latest = 0 AND u2.todate is null 
    INNER JOIN 
    (
     SELECT personid, MAX(fromdate) max_date 
     FROM users ux 
     GROUP BY personId 
    ) x ON u2.personid = x.personid AND 
      u2.fromdate = x.max_date 
    WHERE NOT EXISTS(SELECT NULL FROM users u3 WHERE u1.PersonId = u3.PersonId AND u3.latest = 1); 

最初の内部結合では、NULLではない値を取り除かなければなりませんでした。それは実際のデータに現れました。最後の「存在しない場所」は、既に正しいユーザーを取り除くことです。

0

fromDateからは、常に値を持っていると主張し、各persnIdのDate-toDateからの間隔が密集していることが、ここに私の提案です。

まず、次のtoDate値を計算し、それがウィンドウ関数を持つpersonIdの最初のレコードか最後のレコードかを推測します。

次に、いくつかのルール(CASES)を適用して、無効な値を示すレコードに対してのみ有効な値を取得します。最後に、このレコードのみを取得するためにフィルタリングします。最後のレコードでは、元のレコード値とnewToDateレコードとnewLatestレコード値を確認できます。私たちは、あなたがユーザーごとに最大fromDateを見つけ、サブクエリで不正な行を見つけることができますnewX値(多分1または両方)#1については

SELECT * 
    FROM (SELECT id, 
       name, 
       personId 
       fromDate, 
       toDate, 
       latest, 
       CASE WHEN isFirst = 1 AND toDate IS NULL THEN nextValue 
        WHEN isLast = 0 AND toDate IS NULL THEN nextValue 
        ELSE NULL END newToDate, 
       CASE WHEN isLast <> latest 
        THEN isLast 
        ELSE NULL END newLatest 
      FROM (SELECT yourTable.*, 
         LEAD(yourTable.fromDate) OVER (PARTITION BY yourT able.personId ORDER BY yourTable.fromDate ASC) nextValue, 
         (CASE WHEN yourTable.fromDate = FIRST_VALUE(yourTable.fromDate) OVER (PARTITION BY yourTable.personId ORDER BY yourTable.fromDate ASC) 
          THEN 1 
          ELSE 0 END) AS isFirst, 
         (CASE WHEN yourTable.fromDate = FIRST_VALUE (yourTable.fromDate) OVER (PARTITION BY yourTable.personId ORDER BY yourTable.fromDate DESC) 
          THEN 1 
          ELSE 0 END) AS isLast 
        FROM yourTable)) 
WHERE newToDate IS NOT NULL 
    OR newLatest IS NOT NULL 
+1

これを動作させるのに問題がありました。それは「LEAD(...)OVER」が好きではなかった。理由は分かりません。私はMySQLの5.7を使用して、多分thatsなぜ...どのような場合にも助けてくれてありがとう。私の解決策は正しいと思うが、多分私は何かを逃した。 – Miyagi

1

を示しフィールドのみをupdeta必要があります。あなたはすでにあなたがそう#1を固定したら

SELECT u.id FROM users u WHERE u.latest = 0 
AND u.fromDate = (SELECT MAX(u_sorted.fromDate) FROM user u_sorted WHERE u_sorted.personId=u.personId); 

2番目の部分は簡単です:それは、次のようなlatest = 1

何か(私はこれをテストしていない)必要があります一つだけですlatest列に依存することができます。今度は、toDateがnullの最新のものを除いて、すべての行を検索する必要があります。

SELECT id FROM user WHERE latest = 0 AND toDate IS NULL; 

ここで唯一の方法は、これらの行を修正することです。不足しているtoDateを、その人の次の時系列のエントリのfromDateより1日早く設定したいと思うかもしれません。 (個人的には、toDate列を取り除き、is_active列のユーザーのプロファイルに置き換えますが、それは別のトピックです。)

注:上記のクエリは、fromDate列が破損しておらず、重複がなく、NULLではないことを前提としています。

+0

注:私は、ある人が非アクティブになった場合、最新のtoDateが記入されますが、最新のものはまだその行の1であると仮定しました。代わりにlatestを0に設定する必要がある場合は、最初のクエリを少し変更する必要があります。 – Bampfer

+0

私はそれを働かせることができませんでした...それは2番以外のすべてのIDを列挙しました。その行だけでなく、その特定の人の最新の日付を探したいと思います。または、おそらく私は内側の選択を理解していない... – Miyagi

+0

私はそこにpersonIdの代わりにidを使用しているように見えます。私は修正します。 – Bampfer

関連する問題