SQL 按日期加入和排序个人主题
SQL Joining and ordering invididual subjects by date
所以我有两个SQLtable,一个是客户通讯录,一个是购买日志。
客户Table
Cust ID Cust Name
1 Adam
2 Brian
3 Charles
4 Dave
...
购买记录
Customer ID Price Date
1 0 1996-01-20
1 0 1995-01-01
2 1999-05-22
...
我想看的是客户名称和最近一次购买的价格。
所以 table 应该是这样的:
Customer Name Price
Adam 0
Brian
...
我想我对使用哪些函数(如排序依据、限制和连接)有一个大致的了解,但我无法将它们组合在一起。
更糟糕的是,我需要找出处理联系的方法,这意味着如果客户在同一天进行多次购买。默认情况下,我认为它只会列出第一个价格,但我如何才能让它列出当天的最高价格?还是平均价?
让我们暂时搁置您写的领带问题,从基础开始,将名称纳入购买 table。这是一个简单的连接:
SELECT c.name, p.price, p.date from purchase as p inner join customer as c
ON c.cust_id = c.customer_id;
这会给你一个 table 包含所有购买的名称。
现在,您可以在此添加平均值、总和、最大值或任何您想要的聚合,例如:
SELECT name, date, MAX(price) from (
SELECT c.name, p.price, p.date from purchase as p inner join customer as c
ON c.cust_id = c.customer_id
) group by name, date;
您可以使用 Postgres 的 distinct on ()
运算符:
SELECT distinct on (c.cust_id) c.cust_name, p.price, p.purchase_date
from customer c
join purchase p ON c.cust_id = c.customer_id
order by c.cust_id, p.date desc, p.price desc;
通过将 price desc
包含在 order by
中,如果一天有两个价格,Postgres 将选择最高的价格。
另一种选择是加入派生的 table(这可能更快)
select c.cust_id, c.cust_name, p.price, p.purchase_date
from customer c
join (
select distinct on (customer_id) customer_id, price, purchase_date
from purchase
order by customer_id, purchase_date desc, p.price desc
) p on c.cust_id = p.customer_id;
记录排名的标准 SQL 方式是 RANK
或 DENSE_RANK
(均考虑平局)或 ROW_NUMBER
(不考虑平局)。
以下查询取最后一个购买日,如果有多次购买,它会选择价格较高的记录。 (好吧,如果有两个最高价相同的购买,其中一个记录是任意选择的,但这无关紧要。)
select
customer.cust_name,
ranked.price
from customer
join
(
select
customer_id,
price,
row_number() over (partition by customer_id order by date desc, price desc) as rnk
from purchase_history
) ranked on ranked.customer_id = customer.cust_id and ranked.rnk = 1;
以下查询获取最后一个购买日的购买量并计算这些的平均价格。
select
customer.cust_name,
avg(ranked.price)
from customer
join
(
select
customer_id,
price,
rank() over (partition by customer_id order by date desc) as rnk
from purchase_history
) ranked on ranked.customer_id = customer.cust_id and ranked.rnk = 1
group by customer.cust_id, customer.cust_name;
所以我有两个SQLtable,一个是客户通讯录,一个是购买日志。
客户Table
Cust ID Cust Name
1 Adam
2 Brian
3 Charles
4 Dave
...
购买记录
Customer ID Price Date
1 0 1996-01-20
1 0 1995-01-01
2 1999-05-22
...
我想看的是客户名称和最近一次购买的价格。 所以 table 应该是这样的:
Customer Name Price
Adam 0
Brian
...
我想我对使用哪些函数(如排序依据、限制和连接)有一个大致的了解,但我无法将它们组合在一起。
更糟糕的是,我需要找出处理联系的方法,这意味着如果客户在同一天进行多次购买。默认情况下,我认为它只会列出第一个价格,但我如何才能让它列出当天的最高价格?还是平均价?
让我们暂时搁置您写的领带问题,从基础开始,将名称纳入购买 table。这是一个简单的连接:
SELECT c.name, p.price, p.date from purchase as p inner join customer as c
ON c.cust_id = c.customer_id;
这会给你一个 table 包含所有购买的名称。
现在,您可以在此添加平均值、总和、最大值或任何您想要的聚合,例如:
SELECT name, date, MAX(price) from (
SELECT c.name, p.price, p.date from purchase as p inner join customer as c
ON c.cust_id = c.customer_id
) group by name, date;
您可以使用 Postgres 的 distinct on ()
运算符:
SELECT distinct on (c.cust_id) c.cust_name, p.price, p.purchase_date
from customer c
join purchase p ON c.cust_id = c.customer_id
order by c.cust_id, p.date desc, p.price desc;
通过将 price desc
包含在 order by
中,如果一天有两个价格,Postgres 将选择最高的价格。
另一种选择是加入派生的 table(这可能更快)
select c.cust_id, c.cust_name, p.price, p.purchase_date
from customer c
join (
select distinct on (customer_id) customer_id, price, purchase_date
from purchase
order by customer_id, purchase_date desc, p.price desc
) p on c.cust_id = p.customer_id;
记录排名的标准 SQL 方式是 RANK
或 DENSE_RANK
(均考虑平局)或 ROW_NUMBER
(不考虑平局)。
以下查询取最后一个购买日,如果有多次购买,它会选择价格较高的记录。 (好吧,如果有两个最高价相同的购买,其中一个记录是任意选择的,但这无关紧要。)
select
customer.cust_name,
ranked.price
from customer
join
(
select
customer_id,
price,
row_number() over (partition by customer_id order by date desc, price desc) as rnk
from purchase_history
) ranked on ranked.customer_id = customer.cust_id and ranked.rnk = 1;
以下查询获取最后一个购买日的购买量并计算这些的平均价格。
select
customer.cust_name,
avg(ranked.price)
from customer
join
(
select
customer_id,
price,
rank() over (partition by customer_id order by date desc) as rnk
from purchase_history
) ranked on ranked.customer_id = customer.cust_id and ranked.rnk = 1
group by customer.cust_id, customer.cust_name;