英文:
MySQL Pivot Using Date As Value
问题
我尝试创建一个过程,将以下表格从:
ID | Visit | Date |
---|---|---|
1234567 | Cake | 01.01.2023 |
1234567 | Coffee | 01.01.2023 |
1234567 | Cake | 02.01.2023 |
2345678 | Coffee | 02.02.2023 |
2345678 | Coffee | 03.02.2023 |
转换为:
ID | Cake | Coffee |
---|---|---|
1234567 | Max(Date) 02.01.2023 | Max(Date) 01.01.2023 |
2345678 | Max(Date) None | Max(Date) 03.02.2023 |
列名 "Visit" 中不同项的数量(以及所有其他列)可以动态改变。
我注意到 MySQL 不支持数据透视,根据我在互联网上找到的信息,我尝试了以下代码。
不幸的是,我甚至无法运行这段代码。你有什么可以改进的想法吗?
感谢你的支持!非常感激!!
最好,
Janine
代码:
CREATE PROCEDURE VisitReport.Pivot()
BEGIN
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT CONCAT(
'MAX(CASE WHEN Visit= "', Visit, '" THEN [Date] ELSE 0 END)
AS "', Visit, '"')
)
INTO @sql
FROM VisitReport;
SET @sql = CONCAT('SELECT ID, ', @sql,
' FROM VisitReport GROUP BY ID');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
英文:
I try to create a procedure that transforms the following table from:
ID | Visit | Date |
---|---|---|
1234567 | Cake | 01.01.2023 |
1234567 | Coffee | 01.01.2023 |
1234567 | Cake | 02.01.2023 |
2345678 | Coffee | 02.02.2023 |
2345678 | Coffee | 03.02.2023 |
to:
ID | Cake | Coffee |
---|---|---|
1234567 | Max(Date) 02.01.2023 | Max(Date) 01.01.2023 |
2345678 | Max(Date) None | Max(Date) 03.02.2023 |
The number of different items in column Visit (and all other columns) can change dynamically.
I noticed that mysql does not support pivot, and based on what I found on the internet, I tried the following.
Unfortunately, I don't even get this code to run. Do you have any ideas on what I can improve?
Thank you for your support!!! Thats so much appreciated!!
Best,
Janine
Code:
CREATE PROCEDURE VisitReport.Pivot()
BEGIN
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT CONCAT(
'MAX(CASE WHEN Visit= "', Visit, '" THEN [Date] ELSE 0 END)
AS ', Visit, '"')
)
INTO @sql
FROM VisitReport;
SET @sql = CONCAT('SELECT ID, ', @sql,
' FROM VisitReport GROUP BY ID');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
答案1
得分: 1
我已经修改了来自Joel Coehoorn的示例,加入了prepare和execute。所以没有什么可复制的。
查看这里:
英文:
I have modified the sample from Joel Coehoorn, with prepare and execute. So its nothing to copy
see here:
答案2
得分: 0
你可以尝试以下内容:
DELIMITER //
CREATE PROCEDURE GetCakeCoffeeDates()
BEGIN
SELECT
id,
(CASE WHEN cakeDate IS NULL THEN '无' ELSE cakeDate END) AS 蛋糕,
(CASE WHEN coffeeDate IS NULL THEN '无' ELSE coffeeDate END) AS 咖啡
FROM
(SELECT
c.`id`,
MAX(CASE WHEN c.`visit`='Cake' THEN c.`date` END) AS cakeDate,
MAX(CASE WHEN c.`visit`='Coffee' THEN c.`date` END) AS coffeeDate
FROM `cake_coffee` c GROUP BY c.`id`) a;
END //
DELIMITER ;
调用存储过程的方法如下:
CALL GetCakeCoffeeDates;
我只翻译了代码部分,没有其他内容。如果有任何疑问,请告诉我。
英文:
You can try the following:
DELIMITER //
CREATE PROCEDURE GetCakeCoffeeDates()
BEGIN
SELECT
id,
(CASE WHEN cakeDate IS NULL THEN 'None' ELSE cakeDate END) AS cake,
(CASE WHEN coffeeDate IS NULL THEN 'None' ELSE coffeeDate END) AS coffee
FROM
(SELECT
c.`id`,
MAX(CASE WHEN c.`visit`='Cake' THEN c.`date` END) AS cakeDate,
MAX(CASE WHEN c.`visit`='Coffee' THEN c.`date` END) AS coffeeDate
FROM `cake_coffee` c GROUP BY c.`id`) a;
END //
DELIMITER ;
to call the procedure:
CALL GetCakeCoffeeDates;
I am just assuming that there will be none other than cake
and coffee
.
Let me know if I am missing something
答案3
得分: 0
以下是已经翻译好的部分:
"给定这个信息,在单个SQL语句中做到这一点是不可能的。
SQL语言有一个非常严格的规则,即在查询编译时必须知道列的数量和类型,在查看任何数据之前。由于您必须查看数据以知道要显示哪些列,因此您将无法在单个SQL查询中执行此操作。
相反,您必须使用动态SQL来完成以下三个步骤:
- 运行一个查询以确定您将需要哪些列。
- 使用第1步的结果构建一个新的SQL语句,明确列出您将需要的每个列。
- 运行第2步的查询。
值得注意的是,添加PIVOT支持也不会有所帮助。即使使用PIVOT,您仍然需要知道结果列的数量。
尽管如此,您已经在朝着这个结果取得了良好的进展。一旦我们知道了这些列,PIVOT可能会改进此查询,但在没有它的情况下,已经尝试的条件聚合策略是我们的最佳选择。我只需要清理一下使用单引号而不是双引号以及使用反引号而不是方括号的一些语法问题。我还在结果的格式方面进行了一些改进,这有助于调试:"
英文:
> The number of different items in column Visit (and all other columns) can change dynamically.
Given that information, this is impossible to do in a single SQL statement.
The SQL language has a very strict rule that the number and types of columns must be known at query compile time, before looking at any data. Since you have to look at the data to know what columns to show, you will not be able to do this in a single SQL query.
Instead, you must use dynamic SQL do this over three steps:
- Run a query to determine what columns you will need.
- Use the results from step 1 to build a new SQL statement that explicitly lists each of the columns you will need
- Run the query from step 2.
It's also worth noting that adding PIVOT
support would not help. Even with PIVOT, you still need to know that number of result columns.
That said, you'd made good progress towards this result. Once we know the columns, PIVOT might improve this query, but without it the conditional aggregation strategy already attempted is our best bet. I only needed to clean up a few syntax issues with using single quotes instead of double and back-ticks instead of square-brackets. I took the liberty of improving the format of the result as well, which helps with debugging:
SELECT
CONCAT('SELECT ID\n\t,',
GROUP_CONCAT(DISTINCT CONCAT(
'MAX(CASE WHEN Visit= ''', Visit, ''' THEN `Date` END) AS ',
Visit, ' ') SEPARATOR '\n\t,'),
'\nFROM VisitReport GROUP BY ID;') AS q
FROM VisitReport;
See it here:
> https://dbfiddle.uk/7YmQeAMf
The fiddle just copy/pastes the result from the 2nd sample block to the third to give the correct result.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论