1

У меня есть эта таблица:PostgreSQL выбор несколько кортежей в ИНЕКЕ

create table myTable (keyword text, category text, result text 
        , primary key (keyword,category)); 

insert into myTable values 
    ('foo',  'A', '10'), 
    ('bar',  'A', '200'), 
    ('baz',  'A', '10'), 
    ('Superman', 'B', '200'), 
    ('Yoda',  'B', '10'), 
    ('foo',  'C', '10'); 

Я хочу, чтобы получить результаты по наборам (keyword,category). Таким образом, в основном, с одним легким кортежем У меня есть следующий запрос:

SELECT result FROM myTable WHERE keyword LIKE '%a%' AND category = 'A'; 
-- returns 10,200 as expected 

Но я могу иметь столько кортежей, как я хочу. Распространяя этот запрос для нескольких кортежей возвращает плохие результаты:

SELECT result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    AND (keyword LIKE '%Superman%' AND category = 'B'); 
-- expected 200; but returned no rows... 

SELECT distinct result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    OR (NOT(keyword LIKE '%Superman%') AND category = 'B'); 
-- expected 10; but returned 10,200... 

Это довольно логично, поскольку PostgreSQL не следовать порядку оператора и круглые скобки.

Только OR статьи работают. Если бы я только OR положения, я бы использовать что-то вроде этого:

SELECT result FROM myTable 
    INNER JOIN (VALUES 
     ('foo','C'), 
     ('Superman', 'B') 
    ) t(keyword,category) USING (keyword,category); -- 10,200 as expected 

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

Точнее, когда я пишу:

SELECT result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    AND (keyword LIKE '%Superman%' AND category = 'B'); 
-- expected 200; but returned no row 

Я имею в виду, я хочу пересечение результатов, полученных два пунктов. Первый кортеж возвращает 10 200, а второй 200. Я хочу вернуть только 200 в этом случае.

Использование OR как предполагающее, в комментариях, как это:

SELECT distinct result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    OR (keyword LIKE '%Superman%' AND category = 'B'); 

возвращает 10200, но это не значит, что я хочу ...

+0

Ошибка в коде, возможно? Возможно, вы имели в виду: 'SELECT result FROM myTable WHERE (ключевое слово LIKE '% a%' AND category = 'A') ИЛИ (ключевое слово LIKE '% Superman%' AND category = 'B');'. Если у вас есть категория A ** AND ** категория B, то результат, очевидно, ничего. –

+0

Что касается 'keyword LIKE '% a%' AND category = 'A'' => возвращает bar и baz, как ожидалось, где« NOT »(ключевое слово LIKE«% Superman% ») AND category =' B'' => возвращает yoda как ожидалось –

+0

@ SimoKivistö Для первого запроса по ошибке я не хочу OR, так как я не хочу получать каждый результат для первых кортежей PLUS каждый результат для второго. На самом деле это ИНТЕРСИЦИЯ, которая мне нужна. – pidupuis

ответ

1

То, что вы, кажется, ищет называется реляционная деление. Задача может быть сформулирована как:

результаты находят, что имеют, по меньшей мере, один ряд, соответствующие эти условия:
keyword LIKE '%a%' AND category = 'A'
и по меньшей мере, один ряд соответствие этих условия:
keyword LIKE '%Superman%' AND category = 'B'

Быстрое решение для условий, возвращающих DISTINCT результаты:

SELECT DISTINCT result 
FROM tbl t1 
JOIN tbl t2 USING (result) 
WHERE t1.keyword LIKE '%a%' AND t1.category = 'A' 
AND t2.keyword LIKE '%Superman%' AND t2.category = 'B'; 

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

SELECT result 
FROM (
    SELECT DISTINCT result 
    FROM tbl 
    WHERE keyword LIKE '%a%' AND category = 'A' 
    ) t1 
JOIN (
    SELECT DISTINCT result 
    FROM tbl 
    WHERE keyword LIKE '%Superman%' AND category = 'B' 
    ) t2 USING (result); 

Или:

SELECT result 
FROM (
    SELECT DISTINCT result 
    FROM tbl 
    WHERE keyword LIKE '%a%' AND category = 'A' 
    ) t 
WHERE EXISTS (
    SELECT 1 
    FROM tbl 
    WHERE result = t.result 
    AND keyword LIKE '%Superman%' AND category = 'B' 
    ); 

SQL Скрипки.

Мы собрали арсенал методов запроса в соответствии с этим: смежный вопрос

+0

Решение с использованием 'EXISTS' выглядит лучше, потому что оно позволяет мне использовать' NOT'. Как вы предлагаете использовать его с большим количеством кортежей, чередующихся с символами 'AND' и' OR'? (Можно ли объединить несколько «EXISTS» и «UNION» без бесконечной глубины встроенного выбора?) – pidupuis

+0

@pidupuis: вы уже знаете, как реализовать 'OR', добавить' EXISTS'/'NOT EXISTS' в предложение WHERE для' И '/' И НЕ' ... –

0

Вы были почти там:

SELECT distinct result FROM myTable 
WHERE (keyword LIKE '%a%' AND category = 'A') 
OR (keyword LIKE '%Superman%' AND category = 'B'); 

Что это означает: он возвращает строку, если ключевое слово похоже на «% a%» и category = «A» ИЛИ, если ключевое слово похоже на «% supaerman%» и category = 'B'

Ваши запросы сделал следующее

SELECT result FROM myTable 
WHERE (keyword LIKE '%a%' AND category = 'A') 
AND (keyword LIKE '%Superman%' AND category = 'B'); -- expected 200; but returned no rows 

Чтобы вернуться сюда строку (среди других вещей категории в этой строке должны были быть «A» и «B». Поскольку это не может быть одновременно, строки не возвращаются.

SELECT distinct result FROM myTable 
WHERE (keyword LIKE '%a%' AND category = 'A') 
OR (NOT(keyword LIKE '%Superman%') AND category = 'B'); -- expected 10; but returned 10,200.. 

НЕ (...) в этом случае сделал запрос возвращает все строки с категорией равным «B», где ключевое слово не содержит «Супермена» (плюс, конечно, результаты из условия, прежде чем он OR) ,;)

+0

Спасибо, но это не OR. И я имел в виду ИНТЕРЕС. См. Мое редактирование. – pidupuis

0

Я думаю, вы также можете взглянуть на документацию SIMILAR TO

Вы можете сделать что-то вроде этого

SELECT * from myTable where keyword SIMILAR TO '%(oo|ba)%' and category SIMILAR TO '(A)'; 
Смежные вопросы