0

さまざまなソースからのアイテムでいっぱいのテーブルがあります。一部のソースは同じ場所にある場合があります (私の例では、異なる BBC ニュース フィードは異なるソースになりますが、それらはすべて BBC からのものです)。各アイテムには「一意の」ID があり、同じ場所から他のアイテムを識別するために使用できます。これは、サイト上の同じニュース記事に関連しているが、異なるフィードで公開されているアイテムは同じ「一意の ID」を持つことを意味しますが、これは必ずしもグローバルに一意であるとは限りません。

問題は、表示時に重複を排除したいということです。そのため、フィードの 2 つまたは 3 つにリンクが含まれている場合でも、(表示しているフィードに応じて) 各ストーリーの多くても 1 つのバージョンしか取得できません。

各ソースとフィールドsourcesに関する情報を含むテーブルがあります。次に、各アイテム、その、、およびを含むテーブルがあります。ソースとソースが同じアイテムは最大で 1 回表示され、ソースが最も高いアイテムが優先されます。location_idlocation_precedenceitemsunique_idsource_idcontentunique_idlocation_idlocation_precedence

私は次のようなことを考えていたでしょう:

SELECT `sources`.`name` AS `source`,
       `items`.`content`,
       `items`.`published`
FROM `items` INNER JOIN `sources`
  ON `items`.`source_id` = `sources`.`id` AND `sources`.`active` = 1
GROUP BY `items`.`unique_id`, `sources`.`location_id`
ORDER BY `sources`.`location_priority` DESC

うまくいくでしょうが、それは場所の優先度フィールドを無視しているようです。私は何を逃したのですか?


サンプルデータ:

CREATE TABLE IF NOT EXISTS `sources` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `location_id` int(10) unsigned NOT NULL,
  `location_priority` int(11) NOT NULL,
  `active` tinyint(1) unsigned NOT NULL default '1',
  `name` varchar(150) NOT NULL,
  `url` text NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `active` (`active`)
);

INSERT INTO `sources` (`id`, `location_id`, `location_priority`, `active`, `name`, `url`) VALUES
(1, 1, 25, 1, 'BBC News Front Page', 'http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml'),
(2, 1, 10, 1, 'BBC News England', 'http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/england/rss.xml'),
(3, 1, 15, 1, 'BBC Technology News', 'http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/technology/rss.xml'),
(4, 2, 0, 1, 'Slashdot', 'http://rss.slashdot.org/Slashdot/slashdot'),
(5, 3, 0, 1, 'The Daily WTF', 'http://syndication.thedailywtf.com/TheDailyWtf');

CREATE TABLE IF NOT EXISTS `items` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `source_id` int(10) unsigned NOT NULL,
  `published` datetime NOT NULL,
  `content` text NOT NULL,
  `unique_id` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `unique_id` (`unique_id`,`source_id`),
  KEY `published` (`published`),
  KEY `source_id` (`source_id`)
);

INSERT INTO `items` (`id`, `source_id`, `published`, `content`, `unique_id`) VALUES
(1,  1, '2009-12-01 16:25:53', 'Story about Subject One',                     'abc'),
(2,  2, '2009-12-01 16:21:31', 'Subject One in story',                        'abc'),
(3,  3, '2009-12-01 16:17:20', 'Techy goodness',                              'def'),
(4,  2, '2009-12-01 16:05:57', 'Further updates on Foo case',                 'ghi'),
(5,  3, '2009-12-01 15:53:39', 'Foo, Bar and Quux in court battle',           'ghi'),
(6,  2, '2009-12-01 15:52:02', 'Anti-Fubar protests cause disquiet',          'mno'),
(7,  4, '2009-12-01 15:39:00', 'Microsoft Bleh meets lukewarm reception',     'pqr'),
(8,  5, '2009-12-01 15:13:45', 'Ever thought about doing it in VB?',          'pqr'),
(9,  1, '2009-12-01 15:13:15', 'Celebrity has 'new friend'',        'pqr'),
(10, 1, '2009-12-01 15:09:57', 'Microsoft launches Bleh worldwide',           'stu'),
(11, 2, '2009-12-01 14:57:22', 'Microsoft launches Bleh in UK',               'stu'),
(12, 3, '2009-12-01 14:57:22', 'Microsoft launches Bleh',                     'stu'),
(13, 3, '2009-12-01 14:42:15', 'Tech round-up',                               'vwx'),
(14, 2, '2009-12-01 14:36:26', 'Estates 'old news' say government', 'yza'),
(15, 1, '2009-12-01 14:15:21', 'Iranian doctor 'was poisoned'',     'bcd'),
(16, 4, '2009-12-01 14:14:02', 'Apple fans overjoyed by iBlah',               'axf');

