0

こんにちは、MySQL を使用して追跡のリストを使用してログをフィルター処理したいと考えています。

すべてのログはサーバーに属し、

すべてのトラッキングはサーバーに属し、0..N パターンを持ちます

すべてのパターンは追跡に属します

私は3つのテーブルを持っています:

logs     : |  id  |      ip     | url     | server_id | ...
tracking : |  id  | server_id   | name    | other fields...
pattern  : |  id  | tracking_id | pattern |

特定のサーバーの追跡に一致するログをカウントしたいのですが、問題は、クエリがパターンを持つ追跡とそうでない追跡を混同することです。

SQL フィドル: http://sqlfiddle.com/#!2/f11b1/2

SELECT COUNT(DISTINCT logs.ip), tr.name
FROM `logs`
INNER JOIN `trackings` as tr ON 
        ( tr.server_id = logs.server_id )
        AND -- OTHER conditions between log and tracking
    LEFT JOIN `patterns` as pt ON 
        ( pt.tracking_id = tr.id )
        AND (logs.url LIKE pt.pattern )
GROUP BY tr.id

私の問題は 2 番目の結合にあります。使用するINNER JOIN patterns as pt ONと正しい結果が得られますが、いくつかのパターンを持つ追跡でのみ使用できます。使用するLEFT JOIN patterns as pt ONと、すべての追跡を取得できますが、カウントが偽になりますSELECT COUNT(DISTINCT logs.ip) FROM logs(

EDIT I トラッキングにパターンと UNION があるかどうかを示すトラッキングのフィールドで正しい結果を得ることができます:

(
SELECT COUNT(DISTINCT lg.ip), tr.name
FROM `logs` as lg
INNER JOIN `trackings` as tr ON 
        ( tr.server_id = lg.server_id )
        AND (tr.hasPatterns = 1)
        AND -- Other conditions
    INNER JOIN `patterns` as pt ON 
        ( pt.tracking_id = tr.id )
        AND (lg.url LIKE pt.pattern )
WHERE
GROUP BY tr.id
)
UNION
(
SELECT COUNT(DISTINCT lg.ip), tr.name
FROM `logs` as lg
INNER JOIN `trackings` as tr ON 
        ( tr.server_id = lg.server_id )
        AND (tr.hasPatterns = 0)
WHERE
GROUP BY tr.id, lg.date
)

しかし、ユニオンを使わずにそれを行う方法があると思います...

4

1 に答える 1

0

内に条件を入れることができるcountので、次のようにすればあなたが望むことができると思います:

SELECT COUNT(DISTINCT (case when tr.hasPatterns = 1 and pt.tracking_id is not null
                            then lg.ip
                            when tr.hasPatterns = 0
                            then lg.ip
                       end)), tr.name
FROM `logs` as lg
INNER JOIN `trackings` as tr ON 
        ( tr.server_id = lg.server_id )
        AND -- Other conditions
    LEFT JOIN `patterns` as pt ON 
        ( pt.tracking_id = tr.id )
        AND (lg.url LIKE pt.pattern )
WHERE
GROUP BY tr.id

編集:

これはあなたが望むものを返しています:

SELECT COUNT(DISTINCT (case when tr.size = 0 and pt.tracking_id is not null
                            then lg.ip
                            when tr.size > 0 and lg.size > tr.size
                            then lg.ip
                       end)), tr.name
FROM `logs` as lg
INNER JOIN `trackings` as tr ON 
        ( tr.server_id = lg.server_id )
    LEFT JOIN `patterns` as pt ON 
        ( pt.tracking_id = tr.id )
        AND (lg.url LIKE pt.pattern )
GROUP BY tr.id;

SQL Fiddle にはlg.size > tr.size、元の質問にない追加の条件があります。

于 2013-08-14T17:04:05.147 に答える