2015-11-13 2 views
0

У меня есть запрос, который работает, но кажется, что он может/должен быть переписан более элегантным способом. Проблема в том, что я не нашел способ сделать это из-за инструкции HAVING.Несколько условий для HAVING в запросе MySQL

Я просто хочу посмотреть, в каком из 3 магазинов был куплен клиент, и назначить им «главный магазин».

Я закончил с UNION В 7 разных случаях ... это становится немного смешно.

В моем прекрасном мире я мог бы как-то использовать HAVING . . OR HAVING . ., но это, похоже, не соответствует философии MySQL.

SELECT Cust_ID, 'Main_store_1' AS Main_Store, sum(StoreName = 'Store_1') as num_Store_1, sum(StoreName = 'Store_2') as num_Store_2, sum(StoreName = 'Store_3') as num_Store_3 
FROM shopping_table 
WHERE Cust_ID in (<some list of Cust_IDs>) 
AND StoreName in ('Store_1', 'Store_2', 'Store_3') 
GROUP BY Cust_ID 
HAVING num_Store_1 > 1 and num_Store_2 = 0 and Store_3 = 0 
UNION 
SELECT Cust_ID, 'Main_store_2' AS Main_Store, sum(StoreName = 'Store_1') as num_Store_1, sum(StoreName = 'Store_2') as num_Store_2, sum(StoreName = 'Store_3') as num_Store_3 
FROM shopping_table 
WHERE Cust_ID in (<some list of Cust_IDs>) 
AND StoreName in ('Store_1', 'Store_2', 'Store_3') 
GROUP BY Cust_ID 
HAVING num_Store_1 = 0 and num_Store_2 > 0 and Store_3 = 0 

и советы/философские выводы были бы весьма признательны. Благодарю.

+0

Можете ли вы включить образец данных и ожидаемые результаты? Является ли главный магазин магазином, где клиент покупает исключительно? – JRD

+0

Да, главный магазин - это магазин, в котором покупатель совершает покупки исключительно (хотя в реальной жизни есть случай для любой комбинации посещенных магазинов, но назначение передает их в один «главный магазин» ... следовательно, 7 UNION заявлений и слишком длинный кусок кода MySQL) –

+0

Да, как вы собираетесь предоставить схему и образцы данных, чтобы мы могли * придумать *, как вы говорите об эффективности сравнения? – Drew

ответ

0

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

...HAVING (num_Store_1 > 1 and num_Store_2 = 0 and Store_3 = 0) OR (num_Store_1 = 0 and num_Store_2 > 0 and Store_3 = 0)

1

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

SELECT q.* 
, CASE 
    WHEN (num_Store_1 > 1 and num_Store_2 = 0 and Store_3 = 0) 
    THEN 'Main_store_1' 
    WHEN (num_Store_1 = 0 and num_Store_2 > 0 and Store_3 = 0) 
    THEN 'Main_store_2' 
    WHEN [more conditions] 
    THEN [another string] 
    ELSE 'No Main' 
    END AS Main_Store 
FROM (
    SELECT Cust_ID 
    , sum(StoreName = 'Store_1') as num_Store_1 
    , sum(StoreName = 'Store_2') as num_Store_2 
    , sum(StoreName = 'Store_3') as num_Store_3 
    FROM shopping_table 
    WHERE Cust_ID in (<some list of Cust_IDs>) 
    AND StoreName in ('Store_1', 'Store_2', 'Store_3') 
    GROUP BY Cust_ID 
) AS q 
; 
+0

Genius. Переход от 'HAVING' к' SELECT' - отличная идея. –

+0

Вы можете * сделать это без подзапроса, но тогда у вас будет много выражений СУММ. – Uueerdo

0

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

SELECT  Cust_ID, 
      Max(StoreName) as Main_Store, 
      Sum(StoreName = 'Store_1') as num_Store_1, 
      Sum(StoreName = 'Store_2') as num_Store_2, 
      Sum(StoreName = 'Store_3') as num_Store_3 
FROM  shopping_table 
WHERE  Cust_ID in (<some list of Cust_IDs>) 
AND   StoreName in ('Store_1', 'Store_2', 'Store_3') 
GROUP BY Cust_ID 
HAVING  Count(DISTINCT StoreName) = 1 

Или, если вы хотите получить список других клиентов, а также, и выбрать в качестве их основного магазина самого важного магазина среди тех, кого они посетили, а затем использовать CASE с WHEN в магазин, в порядке их по убыванию priority:

SELECT  Cust_ID, 
      CASE 
       WHEN Sum(StoreName = 'Store_1') > 0 THEN 'Store_1' 
       WHEN Sum(StoreName = 'Store_2') > 0 THEN 'Store_2' 
       WHEN Sum(StoreName = 'Store_3') > 0 THEN 'Store_3' 
      END as Main_Store, 
      Sum(StoreName = 'Store_1') as num_Store_1, 
      Sum(StoreName = 'Store_2') as num_Store_2, 
      Sum(StoreName = 'Store_3') as num_Store_3 
FROM  shopping_table 
WHERE  Cust_ID in (<some list of Cust_IDs>) 
AND   StoreName in ('Store_1', 'Store_2', 'Store_3') 
GROUP BY Cust_ID 
+0

В вашем первом примере вам не понадобятся «SUM» или «MAX», так как «COUNT (DISTINCT storeName) = 1» устраняет необходимость. Во-вторых, каждый, кто посетил магазин 1 даже за один раз, будет иметь его в качестве основного магазина, даже если он посетил магазин3 тысячу раз. – Uueerdo

+0

В соответствии со стандартами «SQL» вам необходимо агрегировать выбранные поля, которые вы не группируете, поэтому необходимы 'SUM' и' MAX'. И вы правы в отношении второго наблюдения. Это сделано так. ОП не указал, что разница в уровне счета должна учитываться с некоторым весовым коэффициентом. – trincot

Смежные вопросы