SQL - объединить две таблицы, но получить среднее значение объединенного столбца только по вхождениям левой таблицы - PullRequest
0 голосов
/ 09 марта 2019

Я хочу объединить две таблицы, но получить среднее значение по объединенному столбцу только по вхождениям левой таблицы

документ:

+-----+-----+-------+
| dId | name| score |
+-----+-----+-------+
| A   | n1  | 100   |
| B   | n1  | 70    |
+-----+-----+-------+

лицо:

+------+------------+-----+
| ename| details    | dId |
+------+------------+-----+
| e1   | a          |   A |
| e2   | a          |   A |
| e3   | b          |   A |
| e4   | c          |   B |
+------+------------+-----+

Ожидаемый результат:

+------+--------+---------------+
| name | average| entities      |
+------+--------+---------------+
| n1    | 85    |e1, e2, e3, e4 |
+------+--------+---------------+

Потому что (100 + 70) / 2 = 85

Токовый выход:

+------+--------+---------------+
| name | average| entities      |
+------+--------+---------------+
| n1    | 92.5  |e1, e2, e3, e4 |
+------+--------+---------------+

Потому что (100 + 100 + 100 + 70) / 4 = 92,5

Текущий запрос:

SELECT
  docT.name,
  AVG(docT.score),
  STRING_AGG(entityT.ename)
FROM
  document_sentiment docT
JOIN
  entity_sentiment entityT
ON
  docT.dId = entityT.dId
GROUP BY
  docT.cname

Как я могу получить оценку, как в ожидаемом результате?

Ответы [ 4 ]

1 голос
/ 09 марта 2019

Попробуйте это

select  t.name, av,  
    GROUP_CONCAT(DISTINCT entityT.name ORDER BY entityT.name SEPARATOR ', ') AS entities
from (
    SELECT docT.dId, docT.name,
          AVG(docT.score) av
    FROM document_sentiment docT
    GROUP BY docT.name) T
JOIN entity_sentiment entityT ON T.dId = entityT.dId
GROUP BY T.name

SQL Fiddle

1 голос
/ 09 марта 2019

Ниже для BigQuery Standard SQL

#standardSQL
SELECT
  docT.name,
  AVG(docT.score) average,
  STRING_AGG(entityT.ename) entities
FROM `project.dataset.document_sentiment` docT
JOIN (
  SELECT dId, STRING_AGG(ename) ename
  FROM `project.dataset.entity_sentiment`
  GROUP BY dId
) entityT
ON docT.dId = entityT.dId
GROUP BY docT.name  

Вы можете протестировать, поиграть с выше, используя примеры данных из вашего вопроса, как в примере ниже

#standardSQL
WITH `project.dataset.document_sentiment` AS (
  SELECT 'A' dId, 'n1' name, 100 score UNION ALL
  SELECT 'B', 'n1', 70 
), `project.dataset.entity_sentiment` AS (
  SELECT 'e1' ename, 'a' details, 'A' dId UNION ALL
  SELECT 'e2', 'a', 'A' UNION ALL
  SELECT 'e3', 'b', 'A' UNION ALL
  SELECT 'e4', 'c', 'B' 
)
SELECT
  docT.name,
  AVG(docT.score) average,
  STRING_AGG(entityT.ename) entities
FROM `project.dataset.document_sentiment` docT
JOIN (
  SELECT dId, STRING_AGG(ename) ename
  FROM `project.dataset.entity_sentiment`
  GROUP BY dId
) entityT
ON docT.dId = entityT.dId
GROUP BY docT.name  

Row name    average     entities     
1   n1      85.0        e1,e2,e3,e4  
1 голос
/ 09 марта 2019

Попробуйте следующий код

select name, ename, avg(score) as score
from (SELECT
  docT.name,
  doct.Did,
  MAX(docT.score) as score,
  STRING_AGG(entityT.ename) as ename
FROM
  document_sentiment docT
JOIN
  entity_sentiment entityT
ON
  docT.dId = entityT.dId
GROUP BY
  docT.cname, doct.Did
) sub
group by name, ename
0 голосов
/ 09 марта 2019

Это сложно.Я думаю, что оконные функции могли бы быть самым простым решением:

SELECT docT.name, docT.avg_score,
       STRING_AGG(entityT.ename)
FROM (SELECT docT.*,
             AVG(docT.score) OVER (PARTITION BY docT.cname) as avg_score
      FROM document_sentiment docT
     ) docT JOIN
     entity_sentiment entityT
    ON docT.dId = entityT.dId
GROUP BY docT.cname, docT.avg_score;

Почему это сложно?Ну, если вы агрегируете по cname, то вы теряете dId и не можете сделать JOIN.

Предварительная агрегация не помогает.К счастью, это решается с помощью оконных функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...