2

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

Quest
- (int) id 
- (text) characters

User
- (int) id
- (text) characters

エントリは次のようになります。

クエスト

id | characters
1  | abcdefgh
2  | mkorti
3  | afoxi
4  | bac

ユーザー

id | characters
1  | abcd

ここで、ユーザーにとって最も簡単なクエストを選択したいと思います。最も簡単なクエストは、quest.characters と user.characters の交差が最も多いものです。したがって、この例では、リストは次のようになります (user.id = 1 の場合):

questid | easiness
4       | 100
1       | 50
3       | 40
2       | 0

簡単さは、何パーセント一致したかを示すだけです。MySQL でこのような列の交差を作成することは可能ですか? パフォーマンスはどうですか?実際、私関係を持っています (クエスト -> キャラクターとユーザー -> キャラクター) が、あまりパフォーマンスが良くないと思います。数千のクエストと数千のキャラクターがあるからです。

更新 #1

わかりました、リレーショナルはまだ進むべき道のようです。今、私のテーブルは次のようになります。

CREATE TABLE IF NOT EXISTS `quest` (
  `questid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`questid`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;

CREATE TABLE IF NOT EXISTS `questcharacters` (
  `questid` int(10) unsigned NOT NULL,
  `characterid` int(10) unsigned NOT NULL,
  PRIMARY KEY (`questid`,`characterid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `single_character` (
  `characterid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `single_char` varchar(10) NOT NULL,
  PRIMARY KEY (`characterid`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `user` (
  `userid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `usercharacters` (
  `userid` int(10) unsigned NOT NULL,
  `characterid` int(10) unsigned NOT NULL,
  PRIMARY KEY (`userid`,`characterid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PS .: なぜsingle_charデータ型として VARCHAR(10) があるのか​​不思議ではありませんが、私はマルチバイト値を使用し、MySQL がそれらを char(1) に対してどのように処理するかわかりません。だから私はそこで寛大でした。

アップデート #2

今のところ私のクエリは次のとおりです。

SELECT usercharacters.userid, questcharacters.questid
FROM `usercharacters`
LEFT OUTER JOIN questcharacters ON usercharacters.characterid = usercharacters.characterid
GROUP BY questcharacters.questid, usercharacters.userid;

しかし、簡単さ/重複する文字を計算する方法は? どのフィールドに COUNT() を適用する必要がありますか?

アップデート #3

さて、このクエリで動作しているようです(サブセレクトを使用):

SELECT usercharacters.userid as uid, questcharacters.questid as qid, (SELECT COUNT(questcharacters.characterid) FROM questcharacters LEFT OUTER JOIN usercharacters ON questcharacters.characterid = usercharacters.characterid WHERE questcharacters.questid = qid) as questcount
FROM `usercharacters`
LEFT OUTER JOIN questcharacters ON usercharacters.characterid = usercharacters.characterid
GROUP BY questcharacters.questid, usercharacters.userid;

アップデート #4

SELECT usercharacters.userid as uid, questcharacters.questid as qid, (SELECT COUNT(questcharacters.characterid) FROM questcharacters LEFT OUTER JOIN usercharacters ON questcharacters.characterid = usercharacters.characterid WHERE questcharacters.questid = qid) as user_knows, (SELECT COUNT(questcharacters.characterid) FROM questcharacters WHERE questcharacters.questid = qid) as total_characters
FROM `usercharacters`
LEFT OUTER JOIN questcharacters ON usercharacters.characterid = usercharacters.characterid
GROUP BY questcharacters.questid, usercharacters.userid
ORDER BY total_characters / user_knows DESC;

今欠けているのは、簡単さを選択することだけです。(ORDER BY 句と同様)。誰でもこれを行う方法を知っていますか?

4

2 に答える 2

0

実際にテーブルがある場合questcharacterusercharacters、それが最善の方法です。

SELECT uc.id AS userid, 
       qc.id AS qcid, 
       COUNT(*) AS NumCharacters,
       COUNT(qc.char) AS Nummatches,
       COUNT(qc.char) / count(*) AS Easiness
FROM UserCharacters uc 
   LEFT OUTER JOIN QuestCharacters qc ON uc.char = qc.char
WHERE uc.id = 1
   GROUP BY uc.id, qc.id
   ORDER BY easiness DESC
LIMIT 1

それらを文字列としてのみ持つ場合、SQL はきれいではありません。クロス結合と多くの文字列操作を行う必要があります。最善の方法は、リストを文字列に埋め込むのではなく、リレーショナル データベース (リスト要素ごとに 1 行) の形式で物事をより正規化することです。

于 2013-07-15T17:35:18.660 に答える