1

在我正在构建的 rails 3 应用程序中,我有这三个类:

class Instrument < ActiveRecord::Base
  has_many :parts
  has_many :pieces, through: :parts
end    
class Part < ActiveRecord::Base
  belongs_to :instrument
  belongs_to :piece
end
class Piece < ActiveRecord::Base
  has_many :parts
  has_many :instruments, through: :parts
end

我正在寻找一种方法来选择所有相关乐器是任意一组乐器的子集的片段。

为避免混淆,我将举一个例子:

  • Piece(id:1) with instruments: [1,2,3],
  • Piece(id:2) 与 [1,2,3,4]
  • Piece(id:3) 与 [1,3,4]
  • 带有 [2] 的片段(id:4),

somequery(1,2,3,4)应该产生所有四个部分,somequery(1,2,3)只有 1 和 4,somequery(1,3,4)只有 3 和somequery(2)只有 4。

我正在使用rails 3.2,rails中的解决方案会很棒,但sql也很好,最好是postgres,但如果有一个mysql特定的解决方案也可以。此外,我没有使用相对较小的数据库(1000 多件、50 件仪器和 15.000 个零件),它没有被大量查询,所以如果查询在效率上不是最佳的,那也没问题。

作为最后的免责声明,我知道我在 ruby​​/rails 中的方法,但在 SQL 中相当绿色。

谢谢您的帮助!

4

2 回答 2

2
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp;

SET search_path='tmp';


CREATE TABLE instrument
        ( id INTEGER NOT NULL PRIMARY KEY
        , zname varchar
        );
INSERT INTO instrument(id, zname) VALUES
(1, 'instrument_1'), (2, 'instrument_2')
, (3, 'instrument_3'), (4, 'instrument_4');

CREATE TABLE piece
        ( id INTEGER NOT NULL PRIMARY KEY
        , zname varchar
        );
INSERT INTO piece(id, zname) VALUES
(1, 'piece_1'), (2, 'piece_2'), (3, 'piece_3'), (4, 'piece_4');

CREATE TABLE has_part
        ( piece_id INTEGER NOT NULL
        , instrument_id INTEGER NOT NULL
        , PRIMARY KEY (piece_id,instrument_id)
        );

INSERT INTO has_part(piece_id,instrument_id) VALUES
(1,1), (1,2), (1,3)
, (2,1), (2,2), (2,3), (2,4)
, (3,1), (3,3), (3,4)
, (4,2)
        ;

纯sql(不是双重否定NOT EXISTS , NOT IN()

SELECT zname
FROM piece pp
WHERE NOT EXISTS (
        SELECT * FROM has_part nx
        WHERE nx.piece_id = pp.id
        AND nx.instrument_id NOT IN (1,2,3)
        )
        ;
于 2012-06-20T13:34:37.813 回答
0

尝试这样的事情:

Piece.joins(:instruments).where(:instruments => {:id => [1, 2, 3, 4]})

这将创建一个查询,该查询连接 2 个表并选择带有所需 id 的乐器的片段,最后将它们包装在 ActiveRecord 对象中,以便您以后可以做任何您想做的事情。

于 2012-06-20T11:41:03.783 回答