2016-04-26 9 views
2

Ich habe die folgenden Tabellen:MODE Aggregationsfunktion mit Rotverschiebung

Kunden

customer_id name 
---------------- 
1   bob 
2   alice 
3   tim 

Käufe

id customer_id item_bought 
-------------------------- 
1 1   hat 
2 1   shoes 
3 2   glasses 
3 2   glasses 
4 2   book 
5 3   shoes 
6 1   hat 

Und ich möchte folgendes Ergebnis:

customer_name item_bought_most_often 
------------------------------------ 
bob   hat 
alice   glasses 
tim   shoes 

ich tun würde dies wie folgt aus (nicht wirklich versucht, nur die Idee):

SELECT customer.name as customer_name, 
    MODE(item_bought), as item_bought_most_ofen 
FROM customers 
INNER JOIN purchases USING (customer_id) 
GROUP_BY customer_id 

Allerdings ist die MODE aggregation function nicht in Redshift existieren.

Es scheint, dass Redshift user defined functions sind nur regelmäßige Skalarfunktionen, nicht Aggregationsfunktionen. Also ich glaube nicht, dass ich es selbst definieren kann.

Problemumgehung?

Antwort

2

können Sie mode() nachahmen von row_number() mit:

select name, item_bought 
from (select c.name, p.item_bought, count(*) as cnt, 
      row_number() over (order by count(*) desc) as seqnum 
     from customers c join 
      purchases p 
      using (customer_id) 
     group by c.name, p.item_bought 
    ) cp 
where seqnum = 1; 
+0

Ermöglicht Amazon Redshift, ** cnt '** zu verweisen:' wählen count (*) als cnt, row_number() über (nach cnt desc) als seqnum' auf dem gleichen Level? – lad2025

+0

@ lad2025. . . Arrrgh. In letzter Zeit zu viel Google BigQuery. –

1

Sie könnten erste COUNT jede Person Einkäufe und dann RANK() Fensterfunktion:

SELECT name AS customer_name, item_bought AS item_bought_most_often 
FROM(SELECT name,item_bought,RANK() OVER(PARTITION BY name ORDER BY cnt DESC) rnk 
    FROM (SELECT c.name, p.item_bought, COUNT(*) AS cnt 
      FROM customers c 
      JOIN purchases p 
      ON p.customer_id = c.customer_id 
      GROUP BY c.name, p.item_bought) AS s1) AS s2 
WHERE rnk = 1; 

LiveDemo

Ausgang:

╔═══════════════╦════════════════════════╗ 
║ customer_name ║ item_bought_most_often ║ 
╠═══════════════╬════════════════════════╣ 
║ alice   ║ glasses    ║ 
║ bob   ║ hat     ║ 
║ tim   ║ shoes     ║ 
║ zoe   ║ pencil     ║ 
║ zoe   ║ book     ║ 
╚═══════════════╩════════════════════════╝ 

Hinweis:

RANK werden mehrere häufigsten Werte behandeln.

+0

Ich machte etwas ähnliches. Ich habe wirklich auf eine Aggregationsfunktion wie 'FIRST (my_column), MODE (my_column)' oder die Möglichkeit, sie zu definieren, gehofft. Aber es existiert nicht. Eine andere Möglichkeit wäre etwas wie 'SPLIT_PART (LISTAGG (id, ','), ',', 1)'. oder 'udf_mode (LISTAGG, id, ',')'. udf_mode ist eine benutzerdefinierte Funktion, die den Modus basierend auf einer durch ein Komma getrennten Zeichenfolge berechnet. Aber das sind alle hacky. –

+1

@pinouchon Basierend auf [doc] (http://docs.aws.amazon.com/redshift/latest/dg/user-defined-functions.html) * 'Sie können einen benutzerdefinierten benutzerdefinierten >> Skalar << erstellen Funktion (UDF) '*. Ich sehe keine benutzerdefinierten Aggregatfunktionen doc wie in Postgresql [CREATE AGGREGATE] (http://www.postgresql.org/docs/current/static/sql-createaggregate.html) Idee mit 'LISTAGG' und dann mit udf_mode könnte klappen. – lad2025