SELECT子句中的子查询

时间:2014-01-30 16:02:20

标签: mysql sql select subquery group-concat

我需要从多个表中SELECT来获取如下结果表:

+--------+-------+-------------------+----------------------+
| itemID | level | studyPhraseString | meaningPhraseStrings |
+--------+-------+-------------------+----------------------+
| 1      | 4     | la maison         | house                |
+--------+-------+-------------------+----------------------+
| 2      | 3     | voler             | to fly,to steal      |
+--------+-------+-------------------+----------------------+

注意:studyPhraseStringmeaningPhraseStrings应该是由word表格中的值组成的串联字符串。

我的表格:

项目

CREATE TABLE `item` (
`itemID` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`groupID` bigint(11) unsigned NOT NULL,
`studyLang` varchar(5) NOT NULL,
`meaningLang` varchar(5) NOT NULL,
`studyPhraseID` bigint(11) unsigned NOT NULL,
PRIMARY KEY (`itemID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1;

含义

CREATE TABLE `meaning` (
  `meaningID` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `itemID` bigint(11) unsigned NOT NULL,
  `meaningPhraseID` bigint(11) unsigned NOT NULL,
  `meaningIndex` int(11) unsigned NOT NULL,
  PRIMARY KEY (`meaningID`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1;

短语

CREATE TABLE `phrase` (
  `phraseID` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `phraseLang` varchar(5) NOT NULL DEFAULT '',
  PRIMARY KEY (`phraseID`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=latin1;

phrase_word

CREATE TABLE `phrase_word` (
  `phrase_wordID` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `phraseID` bigint(11) unsigned NOT NULL,
  `wordID` bigint(11) unsigned NOT NULL,
  `wordIndex` int(11) unsigned NOT NULL,
  PRIMARY KEY (`phrase_wordID`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=latin1;

状态

CREATE TABLE `status` (
  `statusID` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `itemID` bigint(11) unsigned NOT NULL,
  `level` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `nextReviewTime` int(11) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`statusID`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1;

CREATE TABLE `word` (
  `wordID` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
  `string` varchar(64) NOT NULL DEFAULT '',
  PRIMARY KEY (`wordID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;

我写了以下SELECT语句:

SELECT item.itemID, status.level, 
(SELECT GROUP_CONCAT(word.string ORDER BY phrase_word.wordIndex SEPARATOR ' ')
FROM word INNER JOIN phrase_word ON word.wordID=phrase_word.wordID
INNER JOIN item AS subItem ON phrase_word.phraseID=subItem.studyPhraseID 
WHERE subItem.itemID=item.itemID
GROUP BY subItem.itemID
) AS studyPhraseString
FROM item INNER JOIN status ON item.itemID=status.itemID
WHERE item.groupID=5
ORDER BY status.statusID DESC

这有效,但不包括meaningPhraseString。我无法弄清楚如何将单词连接成短语并将短语连成一个字符串分隔,

我尝试过嵌套的GROUP_CONCAT子句但没有成功(子查询返回超过1行):

问题

如何编写此声明以包含meaningPhraseStrings?提前谢谢。

PS:我希望这是一个单一的查询

我尝试过以下但是失败了。为什么?它有两级相关查询。

SELECT 
item.itemID, 
status.level, 
(
    SELECT GROUP_CONCAT(word.string ORDER BY phrase_word.wordIndex SEPARATOR ' ')
    FROM word INNER JOIN phrase_word ON word.wordID=phrase_word.wordID
    INNER JOIN item AS subItem ON phrase_word.phraseID=subItem.studyPhraseID 
    WHERE subItem.itemID=item.itemID
    GROUP BY subItem.itemID
) AS studyPhraseString, 

(
    SELECT GROUP_CONCAT(meaningPhraseString SEPARATOR '.') 
    FROM (
        (
            SELECT GROUP_CONCAT(word.string ORDER BY phrase_word.wordIndex SEPARATOR ' ') AS meaningPhraseString
            FROM word INNER JOIN phrase_word ON word.wordID=phrase_word.wordID
            INNER JOIN meaning ON phrase_word.phraseID=meaning.meaningPhraseID
            INNER JOIN item AS subItem ON meaning.itemID=subItem.itemID 

            WHERE subItem.itemID=item.itemID #This fails

            GROUP BY meaning.meaningPhraseID
        ) AS meaningPhraseString
    )
) AS meaningPhraseStrings

FROM item INNER JOIN status ON item.itemID=status.itemID
WHERE item.groupID=5
ORDER BY item.itemID DESC

示例数据:

INSERT INTO `status` VALUES (22,22,0,0),(23,23,0,0),(24,25,0,0),(25,24,0,0),(26,26,0,0);
INSERT INTO `item` VALUES (22,5,'fr','en',49),(23,5,'fr','en',48),(24,5,'fr','en',56),(25,5,'fr','en',50),(26,5,'fr','en',57);
INSERT INTO `meaning` VALUES (27,22,51,0),(28,23,52,0),(29,23,54,1),(30,24,59,0),(31,24,61,1),(32,25,53,0),(33,25,55,1),(34,26,58,0),(35,26,60,1);
INSERT INTO `phrase` VALUES (48,'fr'),(49,'fr'),(50,'fr'),(51,'en'),(52,'en'),(53,'en'),(54,'en'),(55,'en'),(56,'fr'),(57,'fr'),(58,'en'),(59,'en'),(60,'en'),(61,'en');
INSERT INTO `word` VALUES (46,'l\'autobus'),(47,'bus'),(48,'pourquoi'),(49,'comment'),(50,'why'),(51,'ça'),(52,'va?'),(53,'voler'),(54,'incroyable'),(55,'how'),(56,'is'),(57,'to'),(58,'are'),(59,'incredible'),(60,'that?'),(61,'you?'),(62,'fly'),(63,'amazing'),(64,'hi'),(65,'steal');
INSERT INTO `phrase_word` VALUES (86,49,46,0),(87,51,47,0),(88,48,48,0),(89,50,49,0),(90,52,50,0),(91,54,50,0),(92,50,51,1),(93,50,52,2),(94,57,53,0),(95,53,55,0),(96,56,54,0),(97,54,56,1),(98,53,58,1),(99,58,57,0),(100,59,59,0),(101,54,60,2),(102,53,61,2),(103,58,62,1),(104,61,63,0),(105,60,57,0),(106,55,64,0),(107,60,65,1);

最终答案

SELECT i.itemID, 
        s.level,
        sp.studyPhraseString,
        GROUP_CONCAT(mp.meaningPhraseString
                     SEPARATOR ', ') AS meaningPhraseStrings            
   FROM item AS i
   JOIN meaning AS m ON i.itemID = m.itemID
   JOIN status AS s ON i.itemID = s.itemID
   JOIN ( 
       SELECT subItem.studyPhraseID,
              GROUP_CONCAT(word.string 
                           ORDER BY phrase_word.wordIndex 
                           SEPARATOR ' ') AS studyPhraseString
         FROM word 
         JOIN phrase_word
           ON word.wordID=phrase_word.wordID
         JOIN item AS subItem 
           ON phrase_word.phraseID=subItem.studyPhraseID 
     GROUP BY subItem.studyPhraseID
        ) AS sp ON i.studyPhraseID = sp.studyPhraseID   
   JOIN ( 
       SELECT meaning.meaningPhraseID,
              GROUP_CONCAT(word.string 
              ORDER BY phrase_word.wordIndex
              SEPARATOR ' ') AS meaningPhraseString
         FROM word 
         JOIN phrase_word ON word.wordID=phrase_word.wordID
         JOIN meaning ON phrase_word.phraseID=meaning.meaningPhraseID
         JOIN item AS subItem ON meaning.itemID=subItem.itemID 
     GROUP BY meaning.meaningPhraseID
        ) AS mp ON m.meaningPhraseID = mp.meaningPhraseID
  GROUP BY i.itemID, s.level, sp.studyPhraseString
  ORDER BY i.itemID, s.level, sp.studyPhraseString

1 个答案:

答案 0 :(得分:1)

你的问题似乎是这样的:

  

如何将单词连接成短语并将短语连成一个字符串

让我们分解吧。您需要将五个表连接在一起。其中三个是物理表,即itemmeaningstatus。从这些表中,您可以获得所需的结果集项的引用,称为itemID和level,并获得项之间的关系及其含义。

您需要的其他两个表是虚拟表(即子查询)。其中一个为您提供法语短语,另一个为您提供英语翻译。

让我们为虚拟表创建两个查询。我们先把这些单词写成短语。像这样的查询实现了这个目标。

 SELECT subItem.studyPhraseID,
        GROUP_CONCAT(word.string 
                     ORDER BY phrase_word.wordIndex 
                     SEPARATOR ' ') AS studyPhraseString
   FROM word 
  INNER JOIN phrase_word ON word.wordID=phrase_word.wordID
  INNER JOIN item AS subItem ON phrase_word.phraseID=subItem.studyPhraseID 
  GROUP BY subItem.studyPhraseID

这将为您提供短语ID编号和短语的结果集表。根据您的样本,这是一个SQL小提琴。 http://sqlfiddle.com/#!2/11ae2/9/0

然后,创建一个类似的查询,为您提供meaningPhraseString值。

 SELECT meaning.meaningPhraseID,
        GROUP_CONCAT(word.string 
        ORDER BY phrase_word.wordIndex
        SEPARATOR ' ') AS meaningPhraseString
   FROM word 
  INNER JOIN phrase_word ON word.wordID=phrase_word.wordID
  INNER JOIN meaning ON phrase_word.phraseID=meaning.meaningPhraseID
  INNER JOIN item AS subItem ON meaning.itemID=subItem.itemID 
  GROUP BY meaning.meaningPhraseID

这给出了id和含义短语的列表。这是小提琴。 http://sqlfiddle.com/#!2/11ae2/6/0

因此,我们需要一个五向连接(三个物理表和两个子查询)才能到达我们的最终结果集。总之,它看起来像这样:

 SELECT i.itemID, 
        s.level,
        sp.studyPhraseString,
        mp.meaningPhraseString            
   FROM item AS i
   JOIN meaning AS m ON i.itemID = m.itemID
   JOIN status AS s ON i.itemID = s.itemID
   JOIN ( 
           /* the studyPhrase subquery */ 
        ) AS sp ON i.studyPhraseID = sp.studyPhraseID   
   JOIN ( 
           /* the meaningPhrase subquery */ 
        ) AS mp ON m.meaningPhraseID = mp.meaningPhraseID

这里的技巧是你可以互换地使用查询(或虚拟表)和物理表。因此,当您需要汇总一堆表时,可以创建一个查询来执行该操作,然后将其粘贴到JOIN (/*query*/) AS alias中。

最后,您需要通过在查询中添加另一个to fly, to stealGROUP_CONCAT()来创建加入逗号的字符串(例如GROUP BY)。最终结果是

 SELECT i.itemID, 
        s.level,
        sp.studyPhraseString,
        GROUP_CONCAT(mp.meaningPhraseString
                     SEPARATOR ', ') AS meaningPhraseStrings            
   FROM item AS i
   JOIN meaning AS m ON i.itemID = m.itemID
   JOIN status AS s ON i.itemID = s.itemID
   JOIN ( 
           /* the studyPhrase subquery */ 
        ) AS sp ON i.studyPhraseID = sp.studyPhraseID   
   JOIN ( 
           /* the meaningPhrase subquery */ 
        ) AS mp ON m.meaningPhraseID = mp.meaningPhraseID
  GROUP BY i.itemID, s.level, sp.studyPhraseString
  ORDER BY i.itemID, s.level, sp.studyPhraseString

那是你的疑问。 http://sqlfiddle.com/#!2/11ae2/16/0它肯定会利用结构化查询语言中的结构化