mysql - SQL 按首选值列表分组

标签 mysql sql

首先:我不太清楚该在问题标题中输入什么,我不知道如何调用这样的查询,也许这就是我找不到任何答案的原因。

我有一个广播电台表和一个流表。每个广播电台可以有多个流,用于不同的格式、比特率等。 我想获取所有电台的列表,以及给定应用程序首选格式的流。

现在这很棘手,我希望首选格式为列表,并且我的数据库应返回第一个合适的流。

所以我可能有一个这样的列表:('MP3', 'AAC', 'OGG')

然后我希望 MySQL 为每个站点返回“MP3”类型的流,但如果它不存在,它应该返回该站点的“AAC”流,依此类推。 如果没有找到合适的流,它不应该返回站。

示例:

CREATE TABLE `stations` (
  `id` INT(11),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE `streams` (
  `id` INT(11),
  `station` INT(11),
  `media_type` ENUM('MP3', 'OGG', 'AAC', 'Flash'),
  PRIMARY KEY (`id`),
  KEY (`station`),
  CONSTRAINT `fk_1` FOREIGN KEY (`station`) REFERENCES `stations` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB;

INSERT INTO `stations` (`id`) VALUES (1), (2), (3);
INSERT INTO `streams` (`id`, `station`, `media_type`) VALUES (1, 1, 'MP3'), (2, 1, 'AAC'), (3, 2, 'Flash'), (4, 2, 'AAC'), (5, 3, 'Flash');

我做了一个SQLFiddle here

如果首选媒体类型列表是('MP3', 'AAC'),那么使用上面示例数据的期望结果应该是:

station stream  type
1       1       MP3
2       4       AAC
  • Station 1 应具有 MP3 类型的流 1(也支持 AAC,但 MP3 优于 AAC)
  • Station 2 应该有 AAC 类型的流 4(Station 2 不提供 MP3,但 AAC 提供)
  • Station 3 不应出现在结果中,因为它仅通过 Flash 提供流媒体

我试过了:

SELECT
    st.id AS station_id,
    str.id AS stream_id,
    str.media_type,
    FIELD(str.media_type, 'MP3', 'AAC') AS preference
FROM
    stations st
LEFT JOIN
    streams str ON str.station = st.id
GROUP BY 
    st.id
HAVING
    MIN(preference)

但是根据流表中的第一条记录是否是首选媒体类型,它只返回 1 或 0 条记录,我不明白为什么。

我能找到的唯一解决方案是使用子查询对流进行排序,然后按 station_id 分组,如下所示:

SELECT sub.* FROM
    (SELECT
        st.id AS station_id,
        str.id AS stream_id,
        str.media_type
    FROM
        stations st
    LEFT JOIN
        streams str ON str.station = st.id
    WHERE
        str.media_type IN ('MP3', 'AAC')
    ORDER BY
        FIELD(str.media_type, 'MP3', 'AAC')
    ) AS sub
GROUP BY sub.station_id

但这会导致子查询正在创建的临时表的全表扫描,性能无法接受。由于我们不能限制内部查询(因为它还没有分组),临时表会变得非常大。

顺便说一句,我正在运行 MySQL 5.6

那么,我应该使用哪种查询来处理首选属性列表?

最佳答案

如果您只想返回 'MP3''AAC' 存在的行,则不需要外连接。

这是一个标准 SQL 解决方案,可以在 mysql 中按原样工作,请参阅 fiddle :

SELECT
   st.id AS station_id,
   COALESCE(MAX(CASE WHEN str.media_type = 'MP3' THEN str.id END)
           ,MAX(CASE WHEN str.media_type = 'AAC' THEN str.id END)
           ) AS stream_id,
   COALESCE(MAX(CASE WHEN str.media_type = 'MP3' THEN str.media_type END)
           ,MAX(CASE WHEN str.media_type = 'AAC' THEN str.media_type END)
           ) AS media_type
FROM stations st
JOIN streams str 
  ON str.station = st.id
WHERE -- only stations with the requested media types
   str.media_type IN ('MP3', 'AAC')
GROUP BY st.id

添加更多媒体类型很容易,主要是剪切和粘贴。 COALESCE 根据 CASE 的顺序返回第一个匹配的媒体类型。

关于mysql - SQL 按首选值列表分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32080957/

相关文章:

mysql - 如何在数据库中实现这一点?

mysql从循环中的选择查询返回结果集

mysql - 如何仅向列添加特定值?

sql - SQL Server 2012 中的旧 SSIS

sql - 尽管引用了表,但列名不明确

mysql - 无法添加或更新子行 : a foreign key constraint fails mysql

php - 在 MySQL 数据库中存储数据的最佳方式

Javascript MySQL查询在Discord聊天中返回[object Object],但在控制台中返回正确的结果

sql - 需要制作一个 .bat 文件来停止然后重新启动 SQL Server 数据库

MYSQLi/PHP 允许在 UNIQUE 上重复输入吗?