SQLite 3.24 - подсчет вхождений значений, сгруппированных по id, без использования оконных функций - PullRequest
1 голос
/ 07 апреля 2020

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

Я работаю над инструментом для торговой карточной игры, колода - это список карт, у меня есть отображение таблицы deckId на cardId

Учитывая пример (rowid не показано)

deckId| cardId
-----------
1  | 321
1  | 50
1  | 100
1  | 125
2  | 321
2  | 50
2  | 99
2  | 87
3  | 50
3  | 12
3  | 5
3  | 47
4  | 999
4  | 998
4  | 997
4  | 996

Я пытаюсь выполнить запрос для каждой колоды, сколько карт у нее в одной колоде.

deckId  |  count(cardId)
--------------------
1  | 2 // 321 and 50 appear in both deckId=1 and deckId=2
2  | 2 // 321 and 50 appear in both deckId=1 and deckId=2
3  | 1 // 50 appears in deckId=2 and deckId=3
4  | 0 // none of the cards in deckId=4 appear in any other decks

Я пробовал

SELECT deckId, COUNT(cardId)
FROM table
GROUP BY deckId

но это просто дает мне (потому что в каждой колоде по 4 карты):

deckId  | count(cardId)
-----------------------
1 | 4
2 | 4
3 | 4
4 | 4

Итак, как мне запросить каждую колоду, сколько у нее «общих» карт? ? (были предложены оконные функции, но я вынужден использовать SQLite версии 3.24, прежде чем оконные функции будут реализованы)

Ответы [ 2 ]

2 голосов
/ 07 апреля 2020

Вы можете использовать оконные функции и агрегирование:

select 
    deckId,
    sum(case when cnt > 1 then 1 else 0 end) cnt
from (
    select deckId, count(*) over(partition by cardId) cnt
    from mytable 
) t
group by deckId

Демонстрация на DB Fiddle :

deckId | cnt
:----- | --:
1      |   2
2      |   2
3      |   1
4      |   0

In В версиях SQLite, которые не поддерживают оконные функции, вы можете эмулировать количество окон с помощью подзапроса:

select 
    deckId,
    sum(case when cnt > 1 then 1 else 0 end) cnt
from (
    select 
        deckId, 
        (select count(*) from mytable t1 where t1.cardId = t.cardId) cnt
    from mytable t 
) t
group by deckId
1 голос
/ 07 апреля 2020

Вот способ, который не использует оконные функции:

WITH counted AS
  (SELECT deckId,
          (SELECT count(*)
           FROM decks AS d2
           WHERE d.cardId = d2.cardId) AS cnt
   FROM decks AS d)
SELECT deckId, sum(cnt > 1) AS Duplicates
FROM counted
GROUP BY deckId
ORDER BY deckId;

, который производит для вашей таблицы образцов

deckId      Duplicates
----------  ----------
1           2
2           2
3           1
4           0

(Вы хотите отдельные индексы для deckId и cardId столбцы для лучшей производительности.)

...