显示每个客户每月平均花费金额的数据透视查询
Pivot query that shows the average amount spent per customer for each month
我试图通过针对 Sakila Sample Database 显示每个客户每月花费的平均金额编写一个来更好地编写数据透视查询。我已经掌握了基本查询,但我不确定如何将其转换为数据透视查询。
这是该查询的 SQL:
SELECT
payment.amount AS amount,
customer.customer_id AS customer_id,
customer.last_name AS last_name,
customer.first_name AS first_name,
FORMAT ( rental.rental_date, 'MMM' ) _Month,
avg(amount) over ( PARTITION BY customer.customer_id ) avg_rental_amt
FROM
customer INNER JOIN
rental
ON customer.customer_id = rental.customer_id INNER JOIN
payment
ON payment.rental_id = rental.rental_id AND
payment.customer_id = customer.customer_id
这是上面的查询结果在我的 Navicat 数据库开发和管理客户端中:
任何人都知道如何将这些结果转换为数据透视查询,以便从左到右的列为 customer_id、last_name、first_name、一月、二月、... Dec,avg_rental_amt,在 MySQL 或 SQL 服务器中?如果可能的话,我希望结果看起来像这样:
customer_id last_name first_name Jan Feb...Dec avg_rental_amt
505 ABNEY RAFAEL 4.9 2.9 3.4 4.65
504 ADAM NATHANIEL 5.3 4.4 5.2 4.77
36 ADAMS KATHLEEN .9 .9 3.1 3.43
etc...
谢谢!
罗布
您可以进行条件聚合:
SELECT c.customer_id, c.last_name, c.first_name,
AVG(CASE WHEN MONTH(r.rental_date) = 1 THEN p.amount END) as avg_rental_january,
AVG(CASE WHEN MONTH(r.rental_date) = 2 THEN p.amount END) as avg_rental_feb,
...
AVG(CASE WHEN MONTH(r.rental_date) = 12 THEN p.amount END) as avg_rental_december,
AVG(p.amount) avg_rental
FROM customer c
INNER JOIN rental r ON c.customer_id = r.customer_id
INNER JOIN payment p ON p.rental_id = r.rental_id AND p.customer_id = c.customer_id
GROUP BY c.customer_id, c.last_name, c.first_name
此语法应该适用于 SQL 服务器和 MySQL。
请注意,这会计算同一客户 在不同年份 的平均租金 - 与您的原始查询中一样。这可能是,也可能不是您想要的。如果没有,您需要根据您的具体需要调整条件表达式。
您可以通过应用条件聚合来动态管理返回结果
在 SQL 服务器 (Demo) :
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
WITH t AS
(
SELECT 1 AS n UNION ALL
SELECT n + 1 FROM t WHERE n + 1 <= 12
)
SELECT @cols = STRING_AGG(CONCAT('AVG(CASE WHEN MONTH(r.rental_date)=',n,
' THEN r.amount END) "',
FORMAT ( DATEADD( month , n , -1 ), 'MMM' ),
'"'), ',')
FROM t;
SET @query =
CONCAT(
'SELECT c.customer_id AS customer_id,' , @cols ,
' , AVG(r.amount) AS avg_rental_amt ',
' FROM customer c
JOIN rental r
ON c.customer_id = r.customer_id
JOIN payment p
ON p.rental_id = r.rental_id
AND p.customer_id = c.customer_id
GROUP BY c.customer_id, c.last_name, c.first_name');
EXEC sp_executesql @query;
在我的SQL (Demo):
SET @query = NULL;
SET @cols = NULL;
SELECT GROUP_CONCAT(
CONCAT(
'AVG(CASE WHEN MONTH(r.rental_date)=', n,
' THEN r.amount END) AS "',
DATE_FORMAT(CONCAT('0000-',LPAD(n,2,0),'-00'), '%b'),
'"'
)
)
INTO @cols
FROM
(
SELECT @n := @n + 1 AS n
FROM information_schema.tables
JOIN (SELECT @n := 0) AS iter ) nn
WHERE n <= 12;
SET @query =
CONCAT(
'SELECT c.customer_id AS customer_id,' , @cols ,
' , AVG(r.amount) AS avg_rental_amt ',
' FROM customer c
JOIN rental r
ON c.customer_id = r.customer_id
JOIN payment p
ON p.rental_id = r.rental_id
AND p.customer_id = c.customer_id
GROUP BY c.customer_id, c.last_name, c.first_name');
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
我试图通过针对 Sakila Sample Database 显示每个客户每月花费的平均金额编写一个来更好地编写数据透视查询。我已经掌握了基本查询,但我不确定如何将其转换为数据透视查询。
这是该查询的 SQL:
SELECT
payment.amount AS amount,
customer.customer_id AS customer_id,
customer.last_name AS last_name,
customer.first_name AS first_name,
FORMAT ( rental.rental_date, 'MMM' ) _Month,
avg(amount) over ( PARTITION BY customer.customer_id ) avg_rental_amt
FROM
customer INNER JOIN
rental
ON customer.customer_id = rental.customer_id INNER JOIN
payment
ON payment.rental_id = rental.rental_id AND
payment.customer_id = customer.customer_id
这是上面的查询结果在我的 Navicat 数据库开发和管理客户端中:
任何人都知道如何将这些结果转换为数据透视查询,以便从左到右的列为 customer_id、last_name、first_name、一月、二月、... Dec,avg_rental_amt,在 MySQL 或 SQL 服务器中?如果可能的话,我希望结果看起来像这样:
customer_id last_name first_name Jan Feb...Dec avg_rental_amt
505 ABNEY RAFAEL 4.9 2.9 3.4 4.65
504 ADAM NATHANIEL 5.3 4.4 5.2 4.77
36 ADAMS KATHLEEN .9 .9 3.1 3.43
etc...
谢谢!
罗布
您可以进行条件聚合:
SELECT c.customer_id, c.last_name, c.first_name,
AVG(CASE WHEN MONTH(r.rental_date) = 1 THEN p.amount END) as avg_rental_january,
AVG(CASE WHEN MONTH(r.rental_date) = 2 THEN p.amount END) as avg_rental_feb,
...
AVG(CASE WHEN MONTH(r.rental_date) = 12 THEN p.amount END) as avg_rental_december,
AVG(p.amount) avg_rental
FROM customer c
INNER JOIN rental r ON c.customer_id = r.customer_id
INNER JOIN payment p ON p.rental_id = r.rental_id AND p.customer_id = c.customer_id
GROUP BY c.customer_id, c.last_name, c.first_name
此语法应该适用于 SQL 服务器和 MySQL。
请注意,这会计算同一客户 在不同年份 的平均租金 - 与您的原始查询中一样。这可能是,也可能不是您想要的。如果没有,您需要根据您的具体需要调整条件表达式。
您可以通过应用条件聚合来动态管理返回结果
在 SQL 服务器 (Demo) :
DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
WITH t AS
(
SELECT 1 AS n UNION ALL
SELECT n + 1 FROM t WHERE n + 1 <= 12
)
SELECT @cols = STRING_AGG(CONCAT('AVG(CASE WHEN MONTH(r.rental_date)=',n,
' THEN r.amount END) "',
FORMAT ( DATEADD( month , n , -1 ), 'MMM' ),
'"'), ',')
FROM t;
SET @query =
CONCAT(
'SELECT c.customer_id AS customer_id,' , @cols ,
' , AVG(r.amount) AS avg_rental_amt ',
' FROM customer c
JOIN rental r
ON c.customer_id = r.customer_id
JOIN payment p
ON p.rental_id = r.rental_id
AND p.customer_id = c.customer_id
GROUP BY c.customer_id, c.last_name, c.first_name');
EXEC sp_executesql @query;
在我的SQL (Demo):
SET @query = NULL;
SET @cols = NULL;
SELECT GROUP_CONCAT(
CONCAT(
'AVG(CASE WHEN MONTH(r.rental_date)=', n,
' THEN r.amount END) AS "',
DATE_FORMAT(CONCAT('0000-',LPAD(n,2,0),'-00'), '%b'),
'"'
)
)
INTO @cols
FROM
(
SELECT @n := @n + 1 AS n
FROM information_schema.tables
JOIN (SELECT @n := 0) AS iter ) nn
WHERE n <= 12;
SET @query =
CONCAT(
'SELECT c.customer_id AS customer_id,' , @cols ,
' , AVG(r.amount) AS avg_rental_amt ',
' FROM customer c
JOIN rental r
ON c.customer_id = r.customer_id
JOIN payment p
ON p.rental_id = r.rental_id
AND p.customer_id = c.customer_id
GROUP BY c.customer_id, c.last_name, c.first_name');
PREPARE stmt FROM @query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;