Фильтрация строк таблицы, связанных с другой таблицей через сводную таблицу, на основе предложений where, действующих на вторую таблицу - PullRequest
0 голосов
/ 14 мая 2019
+--------------+
|  paintings   |
+--------------+
| id | title   |
+----+---------+
| 1  | muzelf1 |
| 2  | muzelf2 |
| 3  | muzelf3 |
+----+---------+

+----------------------------------------+
|                  tags                  |
+----------------------------------------+
| id | type            | name            |
+----+-----------------+-----------------+
| 1  | painting_medium | oil_painting    |
| 2  | painting_style  | impressionistic |
| 3  | painting_medium | mixed_media     |
| 4  | painting_medium | watercolours    |
| 5  | painting_style  | mixed_media     |
| 6  | painting_style  | photorealistic  |
+----+-----------------+-----------------+


+---------------------------+
|       paintings_tags      |
+---------------------------+
| id | painting_id | tag_id |
+----+-------------+--------+
| 1  | 1           | 1      |
| 2  | 1           | 2      |
| 3  | 2           | 4      |
| 4  | 3           | 2      |
| 5  | 3           | 1      |
+----+-------------+--------+

SQL

CREATE TABLE paintings (
id integer AUTO_INCREMENT PRIMARY KEY,
title text
);

INSERT INTO paintings(id,title) VALUES
 (1,'muzelf1'),(2,'muzelf2'),(3,'muzelf3');

CREATE TABLE tags (
id integer AUTO_INCREMENT PRIMARY KEY,
name text,
type text
);

INSERT INTO tags(id,name,type) VALUES
(1,'oil_painting','painting_medium')
,(2,'impressionistic','painting_style')
,(3,'mixed_media','painting_medium')
,(4,'watercolours','painting_medium')
,(5,'mixed_media','painting_style')
,(6,'photorealistic','painting_style');

CREATE TABLE paintings_tags (
id integer AUTO_INCREMENT PRIMARY KEY,
painting_id integer,
tag_id integer
);

INSERT INTO paintings_tags(id,painting_id,tag_id) VALUES
(1,1,1)
,(2,1,2)
,(3,2,4)
,(4,3,2)
,(5,3,1);

Найдите все картины с помощью [{tags.type = "painiting_medium", tags.name = "oil_painitng"}, {tags.type = "painiting_style", tags.name = "impressionistic"}].

+-----------------------------------+
|         Expected Output           |
+-----------------------------------+
| id | painting_title | painting_id |
+----+----------------+-------------+
| 1  | muzelf1        | 1           |
+----+----------------+-------------+
| 2  | muzelf3        | 3           |
+----+----------------+-------------+

Вот кое-что, что я пытался сделать, используя bookShelf ORM и конструктор запросов knex .

 Painting.query(function (qb) {
    qb.innerJoin('painting_tags','paintings.id','painting_tags.painting_id')
            .innerJoin('tags','painting_tags.tag_id','tags.id')
            .where(qb => {
              tagFilters.forEach(filter => {
                qb.where('tags.type',filter.type).andWhere('tags.name',filter.name)
              })
            });
    });

Вышеуказанное работает только в том случае, если массив фильтров тегов имеет только один элемент. Но мне нужно, чтобы он работал для всех фильтров в массиве.

Как бы выглядел необработанный запрос для вышеупомянутого? И как я могу конвертировать то же самое для работы с использованием ORM и построителя запросов?

1 Ответ

0 голосов
/ 15 мая 2019

Вот одна из идей:

SELECT p.id painting_id
     , p.title
     , MAX(CASE WHEN t.type = 'painting_medium' THEN t.name END) medium
     , MAX(CASE WHEN t.type = 'painting_style' THEN t.name END) style 
  FROM paintings p 
  JOIN paintings_tags pt 
    ON pt.painting_id = p.id 
  JOIN tags t 
    ON t.id = pt.tag_id 
 GROUP 
    BY p.id;
+-------------+---------+--------------+-----------------+
| painting_id | title   | medium       | style           |
+-------------+---------+--------------+-----------------+
|           1 | muzelf1 | oil_painting | impressionistic |
|           2 | muzelf2 | watercolours | NULL            |
|           3 | muzelf3 | oil_painting | impressionistic |
+-------------+---------+--------------+-----------------+

Вы можете отфильтровать это как подзапрос (или использовать HAVING), но, если набор данных не был обширным, я был бы склонен выполнить фильтрацию в небольшом количестве javascript.

...