MySQL使用日期作为值进行数据透视。

huangapple go评论80阅读模式
英文:

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的示例,加入了prepareexecute。所以没有什么可复制的。

查看这里:

https://dbfiddle.uk/KE6-DbTV

英文:

I have modified the sample from Joel Coehoorn, with prepare and execute. So its nothing to copy

see here:

https://dbfiddle.uk/KE6-DbTV

答案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. 运行一个查询以确定您将需要哪些列。
  2. 使用第1步的结果构建一个新的SQL语句,明确列出您将需要的每个列。
  3. 运行第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:

  1. Run a query to determine what columns you will need.
  2. Use the results from step 1 to build a new SQL statement that explicitly lists each of the columns you will need
  3. 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.

huangapple
  • 本文由 发表于 2023年7月17日 21:25:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76704941.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定