2010-12-03 16 views
1

、2つのテーブル、customeridlastchangeinternallinkSQLクエリーのグループ化のヘルプおよびネストされたクエリ

  • internallinkを含む表Bturnover

  • を含む

    • Aです(私は彼女を単純にしている一般的な例に変更すると、実際の構造はより複雑になります。今のところSQLの方言はmySQLです。)

      唯一のユニークなものは、internallinkです。 Aには、同じcustomerID、lastchangeの異なる日付、およびinternallinkの値が異なるレコードがいくつかあります。 これに関連する他の項目があります。私はテーブルを変更することはできません。

      は私が特定の値条件に一致するBのエントリがリンクされているために顧客(同じ得意先とのすべての最高lastchange値)の最新のであるからrecordIDsを必要としています。

      私は

      SELECT `internallink` FROM `B` WHERE (`turnover` > 10000) 
      

      部分が問題ではないと思います。

      私はこれまでのところ得た:

      SELECT `customerID`, MAX(`lastchange`) 
          FROM `A` 
      WHERE `lastchange` IN (SELECT `internallink` FROM `B` 
               WHERE `turnover` > 10000) 
      GROUP BY `customerID`; 
      

      ああを、上記の私の最新の値が基準を満たさないためのCustomerIDsを返しますので、その文は、間違った結果が得られますが、一部の古いはなかった - それは選択します最も古いもので、これを返す。しかし、最新のエントリがしきい値を下回っている場合、customerIDはまったく上がってはなりません。

      どこが間違っていましたか、これには正しいアプローチは何ですか?

      サンプルデータ 表A

       
      customerid lastchange internallink 
           3 2010-02-11 11 
           3 2010-09-04 12 
           3 2010-10-22 13 
           3 2010-11-23 14 
           4 2010-05-05 15 
           4 2010-12-01 16 
           5 2010-11-28 17 
           5 2010-11-29 18 
      

      表B

       
      internallink turnover 
            11  47000 
            12  11000 
            13  8000 
            14  15000 
            15  17000 
            16  23000 
            17  50000 
            18  10000 
      

      私のテストでは、実際のしきい値が12000 であるあなたは、得意先のほとんどは、結果セットにすべきではない見ることができます最近のエントリがしきい値を下回っています。

      結果セットは(3,2010-11-23)(4,2010-12-01)である必要がありますが、現在は(5,2010-11-28)も含まれていますが間違っています。


      少し近づいてください(お手数です、ありがとうございます!)、これら2つのステートメントはどちらも動作します。

      SELECT customerID、MAX(lastchange)、internallink FROM A GROUP BY customerID; SELECT internallink FROM B WHERE(売上高> 12000);

      私が必要としているのは、両方の交差点です...正しいロジックです!

    +0

    サンプルデータを投稿する方法はありますか? 1テーブルあたりのレコード数はわずかですか?あなたが書いたもので問題を視覚化するのは難しいです。 – Andrew

    +0

    この[スタック交換提案](http://area51.stackexchange.com/proposals/11464/code-review?referrer=aWNm_PdciyFqjFW8CUacGw2 "コードレビュー")に興味があるかもしれません。ベータ版を開始する準備はほぼ完了ですが、もう少し必要です。 – greatwolf

    答えて

    0

    、私はこの解決策を見つけた、と私は他の誰もが同じような問題に直面しなければならない場合には これを投稿してください。

    テーブル "キャッシュ"を追加すると、テーブルAの最新のエントリのコピーが保持され、複雑さが大幅に軽減されます。 INSERTとUPDATEのために

     
    CREATE TRIGGER sync_a_insert AFTER INSERT ON a FOR EACH ROW 
        INSERT INTO cache (`customerID`, `internallink`) VALUES (NEW.`customerID`,NEW.`internallink`); 
    CREATE TRIGGER sync_a_update AFTER UPDATE ON a FOR EACH ROW 
        UPDATE cache SET `internallink` = NEW.`internallink` WHERE (`customerID` = NEW.`customerID`); 
    CREATE TRIGGER sync_a_delete BEFORE DELETE ON a FOR EACH ROW 
        DELETE FROM cache WHERE `customerID` = OLD.`customerID`; 
    

    表Aにエントリがキャッシュの更新前に完了しているので、これらのトリガーは、事実の後にオフに行く:それは、このようなトリガを使用して、現在のままです。 DELETEでは、元のエントリが消失する前にキャッシュを更新する必要があります。

    これが配置されると、他のすべてが簡単になる:私にとって

     
    SELECT `customerID` FROM cache WHERE `internallink` IN 
        (SELECT `internallink` FROM b WHERE (`turnover` > 10000)); 
    

    、これは実行可能なソリューションである、と言っても検索を高速化します。もちろん、DBサイズにはコストがかかりますが、パフォーマンスは全体的にはるかに優れていると思います。書き込みアクセスより少なくとも1つ多くの読み取りアクセスがある限り、改善があります。

    あなたが与えた回答は、私にとって非常に役に立ちました。私はそれらからたくさんのことを学び、あなたの助言に従うことを試みました(すでにいくつかを他の場所で使うようにしても)。私の質問に答えるすべての人に感謝します!

    0

    これはsqlサーバーで動作します。mySqlに類似の順位付け関数があるかどうかはわかりません。

    select a.id, a.lastchange, b.turnover, a.rownumber from B b inner join 
    (SELECT id, lastchange, internallink, ROW_NUMBER() OVER(PARTITION BY id ORDER BY lastchange DESC) AS 'rownumber' 
    FROM A) a on b.internallink = a.internallink 
    where a.rownumber = 1 and b.turnover > 5000 
    

    " 'ROWNUMBER' AS()(lastchange DESC BYのid ORDER BY PARTITION)OVER ROW_NUMBER" とは...

    私が一緒にグループにすべて同じidをしたいとによってlastchangeで注文してその後、各行を数えてください。ああ、その列のrownumberという名前。

    id lastchange internallink rownumber 
    1 2010-01-03 2   1 
    1 2010-01-02 1   2 
    1 2010-01-01 1   3 
    2 2010-01-04 2   1 
    

    rownumberが1のレコードを選択すると、idの最後に変更されたレコードが返されます。

    +1

    @foo - MySQLには解析機能はありませんが、この記事ではどのように偽装できるかについて説明しています。http://explainextended.com/2009/03/08/analytic-functions-sum-avg-row_number/ – APC

    +0

    私はこの翻訳/エミュレートを全面的に行うためにしばらく時間をとっています。そしてそれを最初に理解する時間。私はこれを行う簡単な方法があったと思う... – foo

    +0

    @foo - APCが提供するリンクは役立ちます。ダイジェストするときは、さまざまなバリエーションのクエリ(パーティション化されたものや注文されたものの変更)を試して、結果を確認してください。がんばろう。 – imlovinit

    1

    次のクエリは、必要な処理を行う必要があります。これはではなく、です。この種のクエリを書くのに最も効果的な方法です。しかし、それは標準のSQLを使用しており、どのデータベースでも実行されます。

    このような動作:内部サブクエリはすべての顧客IDを最新の変更と一緒に見つけます。そのようなペア(customerid、lastchange)ごとに、テーブルAの元の行を見つけます。テーブルAの行が見つかったら、internallinkを使用してBの一致するレコードを検索します。テストといくつかの研究の多く後

    drop table a; 
    drop table b; 
    
    create table a(
        customerid int not null 
        ,lastchange date not null 
        ,internallink int not null 
    ); 
    
    create table b(
        internallink int not null 
        ,turnover  int not null 
    ); 
    
    insert into a values(3, date '2010-02-11', 11); 
    insert into a values(3, date '2010-09-04', 12); 
    insert into a values(3, date '2010-10-22', 13); 
    insert into a values(3, date '2010-11-23', 14); 
    insert into a values(4, date '2010-05-05', 15); 
    insert into a values(4, date '2010-12-01', 16); 
    insert into a values(5, date '2010-11-28', 17); 
    insert into a values(5, date '2010-11-29', 18); 
    
    insert into b values(11, 47000); 
    insert into b values(12, 11000); 
    insert into b values(13, 8000); 
    insert into b values(14, 15000); 
    insert into b values(15, 17000); 
    insert into b values(16, 23000); 
    insert into b values(17, 50000); 
    insert into b values(18, 10000); 
    
    select a.customerid 
         ,a.lastchange 
         ,a.internallink 
         ,b.turnover 
        from a 
        join b on (a.internallink = b.internallink) 
    where b.turnover > 10000 
        and (a.customerid, a.lastchange) in(select customerid,max(lastchange) 
                 from a 
                group by customerid); 
    
    +0

    あまりにも多くを切り取っているように見えますが、良く見えますが、私の現在の質問はもっと効力があります。標準SQLではない?私が持っていた問題は "IN"を使うことでした。私はちょうど1つの列が必要ですが、2つの選択肢があり、一致するものは1つしかありません。 – foo

    +0

    「切り捨て」とは、間違った結果を返すという意味ですか? – Ronnis

    関連する問題