1

与えられた2つのテーブル、

  • 、、をA含むテーブルcustomeridlastchangeinternallink

  • Bを含むテーブルinternallinkturnover

(ここでは単純化して一般的な例に変更していますが、実際の構造はもっと複雑です。今のところSQL方言はmySQLです。)

(テーブルごとの)唯一のユニークなものは内部リンクです。Aには、同じcustomerID、lastchangeの異なる日付、および異なるinternallink値を持つ複数のレコードがあります。これに関連する他のアイテムがあります。テーブルを変更できません。

顧客にとって最新であり(同じcustomerIDを持つすべての中で最も高いlastchange値)、特定の値の条件に一致するBのエントリがリンクされているAのrecordIDが必要です

私は思います

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`;

残念ながら、そのステートメントは間違った結果をもたらします。これは、上記の値が基準を満たさないcustomerIDを返すためですが、一部の古い値はそうしました。これは、最も古い値を選択し、これを返します。ただし、最新のエントリがしきい値を下回っている場合は、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

内部リンクの売上高
          11 47000
          1211000
          13 8000
          1415000
          1517000
          16 23000
          17 50000
          18 10000

私のテストの実際のしきい値は12000です。最新のエントリがしきい値を下回っているため、customerIDを結果セットに含めるべきではないことがわかります。

結果セットは(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(turnover> 12000);

今必要なのは、両方の共通部分です...正しいロジックを使用してください!

4

3 に答える 3

1

次のクエリはあなたが望むことをするはずです。これは、この種のクエリを作成するための最もパフォーマンスの高い方法ではありません。ただし、標準SQLを使用しており、任意のデータベースで実行されます。

次のように機能します。内部サブクエリは、最新の変更対象とともにすべての顧客IDを検索します。そのようなペア(customerid、lastchange)ごとに、テーブルAで元の行を見つけます。テーブルAで行を見つけたら、内部リンクを使用してBで一致するレコードを見つけますが、関連する売上高が10000より大きい場合に限ります。

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);
于 2010-12-03T09:19:31.533 に答える
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

「ROW_NUMBER()OVER(PARTITION BY id ORDER BY lastchange DESC)AS'rownumber'」は...を意味します。

すべての同じIDをグループ化し、各行をカウントした後、descによるlastchangeで並べ替えます。ああ、その列に行番号という名前を付けます。

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

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

于 2010-12-03T07:18:41.217 に答える
0

多くのテストといくつかの調査の結果、私はこの解決策を見つけました。他の誰かが同様の問題に直面した場合に備えて、これを投稿します。

追加のテーブル「キャッシュ」は、テーブルAの最新のエントリのコピーを保持し、複雑さを大幅に軽減します。次のようなトリガーを使用して最新の状態に保ちます。

各行に挿入した後、トリガーsync_a_insertを作成します
    INSERT INTO cache( `customerID`、` internallink`)VALUES(NEW.`customerID`、NEW.`internallink`);
各行の更新後にトリガーsync_a_updateを作成します
    UPDATEキャッシュSET`internallink`= NEW.`internallink` WHERE(` customerID` = NEW.`customerID`);
各行で削除する前にトリガーsync_a_deleteを作成します
    キャッシュから削除WHERE`customerID`= OLD.`customerID`;

INSERTおよびUPDATEの場合、これらのトリガーは事後にオフになるため、表aのエントリーはキャッシュが更新される前に完了します。DELETEの場合、元のエントリが消える前にキャッシュを更新する必要があります。

これが適切に行われると、他のすべてが単純になります。

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

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

しかし、あなたの答えは私にとって非常に役に立ちました。私は彼らから、そしてあなたのアドバイスに従おうとすることからたくさんのことを学びました(すでに他の場所で使用するためにそれのいくつかを置くことさえ)。私の質問に答えてくれたすべての人に感謝します!

于 2010-12-04T06:45:13.757 に答える