我有一个歌曲表,每首歌最多可以有3种不同的流派。所以在我的表中,对于每首歌我都有列genre1,genre2和genre3。我正试图在列表中显示所有类型。
这是一个随机的示例集:
genre1 genre2 genre3
metal jazz
metal country pop
oldies metal
rap
jazz hip-hop choir
choir metal jazz
我希望在php中完成的列表按字母顺序显示可供选择的可用不同类型。所以应该列出这个:
感谢所有帮助。也许我不是最聪明的方式,但我想不出更好的方法。
答案 0 :(得分:3)
所以单独的列没有什么区别?如果是这种情况,您可以使用UNION
SELECT genre1 AS g FROM t UNION SELECT genre2 AS g FROM t UNION SELECT genre3 AS g FROM t
如果您有WHERE
子句,那么您需要复制3次,或使用中间临时表
表:
mysql> SELECT genre1, genre2, genre3 FROM music;
+--------+---------+--------+
| genre1 | genre2 | genre3 |
+--------+---------+--------+
| metal | jazz | |
| metal | country | pop |
| oldies | metal | |
| rap | | |
| jazz | hip-hop | choir |
| choir | metal | jazz |
+--------+---------+--------+
6 rows in set (0.00 sec)
分组:
mysql> SELECT genre1 AS g FROM music UNION ALL
SELECT genre2 AS g FROM music UNION ALL
SELECT genre3 AS g FROM music
+---------+
| g |
+---------+
| metal |
| metal |
| oldies |
| rap |
| jazz |
| choir |
| jazz |
| country |
| metal |
| |
| hip-hop |
| metal |
| |
| pop |
| |
| |
| choir |
| jazz |
+---------+
18 rows in set (0.00 sec)
数:
mysql> SELECT g, COUNT(*) AS c FROM
(SELECT genre1 AS g FROM music UNION ALL
SELECT genre2 AS g FROM music UNION ALL
SELECT genre3 AS g FROM music)
AS tg GROUP BY g;
+---------+---+
| g | c |
+---------+---+
| | 4 |
| choir | 2 |
| country | 1 |
| hip-hop | 1 |
| jazz | 3 |
| metal | 4 |
| oldies | 1 |
| pop | 1 |
| rap | 1 |
+---------+---+
9 rows in set (0.01 sec)
答案 1 :(得分:2)
SELECT genre1, genre2, genre3 FROM table
假设这是一个数组数组,那么:
function coalesce_into_array($aggregate, $row) {
foreach ($row as $genre) {
$aggregate[] = $genre;
}
return $aggregate;
}
$data = array_unique(array_reduce($data, 'coalesce_into_array', array()));
sort($data);
但是,我不会在严肃的申请中推荐这个。数据库设计很糟糕。阅读有关数据库规范化的信息,了解如何改进它。
答案 2 :(得分:0)
除非您出于性能原因将denormalized(2)类型放入三列,否则应该有一个单独的表格来关联歌曲和流派:
CREATE TABLE SongGenres (
song INT NOT NULL REFERENCES Songs (id) ON DELETE CASCADE,
genre VARCHAR(32) NOT NULL,
UNIQUE INDEX (song, genre),
INDEX genres (genre) -- improves performance for getting genre names
) Engine=InnoDB;
这消除了(“Cross Road Blues”可以在“Blues”和“Delta Blues”下提交,但就此而言)和人工限制(A3的乡村酸屋福音)的三种流派的要求每首歌。如果您有一组有限的流派,则可能需要制作流派列enumerated。 SongGenres表简化了所有类型:
SELECT UNIQUE genre FROM SongGenres;
或者,您可以进一步规范化并为流派创建单独的表:
CREATE TABLE Genres (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32) NOT NULL,
UNIQUE INDEX (name)
) Engine=InnoDB;
CREATE TABLE SongGenres (
song INT NOT NULL REFERENCES Songs (id) ON DELETE CASCADE,
genre INT NOT NULL REFERENCES Genres (id) ON DELETE RESTRICT,
UNIQUE INDEX (song, genre)
) Engine=InnoDB;
这简化了所有类型名称的更多(虽然这只是次要优势):
SELECT name FROM Genres;
Genres表的主要优点是数据正确性:如果有人拼错了类型,则在Genres表中找不到它。潜在的缺点是它将有效类型限制为表中的类型。当然,为SongGenres提供具有INSERT权限的用户帐户是有意义的,因此这种限制并不严重。一旦你开始添加新类型,你就会遇到与没有类型表时相同的问题:拼写错误。不是添加Genres表中没有的新类型,而是查找类似的类型(使用例如Levenshtein distance或SOUNDS LIKE
),如果找到任何类型,请询问用户是否要替换这种类型与发现或保留原始类型之一(并将其添加到流派列表)。
以下是第一种情况下的数据(两个表Songs
和SongGenres
):
mysql> SELECT * FROM Songs; +----+---------------------+--------+---- | id | title | artist | ... +----+---------------------+--------+---- | 1 | Cross Road Blues | ... | 2 | Peace In the Valley | ... +----+---------------------+--------+---- 2 rows in set (0.00 sec) mysql> SELECT * FROM SongGenres; +------+-------------+ | song | genre | +------+-------------+ | 2 | acid | | 1 | blues | | 2 | country | | 1 | delta blues | | 2 | gospel | | 2 | house | | 2 | techno | +------+-------------+ 7 rows in set (0.00 sec) mysql> SELECT s.title, sg.genre FROM Songs AS s JOIN SongGenres AS sg ON s.id=sg.song; +---------------------+-------------+ | title | genre | +---------------------+-------------+ | Cross Road Blues | blues | | Cross Road Blues | delta blues | | Peace In the Valley | acid | | Peace In the Valley | country | | Peace In the Valley | gospel | | Peace In the Valley | house | | Peace In the Valley | techno | +---------------------+-------------+ 7 rows in set (0.00 sec)
使用单独的Genres表,Songs中的数据看起来会相同,但在其他表格中我们会有类似的内容:
mysql> SELECT * FROM Genres; +----+-------------+ | id | name | +----+-------------+ | 1 | acid | | 2 | blues | | 3 | classical | | 4 | country | | 5 | delta blues | | 6 | folk | | 7 | gospel | | 8 | hip-hop | | 9 | house | ... | 18 | techno | +----+-------------+ 18 rows in set (0.00 sec) mysql> SELECT * FROM SongGenres; +------+-------+ | song | genre | +------+-------+ | 1 | 2 | | 1 | 5 | | 2 | 1 | | 2 | 4 | | 2 | 7 | | 2 | 9 | | 2 | 18 | +------+-------+ 7 rows in set (0.00 sec) mysql> SELECT s.title, g.name AS genre -> FROM Songs AS s -> JOIN SongGenres AS sg ON s.id=sg.song -> JOIN Genres AS g ON sg.genre=g.id; +---------------------+-------------+ | title | genre | +---------------------+-------------+ | Cross Road Blues | blues | | Cross Road Blues | delta blues | | Peace In the Valley | acid | | Peace In the Valley | country | | Peace In the Valley | gospel | | Peace In the Valley | house | | Peace In the Valley | techno | +---------------------+-------------+ 7 rows in set (0.00 sec)
答案 3 :(得分:-1)
SELECT DISTINCT类型,流派,流派3 FROM table
也许您需要更好的数据库设计......
songs | genres | [song_id|genre_id]