BG Development


Страници: (4) [1] 2 3 ... последна »  ( Първото ново мнение ) Reply to this topicStart new topicStart Poll

> SQL Monday
Gamma Goblin
Публикувано на: 19-08-2019, 06:57
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 4014
Регистриран на: 21.02.18



Задача: Намерете най-наеманите категории по клиент. Примерно:

CODE

Email         | category |
--------------------------------
sun@bgdev.org | action   |
--------------------------------




Базта данни може да се свали от тук: https://github.com/jOOQ/jOOQ/tree/master/jO...examples/Sakila
PMEmail PosterUsers Website
Top
thrawn
Публикувано на: 19-08-2019, 07:54
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 3864
Регистриран на: 17.01.17



На каква база данни?

Е това сериозно ли го пускаш като задача? Групираш по клиент и категория и извеждаш редът с максимален count. Да видим, за какво се ползва having.

Ако базата данни има window функции, можеш да ги ползваш за определяне на ранг на всеки групиран запис и да изведеш само записите с ранг 1.

Това мнение е било редактирано от thrawn на 19-08-2019, 07:55
PMEmail Poster
Top
Gamma Goblin
Публикувано на: 19-08-2019, 08:27
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 4014
Регистриран на: 21.02.18



На каквато искаш база icon_smile.gif Аз цъкам на постгрес.

Не е толкова лесно защото трябва да изведеш най-наемната категория по клиент:

CODE

AARON.SELBY@sakilacustomer.org      Travel
ADAM.GOOCH@sakilacustomer.org      Horror
ADAM.GOOCH@sakilacustomer.org      Foreign
ADAM.GOOCH@sakilacustomer.org      Children
ADRIAN.CLARY@sakilacustomer.org      Games
ADRIAN.CLARY@sakilacustomer.org      Family
AGNES.BISHOP@sakilacustomer.org      Sci-Fi
AGNES.BISHOP@sakilacustomer.org      Drama
AGNES.BISHOP@sakilacustomer.org      Action
ALAN.KAHN@sakilacustomer.org      Sports
ALAN.KAHN@sakilacustomer.org      Classics
....



Аз го нацъках, но ми е доста бавно - 23 секунди и ми е интересно дали няма по-просто решение. Ще изчакам още малко, някой може да иска да се помъчи.

PP: С WindowFunctions  го свалих на 100мс icon_smile.gif

Това мнение е било редактирано от Gamma Goblin на 19-08-2019, 08:53
PMEmail PosterUsers Website
Top
Gamma Goblin
Публикувано на: 19-08-2019, 17:09
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 4014
Регистриран на: 21.02.18



Обща част:
CODE
create or replace view categories_by_customer as
select c.email as customer, ct.name as category, count(*) as rentals
from customer c
        join rental r on c.customer_id = r.customer_id
        join inventory i on i.inventory_id = r.inventory_id
        join film f on f.film_id = i.film_id
        join film_category fc on fc.film_id = f.film_id
        join category ct on ct.category_id = fc.category_id
group by c.email, ct.name;


това ми беше първия опит:

CODE
select cc.customer, cc.category
               from categories_by_customer cc
               where cc.rentals = (
                   select max(rentals) from categories_by_customer x where x.customer = cc.customer group by x.customer
               )
               order by cc.customer asc, cc.category asc;

Обаче е брутално бавно (23сек), с едно индексче малко се ускорява (пада на 3 сек), но пак е бавно.

Като спомена  WindowFunctions, написах следното което минава за около 100мс:

CODE
select T.customer, T.category, T.rentals
               from (
                        select customer,
                               category,
                               rentals,
                               max(rentals) over (partition by customer) as maxc
                        from categories_by_customer
                    ) as T
               where T.maxc = T.rentals
               order by T.customer asc, T.category asc;


Интересно ми е дали има по-просто/чисто/бързо решение ?

PMEmail PosterUsers Website
Top
dvader
Публикувано на: 19-08-2019, 17:25
Quote Post


Group Icon
Име: Валерий Тодоров
Група: VIP
Ранг: Почетен член

Мнения: 5419
Регистриран на: 12.07.05



del

Това мнение е било редактирано от dvader на 19-08-2019, 17:29


