2012-10-05 5 views
6

私はここで同様のタイプの質問を見ましたが、どれも私の状況を助けませんでした。IDと最新の日時によるMySQLグループ

私は、テーブルには(MySQLのMyISAMテーブルを使用して)テスト

テストは、次のスキーマを持って言うことができますがあります。

TID INT PRIMARY KEY AUTO_INCREMENT 
    TData varchar (data that i want to select) 
    TUserID INT (this will be joined with users table, same users can have many records here) 
    TViewedAt DATETIME (records each time user visits page, datetime format) 

今テストページは現在ログインしているユーザーが訪問するたびに、それがレコードを追加このテーブルには、訪問した人のユーザID、TIDを使用してユーザが訪れた日付と時刻、毎回自動的に増分されるデータおよび日付が記録される。

次に、どのユーザーがテストページにアクセスしたか、何回何回、データをいつ見ることができるかをバックエンド管理ページがあります。基本的に20-25の最新行のリストを持つテーブル。マイクエリーはデータごとに1つのレコードのみを選択する必要があります。データはユーザーのために同じ時間にすることができますが、時間は異なりますが、ユーザーごとに最新のデータを1つだけ選択したいだけです。したがって、ユーザーがテストページを10回訪問した場合、10レコードはデータベースに送られますが、テーブルには最新のレコードが1つしか表示されません。別のユーザーがページ15を訪れた場合、この2番目のユーザーの1つのレコードが表示されます。これは最新のもので、合計で2つの行が表に表示されます。何らかの理由でGROUP BYで動作するようになっていますが、MAX(date)は日付ごとに最新のdatetimeを与えません。そのうち

SELECT * 
    FROM Test 
    WHERE TUserID = 123 
    GROUP BY TData 
    ORDER BY TViewedAt 

戻って2行をそれらの行のどれが最新ではない:

は、ここに私のクエリです。

おかげでたくさん

答えて

11

私は以下であなたが必要とするものを達成することができると考えています。これらの操作は「グループワイズ最大」と呼ばれています。 maxGroup Byと一緒に使用されているので、我々はのためにすべてのデータを取得するために他のクエリを行うよりも

オプション1

これは理解するのが最も簡単で、サブクエリは、すべてのユーザーに対して最大TIDを返します。それらのID。

Select TID, TData, TUserID, TViewedAt 
From Test 
Where TID In(
    Select Max(TID) 
    From Test 
    Group By TUserID 
) 

オプション2

もう少し複雑に理解することは、可能性が最も高い、より効率的に、これはt1.TViewedAtはその最大値にあるとき、大きな値とはt2.TViewedAtが存在しないということに基づいて動作し、 t2行の値はNULLになります。クエリ後

SELECT t1.TID, t1.TData, t1.TUserID, t1.TViewedAt 
FROM Test t1 
LEFT JOIN Test t2 ON t1.TUserID = t2.TUserID AND t1.TViewedAt < t2.TViewedAt 
WHERE t2.TUserID IS NULL; 

結果

TID TData TUserID TViewedAt 
4 test3 123  2012-10-05 00:00:00.000 
5 test2 213  2012-10-03 00:00:00.000 
+0

はい、その作業は非常にシンプルで簡単にありがとうございます – Giorgi

+0

ようこそ、喜んで –

+1

これを行う方法がありますそれはより効率的です、すなわち、サブクエリを必要としないのですか?私はそれが私のサーバを殺していることを発見しています – Jason

1

あなたは最大の集計のためにGROUP BY TUserIDにする必要があります。

SELECT 
    TID, 
    TData, 
    main.TUserID 
    main.TViewedAt 
FROM 
    yourTable main 
    JOIN ( 
    SELECT TUserID, MAX(TViewedAt) AS TViewedAT FROM yourTable GROUP BY TUserID 
) tmax ON main.TUserID = tmax.TUserID AND main.TViewedAt = tmax.TViewedAt 

これはサブクエリに結合する移植可能なメソッドです。サブクエリはユーザーごとに最新のTUserID,TViewedAtを取得します。これはメインテーブルと再び結合され、一致するTDataを取得します。

あなただけ一度に1人のユーザーをしたい場合は、あなたが行うことができます:

SELECT 
    TData, 
    TViewedAt 
FROM yourTable 
WHERE TUserID = 'someid' 
GROUP BY TUserId 
HAVING TViewedAt = MAX(TViewedAt) 

上記のみのMySQLに私もそれを書かれているように動作します。他のRDBMSは、TDataSELECTのリストに表示されていますが、GROUP BYには含まれていないという苦情を申し立てます。

+0

秒1を支援し、0行を返したことがあります。 TViewedAtはDATETIME形式ですか?MAXはそれを理解していますか? – Giorgi

+1

@Giorgi MAX()はdatetimeカラムを認識します。最初のものを使用しますが、WHERE句を追加して必要なユーザーを制限します。最初の方が、2つの方が優れていて、移植性が高いです。 –

0
SELECT t1.TData, t1.TUserID, t1.TViewedAt 
FROM Test t1 
JOIN 
(SELECT TUserID, MAX(TViewedAt) 
FROM Test 
GROUP BY TUserID) t2 
ON t1.TUserID = t2.TUserID AND t1.TViewedAt=t2.TViewedAt 
+0

その作業はありませんでした:( – Giorgi

+0

TDataは違うかもしれません。それでは更新を参照してください... – alex

1

は、私が試したyou-が

select * from pages where date(create_date)=(select date(create_date) from pages order by create_date limit 1) 
+1

これがどのように質問に答えるか説明できますか? – Braiam

関連する問題