在不使用 JOIN 的情况下在 HSQLDB 中进行透视

Posted

技术标签:

【中文标题】在不使用 JOIN 的情况下在 HSQLDB 中进行透视【英文标题】:Pivot in HSQLDB without using JOINs 【发布时间】:2013-01-09 00:29:40 【问题描述】:

我正在使用通过 java JDBC 连接到的 HSLQDB (2.2.9) 数据库。

A 人接种了 1 和 3 疫苗,B 人接种了 2 和 4。 使用这个简单的查询:

SELECT std.*,vac.Date FROM Students AS std
LEFT JOIN ValuesVaccination AS vac
ON vac.ID_Students = std.ID

我得到如下结果集:

 ID |  Name    | ID_Vaccination | Date
 1  | PersonA  | 1              | 2011-06-01
 1  | PersonA  | 3              | 2012-03-21
 1  | PersonB  | 2              | 2012-08-11
 2  | PersonB  | 4              | 2012-09-08

我想得到的是:

 ID |  Name    | Vaccination1 | Vaccination2 | Vaccination3 | Vaccination4  
 1  | PersonA  |  2011-06-01  |    NULL      |  2012-03-21  |    NULL
 2  | PersonB  |    NULL      |  2012-08-11  |    NULL      |  2012-09-08

一种方法是:

SELECT std.*,
       vac1.Date AS "Vaccination1",
       vac2.Date AS "Vaccination2",
       vac3.Date AS "Vaccination3",
       vac4.Date AS "Vaccination4"
FROM Students AS std
LEFT JOIN ValuesVaccination AS vac1
ON vac1.ID_Students = std.ID AND vac1.ID_Vaccinations = 1
LEFT JOIN ValuesVaccination AS vac2
ON vac2.ID_Students = std.ID AND vac2.ID_Vaccinations = 2
LEFT JOIN ValuesVaccination AS vac3
ON vac3.ID_Students = std.ID AND vac3.ID_Vaccinations = 3
LEFT JOIN ValuesVaccination AS vac4
ON vac4.ID_Students = std.ID AND vac4.ID_Vaccinations = 4

问题在于不同疫苗接种的数量是可变的。有没有一种体面的方法可以做到这一点,而无需使用循环在 java 字符串中使用 JOIN 构建查询?

我发现 PIVOT 函数是我需要的,但似乎 HSQLDB 不支持它,搜索 *** 和 google 并没有找到有用的信息。

感谢您提供任何信息

【问题讨论】:

【参考方案1】:

PIVOT 不是标准 SQL,它是仅由 Microsoft SQL Server 2005(及更高版本)和 Oracle 11g 支持的语法的扩展。

这是一个使用标准 SQL 的解决方案,应该适用于任何 RDBMS:

SELECT s.ID, s.Name, 
    MAX(CASE WHEN ID_Vaccination=1 THEN Date END) AS Vaccination1,
    MAX(CASE WHEN ID_Vaccination=2 THEN Date END) AS Vaccination2,
    MAX(CASE WHEN ID_Vaccination=3 THEN Date END) AS Vaccination3,
    MAX(CASE WHEN ID_Vaccination=4 THEN Date END) AS Vaccination4
FROM Students AS s
LEFT JOIN ValuesVaccination AS v
  ON s.ID = v.ID_Students
GROUP BY s.ID, s.Name;

你的评论:

SQL 不允许数据值在同一查询中动态生成新列。所以 任何数据透视查询都要求您在准备查询之前知道要在输出中显示多少种不同的疫苗。

您可以运行两个查询:一个是“发现”一组不同的疫苗接种值:

SELECT DISTINCT ID_Vaccination FROM ValuesVaccination;

然后将其取回应用程序并对其进行循环,同时添加列表达式,以构建数据透视查询。

唯一的选择是获取所有加入到 Student 的数据,就像在您的第一个查询中一样,然后使用应用程序代码将其后处理为旋转格式。

无论哪种方式,要生成动态数据透视查询,您都必须在准备查询之前或获取结果之后使用应用程序代码对其进行补充。

【讨论】:

如果有10种不同的疫苗怎么办?还是30?它们可以由应用程序用户创建和删除 感谢您的回答,MAX 函数正是我所需要的,因为可以有多个值,我需要显示最近的日期。 PIVOT 也受 Oracle 支持。 感谢@a_horse_with_no_name 的提示!我已经编辑了上面的内容并添加了链接。【参考方案2】:

在比尔的回答中,END) 之后只有一个括号太多了。 要使用原始问题中的别名和列名在此线程中获得 100% 正确答案:

SELECT std.ID, std.Name, 
    MAX(CASE WHEN v.ID_Vaccinations=1 THEN Date END) AS Vaccination1,
    MAX(CASE WHEN v.ID_Vaccinations=2 THEN Date END) AS Vaccination2,
    MAX(CASE WHEN v.ID_Vaccinations=3 THEN Date END) AS Vaccination3,
    MAX(CASE WHEN v.ID_Vaccinations=4 THEN Date END) AS Vaccination4
FROM Students AS std
LEFT JOIN ValuesVaccination AS v
ON std.ID = v.ID_Students
GROUP BY std.ID, std.Name

返回所需的结果。

【讨论】:

谢谢,我已经编辑了我的答案以修复不平衡的括号。

以上是关于在不使用 JOIN 的情况下在 HSQLDB 中进行透视的主要内容,如果未能解决你的问题,请参考以下文章

在不使用 boost::promise 的情况下在 boost 线程中返回值

如何在不使用 AudioQueueRef 的情况下在 AudioQueue 中设置音量?

有啥方法可以在不使用 getImageData() 的情况下在 JavaScript 中找到像素的颜色?

如何在不使用 &nbsp 的情况下在行内元素之间添加空格 [重复]

如何在不使用 Segue 的情况下在单独的 UIViewController 中选择实例变量

如何在不使用数据透视和反透视的情况下在 SQL Server 中水平显示数据?