--------------------
I find your lack of faith disturbing
PM
Top
thrawn
Публикувано на: 19-08-2019, 18:01
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 3864
Регистриран на: 17.01.17



Нещо не ми допада това решение.
Трябва ти максимална категория по клиент, което значи, че задължително ти трябва групиране по двете полета. След това ти трябва категорията с максимален count(*) от групите. Най-лесно се получава като номераш всеки ред от групата и избереш само първите (като ги сортираш низходящо) с window функция: row_number() over (order by count(*) desc)

За съжаление съм на телефон и не мога да пиша sql.

Интересния момент тук е, какво правим ако две категории са с равни показатели? Ако ти трябва просто някоя от тях row_number върши работа. Има обаче и вариант да изведеш о двете. Тогава си трябва rank.

Това мнение е било редактирано от thrawn на 19-08-2019, 18:02
PMEmail Poster
Top
Gamma Goblin
Публикувано на: 19-08-2019, 18:11
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 4014
Регистриран на: 21.02.18



Ето схемата в DB Fiddle на който му се играе (няма данни! - свалете си ги от първия линк в гитхъб): https://www.db-fiddle.com/f/22KucUrFud3aQ6zFMVTKCc/0
PMEmail PosterUsers Website
Top
Gamma Goblin
Публикувано на: 19-08-2019, 18:27
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 4014
Регистриран на: 21.02.18



QUOTE (thrawn @ 19-08-2019, 18:01)
Нещо не ми допада това решение.
Трябва ти максимална категория по клиент, което значи, че задължително ти трябва групиране по двете полета. След това ти трябва категорията с максимален count(*) от групите. Най-лесно се получава като номераш всеки ред от групата и избереш само първите (като ги сортираш низходящо) с window функция: row_number() over (order by count(*) desc)

За съжаление съм на телефон и не мога да пиша sql.

Интересния момент тук е, какво правим ако две категории са с равни показатели? Ако ти трябва просто някоя от тях row_number върши работа. Има обаче и вариант да изведеш о двете. Тогава си трябва rank.

ами с row_number()/rank() заявката изглежда по-същия начин и даже се генерира почти същия план и отнема същтото време

CODE

select T.customer, T.category
   from (
            select customer,
                   category,
                   rank() over (partition by customer order by rentals desc ) as something
            from categories_by_customer
        ) as T
   where T.something = 1
   order by T.customer asc, T.category asc;


Това мнение е било редактирано от Gamma Goblin на 19-08-2019, 18:35
PMEmail PosterUsers Website
Top
thrawn
Публикувано на: 19-08-2019, 18:43
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 3864
Регистриран на: 17.01.17



Прави join- овете на края, когато си отсял максимално данните.
Прави тестовете само с данните в rental и чак когато получиш това което ти трябва го линкни с останалите таблици.

---edit---
https://www.db-fiddle.com/f/22KucUrFud3aQ6zFMVTKCc/1 нещо такова, ама не мога да го тествм с данни.

Това мнение е било редактирано от thrawn на 19-08-2019, 19:06
PMEmail Poster
Top
dvader
Публикувано на: 19-08-2019, 19:52
Quote Post


Group Icon
Име: Валерий Тодоров
Група: VIP
Ранг: Почетен член

Мнения: 5419
Регистриран на: 12.07.05



QUOTE (thrawn @ 19-08-2019, 18:43)
Прави join- овете на края, когато си отсял максимално данните.
Прави тестовете само с данните в rental и чак когато получиш това което ти трябва го линкни с останалите таблици.

С коментарите съм съгласен, ама с твойто куери не съм много съгласен.
Правиш групиране по customer/inventory но можеш да имаш различни inventory с едно и също film_category.
Според мен групирането трябва да е по customer + category.


--------------------
I find your lack of faith disturbing
PM
Top
0 потребители преглеждат тази тема в момента (0 гости, 0 анонимни потребители)
Потребители, преглеждащи темата в момента:

Topic Options Страници: (4) [1] 2 3 ... последна » Reply to this topicStart new topicStart Poll

 


Copyright © 2003-2019 | BG Development | All Rights Reserved
RSS 2.0