Group By, но затем запрос в списке агрегации - PullRequest
0 голосов
/ 03 октября 2018

Если у меня есть две таблицы:

Users      Labels
-----      ------
id           id
           user_id

и пользователи и один ко многим на ярлыки.

Я хочу сказать: «Дайте мне всех пользователей с меткой = 1 или меткой =2, но не label = 3 ", поэтому пользователь с метками [1, 5, 6] будет действительным, [2, 5, 6] будет действительным, но [2, 3, 4] будет недействительным.

Как бы я поступил так?В настоящее время я использую array_agg и unnest, но я хотел бы сделать это без операций с массивами.

WITH (
    SELECT user_id, ARRAY_AGG(id) as labels from label
) as labels_agg

SELECT id FROM users
LEFT JOIN labels_agg ON id=user_id
WHERE 1 in UNNEST(labels) and 2 in UNNEST(labels) and 3 not in UNNEST(labels)

Ответы [ 4 ]

0 голосов
/ 22 ноября 2018
#standardSQL
SELECT user_id
FROM labels
GROUP BY user_id
HAVING COUNTIF(id IN (1, 2)) > 0 
AND COUNTIF(id = 3) = 0 
0 голосов
/ 03 октября 2018

с меткой = 1 или меткой = 2, но не меткой = 3

Я рекомендую group by и having для такого рода запросов:

select l.user_id
from labels l
where l.id in (1, 2, 3)
group by l.user_id
having sum(case when l.id in (1, 2) then 1 else 0 end) > 0 and
       sum(case when l.id in (3) then 1 else 0 end) = 0 ;

Предложение having с условным агрегированием достаточно гибкое.sum(case . . . ) подсчитывает количество упомянутых меток для каждого идентификатора пользователя.> 0 говорит, что, по крайней мере, один существует.= 0 говорит, что ничего не существует.

В этом случае вы можете упростить логику до:

select l.user_id
from labels l
where l.id in (1, 2, 3)
group by l.user_id
having max(l.id) in (1, 2);

Это работает для этих идентификаторов, но не так обобщенно.

0 голосов
/ 03 октября 2018

Вы можете получить желаемые результаты, используя EXCEPT.

;WITH cte AS
(
SELECT DISTINCT usr.id AS UserId, lbl.id AS Label_Id FROM Users usr LEFT 
JOIN Labels lbl ON
usr.id = lbl.[user_id] 
)
SELECT UserId FROM cte WHERE
Label_Id IN (1,2) 
EXCEPT
SELECT UserId FROM cte WHERE
Label_Id IN (3) 

Вот демо

0 голосов
/ 03 октября 2018

Это можно сделать с помощью not exists.

SELECT l1.user_id, l1.id as labels 
from label l1
where id in (1,2)
and not exists (select 1 from label l2 where l1.user_id=l2.user_id and l2.id = 3)
...