BG Development


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

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



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

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



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

CODE

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




Базта данни може да се свали от тук: https://github.com/jOOQ/jOOQ/tree/master/jO...examples/Sakila


--------------------
https://www.rust-lang.org/
---
Хора, които са прекалено умни, за да се занимават с политика, са наказани да бъдат управлявани от глупаци.
---
Life is hard; it's harder when you're stupid.
---
Black metal is like coffee. You have to learn to drink it but when you get used to it, you just want it darker and darker
PMEmail PosterUsers Website
Top
thrawn
Публикувано на: 19-08-2019, 07:54
Quote Post



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

Мнения: 2490
Регистриран на: 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



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

Мнения: 2780
Регистриран на: 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


--------------------
https://www.rust-lang.org/
---
Хора, които са прекалено умни, за да се занимават с политика, са наказани да бъдат управлявани от глупаци.
---
Life is hard; it's harder when you're stupid.
---
Black metal is like coffee. You have to learn to drink it but when you get used to it, you just want it darker and darker
PMEmail PosterUsers Website
Top
Gamma Goblin
Публикувано на: 19-08-2019, 17:09
Quote Post



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

Мнения: 2780
Регистриран на: 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;


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



--------------------
https://www.rust-lang.org/
---
Хора, които са прекалено умни, за да се занимават с политика, са наказани да бъдат управлявани от глупаци.
---
Life is hard; it's harder when you're stupid.
---
Black metal is like coffee. You have to learn to drink it but when you get used to it, you just want it darker and darker
PMEmail PosterUsers Website
Top
dvader
Публикувано на: 19-08-2019, 17:25
Quote Post


Group Icon
Име:
Група: VIP
Ранг: Почетен член

Мнения: 4575
Регистриран на: 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



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

Мнения: 2490
Регистриран на: 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



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

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



Ето схемата в DB Fiddle на който му се играе (няма данни! - свалете си ги от първия линк в гитхъб): https://www.db-fiddle.com/f/22KucUrFud3aQ6zFMVTKCc/0


--------------------
https://www.rust-lang.org/
---
Хора, които са прекалено умни, за да се занимават с политика, са наказани да бъдат управлявани от глупаци.
---
Life is hard; it's harder when you're stupid.
---
Black metal is like coffee. You have to learn to drink it but when you get used to it, you just want it darker and darker
PMEmail PosterUsers Website
Top
Gamma Goblin
Публикувано на: 19-08-2019, 18:27
Quote Post



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

Мнения: 2780
Регистриран на: 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


--------------------
https://www.rust-lang.org/
---
Хора, които са прекалено умни, за да се занимават с политика, са наказани да бъдат управлявани от глупаци.
---
Life is hard; it's harder when you're stupid.
---
Black metal is like coffee. You have to learn to drink it but when you get used to it, you just want it darker and darker
PMEmail PosterUsers Website
Top
thrawn
Публикувано на: 19-08-2019, 18:43
Quote Post



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

Мнения: 2490
Регистриран на: 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
Ранг: Почетен член

Мнения: 4575
Регистриран на: 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
1 потребители преглеждат тази тема в момента (1 гости, 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