Агрегировать "только один раз", будь то 1 или 2 строки в соединении - PullRequest
0 голосов
/ 05 ноября 2019

Я пытаюсь выполнить агрегатный запрос, в котором объединение может найти 0, 1 или 2 строки в таблице объединения. Я хочу объединить «только один раз» независимо от того, находит ли объединение 1 или 2 подходящих строки.

Минимальный пример.

+--------------+--------+-----------+
| container_id | thing  | alternate |
+--------------+--------+-----------+
|            1 | box    |         0 |
|            1 | box    |         1 |
|            1 | hat    |         0 |
|            2 | monkey |         0 |
|            3 | monkey |         1 |
|            3 | chair  |         1 |
+--------------+--------+-----------+

+--------------+------+
| container_id | uses |
+--------------+------+
|            1 |    3 |
|            2 |    1 |
|            3 |    2 |
+--------------+------+

Вы можете видеть, что 'box' связан с container_idномер 1 дважды. Один раз с альтернативным = 0 и один раз с альтернативным = 1.

SELECT 
    thing, COUNT(DISTINCT ct.container_id) AS occurrencs, SUM(uses) AS uses 
FROM 
    container_thing AS ct 
INNER JOIN 
    container_usage AS cu ON cu.container_id = ct.container_id 
GROUP BY 
    thing

дает:

+--------+------------+------+
| thing  | occurrencs | uses |
+--------+------------+------+
| box    |          1 |    6 |
| chair  |          1 |    2 |
| hat    |          1 |    3 |
| monkey |          2 |    3 |
+--------+------------+------+

, но я действительно хочу это:

+--------+------------+------+
| thing  | occurrencs | uses |
+--------+------------+------+
| box    |          1 |    3 |
| chair  |          1 |    2 |
| hat    |          1 |    3 |
| monkey |          2 |    3 |
+--------+------------+------+

Я хочу 3в качестве значения для использования в первой строке, потому что 'box' находился в контейнерах, которые использовались всего три раза. Из-за «альтернативного» столбца я получаю 6 для этого значения. Могу ли я присоединиться по-разному или сгруппироваться по-разному или выразить в выражении SUM только SUM один раз для каждой отдельной вещи независимо от значения альтернативы?

(Обратите внимание, что вещь может появляться вконтейнер с альтернативой, без альтернативы или с обоими.)

SQL, необходимый для настройки минимального примера:

-- Set up db
CREATE DATABASE sumtest;
USE sumtest;

-- Set up tables
CREATE TABLE container (id INT PRIMARY KEY);
CREATE TABLE container_thing (container_id INT, thing NVARCHAR(10), alternate BOOLEAN);
CREATE TABLE container_usage (container_id INT, uses INT);

-- Insert data
INSERT INTO container (id) VALUES (1), (2), (3);
INSERT INTO container_thing (container_id, thing, alternate) VALUES (1, 'box', FALSE), (1, 'box', TRUE), (1, 'hat', FALSE), (2, 'monkey', FALSE), (3, 'monkey', TRUE), (3, 'chair', TRUE);
INSERT INTO container_usage VALUES (1, 3), (2, 1), (3, 2);

-- Query
SELECT thing, COUNT(DISTINCT ct.container_id) AS occurrencs, SUM(uses) AS uses FROM container_thing AS ct INNER JOIN container_usage AS cu ON cu.container_id = ct.container_id GROUP BY thing;

Ответы [ 2 ]

0 голосов
/ 05 ноября 2019

Вы можете обойти эту проблему, выбрав DISTINCT значения container_id и thing из container_thing в производной таблице и JOIN с этим значением container_usage:

SELECT thing, COUNT(ct.container_id) AS occurrences, SUM(uses) AS uses 
FROM (SELECT DISTINCT container_id, thing
      FROM container_thing) AS ct 
INNER JOIN container_usage AS cu ON cu.container_id = ct.container_id 
GROUP BY thing;

Вывод

thing   occurrences     uses
box     1               3
chair   1               2
hat     1               3
monkey  2               3

Демонстрация по dbfiddle

0 голосов
/ 05 ноября 2019

Если вы хотите только использовать .., тогда вы не должны выполнять сумму в соединении .., потому что объединение создает строки T1xT2 для каждого предложения ON *
где N - номер строки из таблицы1, а M - число. строк из таблицы2, поэтому в случае поля у вас есть 2 x 1 со значением 3 = 6.

, чтобы избежать этого, вы должны объединить container_usage с подзапросом для совокупного результата для подсчета container_thing

select t.thing, t.count_container,  cu.uses 
from (
  SELECT thing,  container_id, COUNT(DISTINCT ct.container_id)  count_container
  FROM  container_thing 
  GROUP BY thing, container_id
) t 
inner join  container_usage AS cu ON cu.container_id = t.container_id  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...