В поисках наиболее эффективного запроса выбора - PullRequest
3 голосов
/ 30 июня 2019

У меня есть таблица, и мне нужен результат для разных строк, где должны существовать разные значения ключа в одном столбце.

Я получаю эту таблицу один раз в день через REST API из другой системы и выглядит в моей БД MySQL следующим образом (упрощенно):

+----+------+------------+-------+
| ID | type | date       | value |
+----+------+------------+-------+
|  1 | A    | 2019-06-01 |     1 |
|  2 | B    | 2019-06-01 |     2 |
|  3 | A    | 2019-06-02 |     4 |
|  4 | B    | 2019-06-03 |     5 |
|  9 | A    | 2019-06-09 |    11 |
| 10 | B    | 2019-06-09 |    14 |
| 11 | A    | 2019-06-24 |    99 |
+----+------+------------+-------+

Теперь мне нужно выбрать, что все результаты, только если существует значение для типа A и типа B в тот же день. Результат должен выглядеть так:

+------------+-------+--------+----+------+------------+-------+
| date       | typeA | valueA | ID | type | date       | value |
+------------+-------+--------+----+------+------------+-------+
| 2019-06-01 | A     |      1 |  2 | B    | 2019-06-01 |     2 |
| 2019-06-09 | A     |     11 | 10 | B    | 2019-06-09 |    14 |
+------------+-------+--------+----+------+------------+-------+
  • Первая идея:

Использование подвыборов ... вероятно, плохая идея для больших таблиц ... но я не уверен.

SELECT * from 
(SELECT date as dateA, value as valueA from V1 where type = 'A') AS subA,
(SELECT date as dateB, value as valueB from V1 where type = 'B') AS subB
WHERE dateA = dateB
  • 2-я идея:

Создание двух временных таблиц и затем объединение. Но нужно время, чтобы создать две таблицы и объединить обе новые временные таблицы.

CREATE TEMPORARY table tA SELECT date, type as typeA, value as valueA from V1 WHERE type = 'A';
CREATE TEMPORARY table tB SELECT date, type as typeB, value as valueB from V1 WHERE type = 'B';

SELECT * from tA 
INNER JOIN tB on tA.date = tB.date;
  • 3-я идея:

Создание только на временной таблице и использование этого для объединения с использованием основной таблицы:

CREATE TEMPORARY table tB SELECT * from V1 WHERE type = 'B';

SELECT * from V1 
INNER JOIN tB on V1.date = tB.date
where V1.type = 'A'

Какая из моих идей лучше всего подходит для большого стола или есть лучшее решение.

Заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 30 июня 2019

Вам нужно внутреннее соединение

select select v1.date,v1.type as typeA, v1.value as valueA, 
       v2.id, v2.type as typeB, v2.date, v2.value
  from v v1 join v v2    -- v is table name
    on v1.date = v2.date
    and v1.type = 'A' and v2.type = 'B';

+------------+-------+--------+----+------+------------+-------+
| date       | typeA | valueA | ID | type | date       | value |
+------------+-------+--------+----+------+------------+-------+
| 2019-06-01 | A     |      1 |  2 | B    | 2019-06-01 |     2 |
| 2019-06-09 | A     |     11 | 10 | B    | 2019-06-09 |    14 |
+------------+-------+--------+----+------+------------+-------+

Демо

1 голос
/ 01 июля 2019

Если каждая дата может иметь только один из каждого типа (то есть не может быть 2 'A' или 2 'B' для одной и той же даты), то вы можете сгруппировать по дате и использовать условное агрегирование для получения значенийдля разных типов.

select
    date,
    max(case when type = 'A' then id end) idA,
    max(case when type = 'A' then value end) valueA,
    max(case when type = 'B' then id end) idB,
    max(case when type = 'B' then value end) valueB
from V1
where type in ('A', 'B') -- only necessary if other types exist
group by date
having count(distinct type) = 2

http://sqlfiddle.com/#!9/69b9f/1

1 голос
/ 30 июня 2019

Возможно, это не самый очевидный запрос для написания.
Но это может иметь смысл, поскольку вы поворачиваете дату и объединяете типы с датой.
Производительность будет очень зависеть от используемых индексов, которые неизвестны.

SELECT 
 *
FROM (

  SELECT 
     date
   , MAX(CASE WHEN type = 'A' THEN type END) AS  typeA
   , MAX(CASE WHEN type = 'A' THEN value END) AS  valueA
  FROM 
   your_table
  WHERE
   type = 'A' 
  GROUP BY 
   date  
) AS a_type 
INNER JOIN (

  SELECT 
     date
   , MAX(CASE WHEN type = 'B' THEN type END) AS  typeB
   , MAX(CASE WHEN type = 'B' THEN value END) AS  valueB  
  FROM 
   your_table
  WHERE
   type = 'B' 
  GROUP BY 
   date   
) AS b_type
ON
 a_type.date = b_type.date

Результат

| date       | typeA | valueA | date       | typeB | valueB |
| ---------- | ----- | ------ | ---------- | ----- | ------ |
| 2019-06-01 | A     | 1      | 2019-06-01 | B     | 2      |
| 2019-06-09 | A     | 11     | 2019-06-09 | B     | 14     |

см. демо

1 голос
/ 30 июня 2019

эффективный способ может быть основан на внутреннем соединении между датой с различным счетом = 2 и таблицей itesel один раз для ype A и одним tyme для типа b

    select t.date, t1.type typeA, t1.value valueA, t2.type typeB, t2.value valueB, 
    from (
        select  date
        from  my_table  
        group by  date  
        having count(distinct type) = 2
    ) t 
    inner join  my_table t1 on t1.date = t.date and type='A'
    inner join  my_table t2 on t2.date = t.date and type='B'        
...