クエリ後に期待されるコンテンツ:

  • サブジェクト ワンの話
  • 技術の良さ
  • 法廷闘争中のフー、バー、クックス
  • 反フーバーの抗議は不安を引き起こします
  • Microsoft Bleh は生ぬるい反応に出会う
  • VB でやろうと思ったことはありませんか?
  • 有名人に「新しい友達」ができた
  • マイクロソフトがBlehを世界中で発売
  • 技術まとめ
  • エステートの「古いニュース」は政府を言う
  • イランの医師は「毒殺された」
  • iBlah に大喜びする Apple ファン

Andomar によるソリューションのバリエーションを試してみましたが、ある程度成功しました。

SELECT      s.`name` AS `source`,
            i.`content`,
            i.`published`
FROM        `items` i
INNER JOIN  `sources` s
ON          i.`source_id` = s.`id`
AND         s.`active` = 1
INNER JOIN (
  SELECT `unique_id`, `source_id`, MAX(`location_priority`) AS `prio` 
  FROM `items` i
  INNER JOIN `sources` s ON s.`id` = i.`source_id` AND s.`active` = 1
  GROUP BY `location_id`, `unique_id`
) `filter`
ON          i.`unique_id` = `filter`.`unique_id`
AND         s.`location_priority` = `filter`.`prio`
ORDER BY    i.`published` DESC
LIMIT 50

AND s.location_priority = filter.prio物事はほとんど私が望むように機能します。項目は同じ優先度を持つ複数のソースから取得される可能性があるため、項目が繰り返される可能性があります。この場合、GROUP BY i.unique_id外側のクエリのエクストラが機能します。優先度が等しい場合、どちらのソースが「勝つ」かは問題ではないと思います。

私はAND i.source_id = filter.source_id代わりに試してみましたが、これはほとんど機能します(つまり、余分なものを排除しますGROUP BY)が、適切なソースからの結果は得られません。上記の例では、「法廷闘争中のフー、バー、クックス」(出典「BBC テクノロジー ニュース」) ではなく、「フー事件のさらなる最新情報」(出典「BBC ニュース イングランド」) が表示されます。クエリ、私は得る:

unique_id: 'ghi'
source_id: 2
prio: 15

ソース ID が正しくないことに注意してください (予想: 3)。

4

3 に答える 3

5

Order by行を注文するだけで、その中から選択することはありません。

下の行を除外する方法の1つは、 asフィルターlocation_priorityを使用することです。inner join

SELECT     s.name, i.content, i.published
FROM       items i 
INNER JOIN sources s
ON         i.source_id = s.id
AND        s.active = 1
INNER JOIN (
    SELECT unique_id, max(location_priority) as prio
    FROM items i
    INNER JOIN sources s ON s.id = i.source_id AND s.active = 1
    GROUP BY unique_id) filter
ON         i.unique_id = filter.unique_id
AND        s.location_priority = filter.prio;

別の方法は、次のようなwhere ... in <subquery> 句です。

SELECT     s.name, i.content, i.published
FROM       items i 
INNER JOIN sources s
ON         i.source_id = s.id
AND        s.active = 1
WHERE      (i.unique_id, s.location_priority) IN (
    SELECT unique_id, max(location_priority)
    FROM items i
    INNER JOIN sources s ON s.id = i.source_id AND s.active = 1
    GROUP BY unique_id
);

この問題は、「グループ全体の最大値を保持するレコードの選択」とも呼ばれます。Quassnoiはそれに素晴らしい記事を書いています。

編集:同じ優先度で複数のソースとの関係を断ち切る1つの方法はWHERE、サブクエリを含む句です。この例は、以下の関係を断ち切りますi.id DESC

SELECT     s.name, i.unique_id, i.content, i.published
FROM       (
           SELECT unique_id, min(location_priority) as prio
           FROM items i
           INNER JOIN sources s ON s.id = i.source_id AND s.active = 1
           GROUP BY unique_id
           ) filter
JOIN       items i
JOIN       sources s
ON         s.id = i.source_id 
           AND s.active = 1
WHERE      i.id =
           (
           SELECT   i.id
           FROM     items i
           JOIN     sources s 
           ON       s.id = i.source_id 
                    AND s.active = 1
           WHERE    i.unique_id = filter.unique_id
           AND      s.location_priority = filter.prio
           ORDER BY i.id DESC
           LIMIT 1
           )

Quassnoiには、グループごとの最大値を保持するレコードの選択(同点の解決)に関する記事もあります:)

于 2009-12-06T13:17:21.580 に答える
1

のような派生テーブルに自己結合を行います

select max(location_priority) from table where ...
于 2009-12-06T12:58:47.573 に答える
0

私は何を逃しましたか?

これは、が各グループをすでに1行に減らしORDER BYた後に発生します。GROUP BYポールは一つの決議をします。

クエリの問題について:

SELECT `unique_id`, `source_id`, MAX(`location_priority`) AS `prio` 
FROM `items` i
INNER JOIN `sources` s ON s.`id` = i.`source_id` AND s.`active` = 1
GROUP BY `location_id`, `unique_id`

source_id集合体でもグループ化でもありません。結果として、どの値を取得するかは不確定です。

于 2009-12-06T13:12:29.700 に答える