Как выбрать строку в группе на основе условия в SQL? - PullRequest
0 голосов
/ 28 апреля 2018

Вопрос Пожалуйста, рассмотрите следующую таблицу:

+--------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+--------------+--------+--------+
|            1 | A      | I      |
|            1 | A      | J      |
|            2 | B      | B      |
|            2 | B      | K      |
+--------------+--------+--------+

Для каждого transactionID (2 строки связаны с ID 1, две строки с ID 2) я хочу выбрать строку, для которой Sgroup = Rgroup, если какая-либо строка в пределах transactionID удовлетворяет условию. В противном случае, я хочу выбрать строку случайным образом. Для каждого transactionID самое большее одна строка удовлетворяет Sgroup = Rgroup. Как я могу это сделать?

Попытка решения Я знаю, как выбрать строки, для которых выполняется условие Sgroup = Rgroup, следующим образом:

SELECT *
FROM Transaction 
WHERE Sgroup = Rgroup;

+---------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+---------------+--------+--------+
|             2 | B      | B      |
+---------------+--------+--------+

Я также знаю, как выбрать строку случайным образом (благодаря этот вопрос ), если условие не выполняется следующим образом:

SELECT * FROM
(SELECT *
FROM Transaction
WHERE NOT transactionID IN
(SELECT transactionID
FROM Transaction 
WHERE Sgroup = Rgroup)
ORDER BY RAND()) AS temp
GROUP BY temp.transactionID;

+---------------+--------+--------+
| transactionID | Sgroup | Rgroup |
+---------------+--------+--------+
|             1 | A      | I      |
+---------------+--------+--------+

Как я могу объединить эти два выражения в одно? Я пытался работать с выражением CASE, которое я не получил далеко Может кто-нибудь любезно предложить решение?

Пример кода Вот код для генерации таблицы:

CREATE DATABASE MinimalExample;
USE MinimalExample;

CREATE TABLE Transaction (
transactionID int,
Sgroup nvarchar(1),
Rgroup nvarchar(1)
);

INSERT INTO Transaction VALUES
(1,'A','I'), 
(1,'A','J'),
(2,'B','B'),
(2,'B','K');

1 Ответ

0 голосов
/ 28 апреля 2018

Я думаю, что переменные могут быть самым простым решением, если вы действительно имеете в виду «случайный»:

select t.*
from (select t.*,
             (@rn := if(@i = transactionID, @rn + 1,
                        if(@i := transactionID, 1, 1)
                       )
             ) as rn
      from (select t.*
            from t
            order by transactionID, (sgroup = rgroup) desc, rand()
           ) t cross join
           (select @i := -1, @rn := 0) params
     ) t
where rn = 1;

Если под «случайным» вы подразумеваете «произвольный», вы можете использовать этот быстрый и грязный трюк:

(select t.*
 from t
 where sgroup = rgroup
)
union all
(select t.*
 from t
 where not exists (select 1 from t t2 where t2.id = t.id and t2.sgroup = t2.rgroup)
 group by transactionID
);

При этом используются страшные select * с group by, что я настоятельно не рекомендую использовать практически при любых обстоятельствах. Однако в этом случае вы специально пытаетесь сократить каждую группу до неопределенной строки, так что это выглядит не так уж плохо. Я отмечу, что MySQL не гарантирует, что все столбцы в наборе результатов будут взяты из одной и той же строки, хотя на практике это происходит.

Наконец, если у вас есть уникальный первичный ключ в каждой строке, вы можете использовать, вероятно, самое простое решение:

select t.*
from t
where t.id = (select t2.id
              from t t2
              where t2.transactionID = t.transactionID
              order by (rgroup = sgroup) desc, rand()
             );
...