【问题标题】:sql many-to-many query result only if matches only and exactly all items in arraysql 多对多查询结果仅当仅匹配且完全匹配数组中的所有项目时
【发布时间】:2021-03-24 13:57:14
【问题描述】:

我在一个 mysql 数据库上有三个表:

| pieces   | line_up       | instrument    | 
--------------------------------------------
| id_piece | piece_id      | id_instrument |
| title    | instrument_id | instrument    |

现在我想要实现的是:我想查询那些其 line_up 完全由列表中给出的乐器组成的片段,而不是一个少一个。 此 sql 查询将结果减少到仅由 2 种乐器演奏的曲目,但它包括独奏

SELECT id_piece, title FROM pieces WHERE
   (SELECT COUNT(*) FROM line_up WHERE line_up.piece_id = pieces.id_piece)
   =
   (SELECT COUNT(*) FROM line_up
   INNER JOIN instruments ON instruments.id_instrument = line_up.instrument_id
   WHERE line_up.piece_id = pieces.id_piece
   AND instruments.instrument IN ('guitar', 'drums'));

以这些表格为例:

| pieces               |  | line_up                  |  | instruments                |
-----------------------   ---------------------------   ------------------------------
| id_piece | title     |  | piece_id | instrument_id |  | id_instrument | instrument |
-----------------------  ----------------------------   ------------------------------
| 1        | hello     |  | 1        | 1             |  | 1             | guitar     |
| 2        | goodbye   |  | 1        | 2             |  | 2             | drums      |  
| 3        | goodnight |  | 2        | 1             |  ------------------------------
------------------------  | 3        | 2             |
                          ----------------------------

吉他和鼓的唯一实际作品,因此我的查询结果应该是1 | hello。 有什么建议?谢谢!

【问题讨论】:

    标签: mysql sql inner-join aggregate-functions having-clause


    【解决方案1】:

    你可以像这样使用聚合:

    select p.id_piece, p.title
    from pieces as p
    inner join line_up as l on l.piece_id = p.id_piece
    inner join instruments as i on l.instrument_id = i.id_instrument
    group by p.id_piece
    having sum(i.instrument in ('guitar', 'drums')) = 2
       and sum(i.instrument not in ('guitar', 'drums')) = 0
       
    

    如果您没有太多要搜索的工具,另一种选择是having 子句中的字符串聚合:

    having group_concat(i.instrument order by i.instrument) = 'drums,guitar'
    

    第二个表达式要求您为查询提供按字母顺序排列的乐器列表。

    【讨论】:

    • 应该有一些东西可以计算请求项目的数量来代替 2
    • @astentx:如果该值列表是在应用程序中构建的,您会希望应用程序知道给出了多少值。
    • @GMB ..正是如此。非常非常感谢!
    • 有多少乐器会“太多”?我正在考虑 30 种乐器的最大值
    【解决方案2】:

    另一种方法。按乐器组合匹配。

    SELECT title 
    FROM pieces
    WHERE id_piece IN (  
      SELECT piece_id
      FROM line_up 
      WHERE instrument_id IN (
        SELECT id_instrument
        FROM instruments 
        WHERE instrument IN ('Guitar', 'Drums')
      )
      GROUP BY piece_id
      HAVING group_concat(instrument_id order by instrument_id separator ',') = (
        SELECT group_concat(id_instrument order by id_instrument separator ',')
        FROM instruments
        WHERE instrument IN ('Guitar', 'Drums')
       )
    );
    

    【讨论】:

      【解决方案3】:

      您需要计算使用仪器过滤的行数,并将其与您选择的仪器总数和仪器数量进行比较。

      db<>fiddle

      with pieces as (
        select 1 as id_piece, 'hello' as title union all
        select 2 as id_piece, 'goodbye' union all
        select 3 as id_piece, 'goodnight'
      )
      , line_up as (
        select 1 as piece_id, 1 as instrument_id union all
        select 1 as piece_id, 2 as instrument_id union all
        select 2 as piece_id, 1 as instrument_id union all
        select 3 as piece_id, 2 as instrument_id
      )
      , instruments as (
        select 1 as id_instrument, 'guitar' as instrument union all
        select 2 as id_instrument, 'drums' as instrument
      )
      select p.id_piece, p.title
      from pieces as p
        join line_up as l
          on l.piece_id = p.id_piece
        join instruments as i
          on l.instrument_id = i.id_instrument
      group by p.id_piece, p.title
      having sum(case when i.instrument in ('guitar', 'drums') then 1 else 0 end) = count(1)
      and count(1) = (
        /*To select only valid instruments*/
        select count(1)
        from instruments as f
        where f.instrument in ('guitar', 'drums')
      )
      
      -----------+--------
      | id_piece | title |
      |----------+-------|
      |        1 | hello |
      -----------+--------
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-25
        • 2016-02-11
        • 2010-09-09
        • 1970-01-01
        • 2022-10-07
        相关资源
        最近更新 更多